summaryrefslogtreecommitdiffstats
path: root/kcontrol/kfontinst/kfontinst
diff options
context:
space:
mode:
Diffstat (limited to 'kcontrol/kfontinst/kfontinst')
-rw-r--r--kcontrol/kfontinst/kfontinst/FontEngine.cpp376
-rw-r--r--kcontrol/kfontinst/kfontinst/FontEngine.h142
-rw-r--r--kcontrol/kfontinst/kfontinst/Fontmap.cpp596
-rw-r--r--kcontrol/kfontinst/kfontinst/Fontmap.h79
-rw-r--r--kcontrol/kfontinst/kfontinst/GetPid.c519
-rw-r--r--kcontrol/kfontinst/kfontinst/Main.cpp335
-rw-r--r--kcontrol/kfontinst/kfontinst/Makefile.am16
-rw-r--r--kcontrol/kfontinst/kfontinst/XConfig.cpp760
-rw-r--r--kcontrol/kfontinst/kfontinst/XConfig.h114
9 files changed, 2937 insertions, 0 deletions
diff --git a/kcontrol/kfontinst/kfontinst/FontEngine.cpp b/kcontrol/kfontinst/kfontinst/FontEngine.cpp
new file mode 100644
index 000000000..ff5dcd623
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/FontEngine.cpp
@@ -0,0 +1,376 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+// Class Name : KFI::CFontEngine
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 29/04/2001
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2001, 2002, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include "FontEngine.h"
+#include "Misc.h"
+#include <kglobal.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+#include <stdio.h>
+#include <qregexp.h>
+#include <qfile.h>
+#include <ft2build.h>
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+#include FT_TRUETYPE_TABLES_H
+#include FT_TYPE1_TABLES_H
+
+namespace KFI
+{
+
+bool CFontEngine::openFont(const QString &file, int face)
+{
+ bool ok=false;
+
+ if(file==itsPath && face==itsFaceIndex)
+ {
+ ok=NONE!=itsType;
+ }
+ else
+ {
+ closeFont();
+
+ itsWeight=WEIGHT_MEDIUM;
+ itsItalic=ITALIC_NONE;
+ itsPath=file;
+ itsFaceIndex=face;
+ itsPsName=QString();
+
+ if(!openFontFt(file) && !itsPsName.isEmpty())
+ itsType=NONE;
+ }
+
+ return NONE!=itsType;
+}
+
+void CFontEngine::closeFont()
+{
+ closeFaceFt();
+ itsPath=QString::null;
+ itsFaceIndex=-1;
+ itsType=NONE;
+}
+
+QString CFontEngine::weightStr(enum EWeight w)
+{
+ switch(w)
+ {
+ case WEIGHT_THIN:
+ return "Thin";
+ case WEIGHT_ULTRA_LIGHT:
+ return "UltraLight";
+ case WEIGHT_EXTRA_LIGHT:
+ return "ExtraLight";
+ case WEIGHT_DEMI:
+ return "Demi";
+ case WEIGHT_LIGHT:
+ return "Light";
+ case WEIGHT_BOOK:
+ return "Book";
+ case WEIGHT_MEDIUM:
+ return "Medium";
+ case WEIGHT_REGULAR:
+ return "Regular";
+ case WEIGHT_SEMI_BOLD:
+ return "SemiBold";
+ case WEIGHT_DEMI_BOLD:
+ return "DemiBold";
+ case WEIGHT_BOLD:
+ return "Bold";
+ case WEIGHT_EXTRA_BOLD:
+ return "ExtraBold";
+ case WEIGHT_ULTRA_BOLD:
+ return "UltraBold";
+ case WEIGHT_HEAVY:
+ return "Heavy";
+ case WEIGHT_BLACK:
+ return "Black";
+ case WEIGHT_UNKNOWN:
+ default:
+ return "Medium";
+ }
+}
+
+CFontEngine::EWeight CFontEngine::strToWeight(const char *str)
+{
+ if(NULL==str)
+ return WEIGHT_MEDIUM; // WEIGHT_UNKNOWN;
+ else if(kasciistricmp(str, "Bold")==0)
+ return WEIGHT_BOLD;
+ else if(kasciistricmp(str, "Black")==0)
+ return WEIGHT_BLACK;
+ else if(kasciistricmp(str, "ExtraBold")==0)
+ return WEIGHT_EXTRA_BOLD;
+ else if(kasciistricmp(str, "UltraBold")==0)
+ return WEIGHT_ULTRA_BOLD;
+ else if(kasciistricmp(str, "ExtraLight")==0)
+ return WEIGHT_EXTRA_LIGHT;
+ else if(kasciistricmp(str, "UltraLight")==0)
+ return WEIGHT_ULTRA_LIGHT;
+ else if(kasciistricmp(str, "Light")==0)
+ return WEIGHT_LIGHT;
+ else if(kasciistricmp(str, "Medium")==0 || kasciistricmp(str, "Normal")==0 || kasciistricmp(str, "Roman")==0)
+ return WEIGHT_MEDIUM;
+ else if(kasciistricmp(str, "Regular")==0)
+ return WEIGHT_MEDIUM; // WEIGHT_REGULAR;
+ else if(kasciistricmp(str, "Demi")==0)
+ return WEIGHT_DEMI;
+ else if(kasciistricmp(str, "SemiBold")==0)
+ return WEIGHT_SEMI_BOLD;
+ else if(kasciistricmp(str, "DemiBold")==0)
+ return WEIGHT_DEMI_BOLD;
+ else if(kasciistricmp(str, "Thin")==0)
+ return WEIGHT_THIN;
+ else if(kasciistricmp(str, "Book")==0)
+ return WEIGHT_BOOK;
+ else
+ return WEIGHT_MEDIUM; // WEIGHT_UNKNOWN;
+}
+
+static void removeSymbols(QString &str)
+{
+ str.replace(QRegExp("[\\-\\[\\]()]"), " ");
+
+ int len=str.length();
+ QChar space(' ');
+
+ for(int c=0; c<len; ++c)
+ if(str[c].unicode()<0x20 || str[c].unicode()>0x7E)
+ str[c]=space;
+
+ str=str.simplifyWhiteSpace();
+ str=str.stripWhiteSpace();
+}
+
+static bool lookupName(FT_Face face, int nid, int pid, int eid, FT_SfntName *nameReturn)
+{
+ int n = FT_Get_Sfnt_Name_Count(face);
+
+ if(n>0)
+ {
+ int i;
+ FT_SfntName name;
+
+ for(i=0; i<n; i++)
+ if(0==FT_Get_Sfnt_Name(face, i, &name) && name.name_id == nid && name.platform_id == pid &&
+ (eid < 0 || name.encoding_id == eid))
+ {
+ switch(name.platform_id)
+ {
+ case TT_PLATFORM_APPLE_UNICODE:
+ case TT_PLATFORM_MACINTOSH:
+ if(name.language_id != TT_MAC_LANGID_ENGLISH)
+ continue;
+ break;
+ case TT_PLATFORM_MICROSOFT:
+ if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES &&
+ name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM)
+ continue;
+ break;
+ default:
+ continue;
+ }
+
+ if(name.string_len > 0)
+ {
+ *nameReturn = name;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static QCString getName(FT_Face face, int nid)
+{
+ FT_SfntName name;
+ QCString str;
+
+ if(lookupName(face, nid, TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) ||
+ lookupName(face, nid, TT_PLATFORM_APPLE_UNICODE, -1, &name))
+ for(unsigned int i=0; i < name.string_len / 2; i++)
+ str+=0 == name.string[2*i] ? name.string[(2*i)+1] : '_';
+ else if(lookupName(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, &name)) // Pretend that Apple Roman is ISO 8859-1
+ for(unsigned int i=0; i < name.string_len; i++)
+ str+=name.string[i];
+
+ return str;
+}
+
+bool CFontEngine::openFontFt(const QString &file)
+{
+ enum ETtfWeight
+ {
+ TTF_WEIGHT_UNKNOWN = 0,
+ TTF_WEIGHT_THIN = 100 +50,
+ TTF_WEIGHT_EXTRALIGHT = 200 +50,
+ TTF_WEIGHT_LIGHT = 300 +50,
+ TTF_WEIGHT_NORMAL = 400 +50,
+ TTF_WEIGHT_MEDIUM = 500 +50,
+ TTF_WEIGHT_SEMIBOLD = 600 +50,
+ TTF_WEIGHT_BOLD = 700 +50,
+ TTF_WEIGHT_EXTRABOLD = 800 +50,
+ TTF_WEIGHT_BLACK = 900 +50
+ };
+
+ bool status=FT_New_Face(itsFt.library, QFile::encodeName(file), 0, &itsFt.face) ? false : true;
+
+ if(status)
+ itsFt.open=true;
+
+ PS_FontInfoRec t1info;
+
+ if(0==FT_Get_PS_Font_Info(itsFt.face, &t1info))
+ {
+ itsFamily=t1info.family_name;
+ itsType=TYPE_1;
+ }
+ else
+ {
+ itsFamily=getName(itsFt.face, TT_NAME_ID_FONT_FAMILY);
+ itsType=TRUE_TYPE;
+ }
+
+ if(itsFamily.isEmpty())
+ itsFamily=FT_Get_Postscript_Name(itsFt.face);
+
+ if(itsFamily.isEmpty())
+ status=false; // Hmm... couldn't find any of the names!
+
+ if(status)
+ {
+ removeSymbols(itsFamily);
+ itsPsName=(FT_Get_Postscript_Name(itsFt.face));
+
+ if(TYPE_1==itsType)
+ {
+ itsWeight=strToWeight(t1info.weight);
+ itsItalic=t1info.italic_angle <= -4 || t1info.italic_angle >= 4 ? ITALIC_ITALIC : ITALIC_NONE;
+ }
+ else // TrueType...
+ {
+ TT_Postscript *post=NULL;
+ TT_OS2 *os2=NULL;
+ TT_Header *head=NULL;
+ bool gotItalic=false;
+
+ if(NULL==(os2=(TT_OS2 *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_os2)) || 0xFFFF==os2->version)
+ itsWeight=WEIGHT_UNKNOWN;
+ else
+ {
+ FT_UShort weight=(os2->usWeightClass>0 && os2->usWeightClass<100) ? os2->usWeightClass*100 : os2->usWeightClass;
+
+ if(weight<TTF_WEIGHT_THIN)
+ itsWeight=WEIGHT_THIN;
+ else if(weight<TTF_WEIGHT_EXTRALIGHT)
+ itsWeight=WEIGHT_EXTRA_LIGHT;
+ else if(weight<TTF_WEIGHT_LIGHT)
+ itsWeight=WEIGHT_LIGHT;
+ else if(/*weight<TTF_WEIGHT_NORMAL || */ weight<TTF_WEIGHT_MEDIUM)
+ itsWeight=WEIGHT_MEDIUM;
+ else if(weight<TTF_WEIGHT_SEMIBOLD)
+ itsWeight=WEIGHT_SEMI_BOLD;
+ else if(weight<TTF_WEIGHT_BOLD)
+ itsWeight=WEIGHT_BOLD;
+ else if(weight<TTF_WEIGHT_EXTRABOLD)
+ itsWeight=WEIGHT_EXTRA_BOLD;
+ else if(weight<TTF_WEIGHT_BLACK)
+ itsWeight=WEIGHT_BLACK;
+ else if(os2->fsSelection&(1 << 5))
+ itsWeight=WEIGHT_BOLD;
+ else
+ itsWeight=WEIGHT_UNKNOWN;
+
+ itsItalic=os2->fsSelection&(1 << 0) ? ITALIC_ITALIC : ITALIC_NONE;
+ gotItalic=true;
+ }
+
+ if(WEIGHT_UNKNOWN==itsWeight)
+ itsWeight=NULL!=(head=(TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head)) && head->Mac_Style & 1
+ ? WEIGHT_BOLD
+ : WEIGHT_MEDIUM;
+
+ if(!gotItalic && (head!=NULL || NULL!=(head=(TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head))))
+ {
+ gotItalic=true;
+ itsItalic=head->Mac_Style & 2 ? ITALIC_ITALIC: ITALIC_NONE;
+ }
+
+ if(!gotItalic && NULL!=(post=(TT_Postscript *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_post)))
+ {
+ struct TFixed
+ {
+ TFixed(unsigned long v) : upper(v>>16), lower(v&0xFFFF) {}
+
+ short upper,
+ lower;
+
+ float value() { return upper+(lower/65536.0); }
+ };
+
+ gotItalic=true;
+ itsItalic=0.0f==((TFixed)post->italicAngle).value() ? ITALIC_NONE : ITALIC_ITALIC;
+ }
+ }
+ }
+
+ if(!status)
+ closeFaceFt();
+
+ return status;
+}
+
+void CFontEngine::closeFaceFt()
+{
+ if(itsFt.open)
+ {
+ FT_Done_Face(itsFt.face);
+ itsFt.open=false;
+ }
+}
+
+CFontEngine::TFtData::TFtData()
+ : open(false)
+{
+ if(FT_Init_FreeType(&library))
+ {
+ std::cerr << "ERROR: FreeType2 failed to initialise\n";
+ exit(0);
+ }
+}
+
+CFontEngine::TFtData::~TFtData()
+{
+ FT_Done_FreeType(library);
+}
+
+}
diff --git a/kcontrol/kfontinst/kfontinst/FontEngine.h b/kcontrol/kfontinst/kfontinst/FontEngine.h
new file mode 100644
index 000000000..06218c0ae
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/FontEngine.h
@@ -0,0 +1,142 @@
+#ifndef __FONT_ENGINE_H__
+#define __FONT_ENGINE_H__
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Class Name : KFI::CFontEngine
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 29/04/2001
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2001, 2002, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include <qstring.h>
+#include <qstringlist.h>
+
+namespace KFI
+{
+
+class CFontEngine
+{
+ public:
+
+ enum EType
+ {
+ // These have PS Info / support AFM stuff...
+ TRUE_TYPE,
+ TT_COLLECTION,
+ TYPE_1,
+ NONE
+ };
+
+ enum EWeight
+ {
+ WEIGHT_UNKNOWN=0,
+ WEIGHT_THIN,
+ WEIGHT_ULTRA_LIGHT,
+ WEIGHT_EXTRA_LIGHT,
+ WEIGHT_DEMI,
+ WEIGHT_LIGHT,
+ WEIGHT_BOOK,
+ WEIGHT_MEDIUM,
+ WEIGHT_REGULAR,
+ WEIGHT_SEMI_BOLD,
+ WEIGHT_DEMI_BOLD,
+ WEIGHT_BOLD,
+ WEIGHT_EXTRA_BOLD,
+ WEIGHT_ULTRA_BOLD,
+ WEIGHT_HEAVY,
+ WEIGHT_BLACK
+ };
+
+ enum EItalic
+ {
+ ITALIC_NONE,
+ ITALIC_ITALIC,
+ ITALIC_OBLIQUE
+ };
+
+ private:
+
+ struct TFtData
+ {
+ TFtData();
+ ~TFtData();
+
+ FT_Library library;
+ FT_Face face;
+ bool open;
+ };
+
+ public:
+
+ CFontEngine() : itsType(NONE) { }
+ ~CFontEngine() { closeFont(); }
+
+ static EType getType(const char *fname);
+ static QString weightStr(EWeight w);
+ static QString italicStr(EItalic i) { return ITALIC_NONE==i ? "r" : ITALIC_ITALIC==i ? "i" : "o"; }
+
+ //
+ // General functions - these should be used instead of specfic ones below...
+ //
+ bool openFont(const QString &file, int face=0);
+ void closeFont();
+
+ //
+ const QString & getFamilyName() { return itsFamily; }
+ const QString & getPsName() { return itsPsName; }
+ EWeight getWeight() { return itsWeight; }
+ EItalic getItalic() { return itsItalic; }
+ EType getType() { return itsType; }
+ int getNumFaces() { return itsFt.open ? itsFt.face->num_faces : 1; }
+ bool hasPsInfo() { return itsType!=NONE; }
+
+ static EWeight strToWeight(const char *str);
+
+ private:
+
+ bool openFontFt(const QString &file);
+ void closeFaceFt();
+
+ private:
+
+ EWeight itsWeight;
+ EType itsType;
+ EItalic itsItalic;
+ QString itsFamily,
+ itsPsName,
+ itsPath;
+ int itsNumFaces,
+ itsFaceIndex; // Only for TTC fonts - at the moment...
+ TFtData itsFt;
+};
+
+}
+
+#endif
diff --git a/kcontrol/kfontinst/kfontinst/Fontmap.cpp b/kcontrol/kfontinst/kfontinst/Fontmap.cpp
new file mode 100644
index 000000000..0f8178dee
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/Fontmap.cpp
@@ -0,0 +1,596 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Namespae : KFI::Fontmap
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 06/06/2003
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#include "Fontmap.h"
+#include "FontEngine.h"
+#include "XConfig.h"
+#include "FcEngine.h"
+#include "KfiConstants.h"
+#include <ksavefile.h>
+#include <qtextstream.h>
+#include <qdir.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <qregexp.h>
+#include <fstream>
+#include <unistd.h>
+
+using namespace std;
+
+static const char * findSpace(const char *str)
+{
+ while(str && *str!=' ' && *str!='\t')
+ str++;
+
+ return str;
+}
+
+static bool parseLine(const char *line, QString &ps, QString &fname, bool &isAlias)
+{
+ static const int constMaxLen = 127;
+ static const int constFileMaxLen = 1023;
+
+ //
+ // Format:
+ // "/<psname> (<filename>) ; "
+ // "/<psname> /real ; "
+
+ char a[constMaxLen+1],
+ b[constFileMaxLen+1];
+
+ const char *slash1=strchr(line, '/'),
+ *space1=slash1 ? findSpace(slash1) : NULL, //strchr(slash1, ' ') : NULL,
+ *ob=slash1 ? strchr(slash1, '(') : NULL,
+ *cb=ob ? strchr(ob, ')') : NULL,
+ *slash2=space1 && !ob && !cb ? strchr(space1, '/') : NULL,
+ *space2=slash2 ? findSpace(slash2) : NULL, // strchr(slash2, ' ') : NULL,
+ *semic=cb || space2 ? strchr(cb ? cb : space2, ';') : NULL;
+
+ if(semic && space1-slash1<constMaxLen)
+ {
+ slash1++;
+ memcpy(a, slash1, space1-slash1);
+ a[space1-slash1]='\0';
+
+ if(cb && cb-ob<constFileMaxLen) // Then found a file entry...
+ {
+ ob++;
+ memcpy(b, ob, cb-ob);
+ b[cb-ob]='\0';
+ ps=a;
+ fname=b;
+ isAlias=false;
+ return true;
+ }
+ else if(space2 && space2-slash2<constMaxLen) // Then found an alias...
+ {
+ slash2++;
+ memcpy(b, slash2, space2-slash2);
+ b[space2-slash2]='\0';
+ ps=a;
+ fname=b;
+ isAlias=true;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//
+// Returns a PS name from an X family name...
+// e.g. "Times New Roman" -> "TimesNewRoman"
+static QString createX11PsName(const QString &font)
+{
+ QString newName(font);
+ unsigned int ch;
+ bool newWord=true;
+
+ newName.replace(QRegExp("\\-"), "_");
+
+ for(ch=0; ch<newName.length(); ++ch)
+ {
+ if(newName[ch].isSpace())
+ newWord=true;
+ else
+ {
+ if(newName[ch]==newName[ch].upper())
+ {
+ if(!newWord)
+ newName[ch]=newName[ch].lower();
+ }
+ else
+ if(newName[ch]==newName[ch].lower())
+ {
+ if(newWord)
+ newName[ch]=newName[ch].upper();
+ }
+ newWord=false;
+ }
+ }
+
+ newName.replace(" ", QString::null);
+ return newName;
+}
+
+static const char * getItalicStr(KFI::CFontEngine::EItalic it)
+{
+ switch(it)
+ {
+ default:
+ case KFI::CFontEngine::ITALIC_NONE:
+ return NULL;
+ case KFI::CFontEngine::ITALIC_ITALIC:
+ return "Italic";
+ case KFI::CFontEngine::ITALIC_OBLIQUE:
+ return "Oblique";
+ }
+}
+
+//
+// Create a full Ps name
+static QString createName(const QString &family, const QString &weight, const char *italic)
+{
+ QString name;
+ QTextOStream str(&name);
+
+ str << family;
+ if(!weight.isEmpty() || NULL!=italic)
+ {
+ str << '-';
+ if(!weight.isEmpty())
+ str << weight;
+ if(NULL!=italic)
+ str << italic;
+ }
+
+ return name;
+}
+
+static QString getEntry(QStringList &list, const QString &name)
+{
+ QStringList::Iterator it(list.begin()),
+ end(list.end());
+
+ for( ; it!=end; ++it)
+ if(0==(*it).find('/'+name+' '))
+ return *it;
+
+ return QString::null;
+}
+
+inline bool isAlias(const QString &entry)
+{
+ return -1==entry.findRev(QRegExp(")\\s*;\\s*$"));
+}
+
+static void addEntry(QStringList &list, const QString &name, const QString &file, const QString &fmapDir)
+{
+ QString existing(getEntry(list, name));
+ bool insert=true;
+
+ if(!existing.isEmpty())
+ if(isAlias(existing))
+ list.remove(existing);
+ else
+ insert=false;
+
+ if(insert)
+ {
+ QString entry;
+ QTextOStream str(&entry);
+
+ str << '/' << name << " (";
+
+ if(0==file.find(fmapDir))
+ str << file.mid(fmapDir.length());
+ else
+ str << file;
+
+ str << ") ;";
+ list.append(entry);
+ }
+}
+
+static void addAliasEntry(QStringList &list, const QString &x11Name, const QString &psName)
+{
+ if(x11Name!=psName)
+ {
+ QString existing(getEntry(list, x11Name));
+
+ if(existing.isEmpty())
+ {
+ QString entry;
+ QTextOStream str(&entry);
+
+ str << '/' << x11Name << " /" << psName << " ;";
+ list.append(entry);
+ }
+ }
+}
+
+static QString locateFile(const char *dir, const char *file, int level=0)
+{
+ if(level<5)
+ {
+ QDir d(dir);
+
+ if(d.isReadable())
+ {
+ const QFileInfoList *fList=d.entryInfoList();
+
+ if(fList)
+ {
+ QFileInfoListIterator it(*fList);
+ QFileInfo *fInfo;
+ QString str;
+
+ for(; NULL!=(fInfo=it.current()); ++it)
+ if("."!=fInfo->fileName() && ".."!=fInfo->fileName())
+ if(fInfo->isDir())
+ {
+ if(!(str=locateFile(QFile::encodeName(fInfo->filePath()+"/"), file, level+1)).isEmpty())
+ return str;
+ }
+ else
+ if(fInfo->fileName()==file)
+ return fInfo->filePath();
+ }
+ }
+ }
+
+ return QString::null;
+}
+
+static QString locateFile(const char *file, const char **dirs)
+{
+ int d;
+ QString str;
+
+ for(d=0; dirs[d]; ++d)
+ if(!(str=locateFile(dirs[d], file)).isEmpty())
+ return str;
+
+ return QString::null;
+}
+
+#define FONTMAP "Fontmap"
+
+namespace KFI
+{
+
+namespace Fontmap
+{
+
+bool create(const QString &dir, CFontEngine &fe)
+{
+ bool root(Misc::root()),
+ added=false;
+ QString fmapDir(Misc::dirSyntax(root ? KFI_ROOT_CFG_DIR : dir));
+ CFile old(fmapDir);
+ QStringList entries;
+ int i;
+ FcPattern *pat = FcPatternCreate();
+ FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SCALABLE, (void*)0);
+ FcFontSet *fs = FcFontList(0, pat, os);
+
+ FcPatternDestroy(pat);
+ FcObjectSetDestroy(os);
+
+ for (i = 0; i<fs->nfont; i++)
+ {
+ QString fName(Misc::fileSyntax(CFcEngine::getFcString(fs->fonts[i], FC_FILE)));
+ FcBool scalable=FcFalse;
+
+ if(!fName.isEmpty() && (root || dir.isEmpty() || 0==fName.find(dir)) &&
+ FcResultMatch==FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &scalable) && scalable)
+ {
+ const QStringList *existing=old.getEntries(fName);
+
+ if(existing && existing->count())
+ entries+=(*existing);
+ else
+ {
+ int face=0,
+ numFaces=0;
+
+ do
+ {
+ if(fe.openFont(fName, face))
+ {
+ if(fe.hasPsInfo())
+ {
+ if(0==numFaces)
+ numFaces=fe.getNumFaces(); // Only really for TTC files...
+
+ //
+ // Add real
+ addEntry(entries, fe.getPsName(), fName, fmapDir);
+ added=true;
+
+ //
+ // Add fake entries for X11 generated names
+ switch(fe.getWeight())
+ {
+ case CFontEngine::WEIGHT_MEDIUM:
+ case CFontEngine::WEIGHT_REGULAR:
+ {
+ QString x11Ps(createX11PsName(fe.getFamilyName()));
+
+ if(CFontEngine::ITALIC_ITALIC!=fe.getItalic() &&
+ CFontEngine::ITALIC_OBLIQUE!=fe.getItalic())
+ addAliasEntry(entries,
+ createName(x11Ps, "Roman",
+ getItalicStr(fe.getItalic())),
+ fe.getPsName());
+ addAliasEntry(entries,
+ createName(x11Ps, NULL, getItalicStr(fe.getItalic())),
+ fe.getPsName());
+ break;
+ }
+ case CFontEngine::WEIGHT_UNKNOWN:
+ break;
+ default:
+ addAliasEntry(entries,
+ createName(createX11PsName(fe.getFamilyName()),
+ CFontEngine::weightStr(fe.getWeight()),
+ getItalicStr(fe.getItalic())),
+ fe.getPsName());
+ }
+ }
+ fe.closeFont();
+ }
+ }
+ while(++face<numFaces);
+ }
+ }
+ }
+
+ bool status=true;
+
+ if(added || entries.count()!=old.getLineCount())
+ {
+ KSaveFile out(fmapDir+FONTMAP);
+ QTextStream *stream=out.textStream();
+
+ if(stream)
+ {
+ QStringList::Iterator it;
+
+ for(it=entries.begin(); it!=entries.end(); ++it)
+ *stream << *it << endl;
+ }
+ else
+ status=false;
+ }
+
+ //
+ // Ensure GS's main Fontmap references our file...
+ if(root && status)
+ {
+ static const char * constGhostscriptDirs[]=
+ {
+ "/usr/share/ghostscript/",
+ "/usr/local/share/ghostscript/",
+ "/usr/share/gs-esp/",
+ NULL
+ };
+
+ QString gsFile=locateFile(FONTMAP, constGhostscriptDirs);
+
+ if(!gsFile.isEmpty())
+ {
+ const int constMaxLineLen=1024;
+ const char *constRLF=".runlibfile";
+
+ char line[constMaxLineLen];
+ ifstream in(QFile::encodeName(gsFile));
+
+ if(in)
+ {
+ QCString fmap(QFile::encodeName(fmapDir+FONTMAP));
+ int lineNum=0,
+ kfiLine=-1,
+ gsLine=-1,
+ ncLine=-1;
+
+ do
+ {
+ in.getline(line, constMaxLineLen);
+
+ if(in.good())
+ {
+ line[constMaxLineLen-1]='\0';
+
+ if(strstr(line, fmap.data())!=NULL && strstr(line, constRLF)!=NULL)
+ kfiLine=lineNum;
+ else if(strstr(line, FONTMAP".GS")!=NULL && strstr(line, constRLF)!=NULL)
+ gsLine=lineNum;
+ if(-1==ncLine && '%'!=line[0])
+ ncLine=lineNum;
+ lineNum++;
+ }
+ }
+ while(!in.eof() && (-1==kfiLine || -1==gsLine));
+
+ //
+ // If the file doesn't already say to use our Fontmap file, then tell it to!
+ // Also, ensure ours is .runlibfile'd before the main GS one - else problems can occur
+ if(-1==kfiLine || kfiLine>gsLine)
+ {
+ in.clear();
+ in.seekg(0, ios::end);
+ int size= (streamoff) in.tellg();
+ in.seekg(0, ios::beg);
+
+ char *buffer=new char[size+strlen(fmap)+strlen(constRLF)+5];
+
+ if(buffer)
+ {
+ bool added=false;
+
+ buffer[0]='\0';
+ lineNum=0;
+
+ do
+ {
+ in.getline(line, constMaxLineLen);
+
+ if(in.good())
+ {
+ line[constMaxLineLen-1]='\0';
+
+ if(lineNum>=ncLine && !added)
+ {
+ strcat(buffer, "(");
+ strcat(buffer, fmap);
+ strcat(buffer, ") ");
+ strcat(buffer, constRLF);
+ strcat(buffer, "\n");
+ added=true;
+ }
+
+ if(lineNum!=kfiLine)
+ {
+ strcat(buffer, line);
+ strcat(buffer, "\n");
+ }
+ lineNum++;
+ }
+ }
+ while(!in.eof());
+
+ in.close();
+
+ if(added) // Don't re-write GS's Fontmap unless we've actually added something...
+ {
+ KSaveFile out(gsFile);
+ QTextStream *stream=out.textStream();
+
+ if(stream)
+ *stream << buffer;
+ }
+ delete [] buffer;
+ }
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+CFile::CFile(const QString &dir)
+ : itsDir(dir),
+ itsLineCount(0)
+{
+ ifstream f(QFile::encodeName(dir+FONTMAP));
+
+ itsEntries.setAutoDelete(true);
+
+ if(f)
+ {
+ static const int constMaxLine=512;
+
+ char line[constMaxLine+1];
+ TEntry *current=NULL;
+
+ while(!f.eof())
+ {
+ f.getline(line, constMaxLine);
+
+ if(!f.eof())
+ {
+ QString ps,
+ fname;
+ bool isAlias;
+
+ if(parseLine(line, ps, fname, isAlias))
+ {
+ itsLineCount++;
+
+ TEntry *entry=getEntry(&current, fname, isAlias);
+
+ if(!isAlias && entry && entry->psName.isEmpty())
+ entry->psName=ps;
+
+ if(entry)
+ entry->entries.append(line);
+ }
+ }
+ }
+ f.close();
+ }
+}
+
+const QStringList * CFile::getEntries(const QString &fname)
+{
+ TEntry *entry=findEntry(0==fname.find(itsDir) ? fname.mid(itsDir.length()) : fname, false);
+
+ return entry ? &entry->entries : NULL;
+}
+
+CFile::TEntry * CFile::findEntry(const QString &fname, bool isAlias)
+{
+ TEntry *entry=NULL;
+
+ for(entry=itsEntries.first(); entry; entry=itsEntries.next())
+ if(isAlias ? entry->psName==fname : entry->filename==fname)
+ break;
+
+ return entry;
+}
+
+CFile::TEntry * CFile::getEntry(TEntry **current, const QString &fname, bool isAlias)
+{
+ //
+ // See if its the current one...
+ if(*current && (isAlias ? (*current)->psName==fname : (*current)->filename==fname))
+ return *current;
+
+ //
+ // See if its already known...
+ TEntry *entry=findEntry(fname, isAlias);
+
+ //
+ // If not found, then create a new entry
+ if(!entry)
+ {
+ entry=new TEntry(fname);
+ itsEntries.append(entry);
+ }
+
+ *current=entry;
+ return entry;
+}
+
+}
+
+}
diff --git a/kcontrol/kfontinst/kfontinst/Fontmap.h b/kcontrol/kfontinst/kfontinst/Fontmap.h
new file mode 100644
index 000000000..28d5c9d7e
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/Fontmap.h
@@ -0,0 +1,79 @@
+#ifndef __FONTMAP_H__
+#define __FONTMAP_H__
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Namespace : KFI::Fontmap
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 06/06/2003
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+namespace KFI
+{
+
+class CFontEngine;
+
+namespace Fontmap
+{
+ class CFile
+ {
+ private:
+
+ struct TEntry
+ {
+ TEntry(const QString &fname) : filename(fname) {}
+
+ QString filename,
+ psName;
+ QStringList entries;
+ };
+
+ public:
+
+ CFile(const QString &dir);
+
+ const QStringList * getEntries(const QString &fname);
+ unsigned int getLineCount() { return itsLineCount; }
+
+ private:
+
+ TEntry * findEntry(const QString &fname, bool isAlias=false);
+ TEntry * getEntry(TEntry **current, const QString &fname, bool isAlias=false);
+
+ private:
+
+ QString itsDir;
+ QPtrList<TEntry> itsEntries;
+ unsigned int itsLineCount;
+ };
+
+ extern bool create(const QString &dir, CFontEngine &fe);
+}
+
+}
+
+#endif
diff --git a/kcontrol/kfontinst/kfontinst/GetPid.c b/kcontrol/kfontinst/kfontinst/GetPid.c
new file mode 100644
index 000000000..015ea7ce9
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/GetPid.c
@@ -0,0 +1,519 @@
+/*
+////////////////////////////////////////////////////////////////////////////////
+//
+// File Name : GetPid.c
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 19/03/2003
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2003
+////////////////////////////////////////////////////////////////////////////////
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__DragonFly__)
+#include <sys/param.h>
+#endif
+
+#include <sys/types.h>
+
+#ifndef __cplusplus
+#define bool unsigned int
+#define false 0
+#define true (!false)
+#endif
+
+#define BUFSIZE 1024
+#define PROCDIR "/proc"
+
+/*
+ Get process ID - using name of exe and parent process ID
+
+ Implemented for:
+
+ Linux Tested on Linux 2.4
+ FreeBSD Tested on FreeBSD 5.1 by Brian Ledbetter <brian@shadowcom.net>
+ NetBSD
+ Irix
+ Solaris Tested on Solaris 8 x86 by Torsten Kasch <tk@Genetik.Uni-Bielefeld.DE>
+ HP-UX Tested on HP-UX B.11.11 U 9000/800
+ AIX
+ ...else parse output of "ps -eaf"
+
+
+ Some sections of this code are copied from / inspired by ksysguard,
+ Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org>
+
+ To test this file, do the following:
+
+ 1. Compile this file as follows:
+
+ gcc GetPid.c -DTEST_GETPID -DOS_Linux -o tst
+
+ ...replace OS_Linux with your particular OS type: OS_FreeBSD, OS_NetBSD, OS_Irix, OS_Solaris,
+ OS_HPUX, or OS_AIX
+
+ 2. Start a program - such as "vi"
+ 3. Do a "ps -eaf" to ensure there is *only one* process called "vi"
+ 4. Get the parent process ID of your "vi" above
+ 5. Call tst with that value -e.g. vi ppid=23 then ./tst vi 23
+ ...this should then print out the process ID of "vi"
+ 6. Email me and let me know if it works!
+*/
+
+#if defined OS_Linux || defined __Linux__
+
+#include <dirent.h>
+#include <ctype.h>
+
+#define FOUND_NAME 1
+#define FOUND_PPID 2
+#define FOUND_ALL (FOUND_NAME+FOUND_PPID)
+
+unsigned int kfi_getPid(const char *proc, unsigned int ppid)
+{
+ bool error=false;
+ unsigned int pid=0;
+ DIR *dir;
+ struct dirent *entry;
+
+ /* read in current process list via the /proc filesystem entry */
+ if(NULL!=(dir=opendir(PROCDIR)))
+ {
+ while((entry=readdir(dir)) && !error)
+ if(isdigit(entry->d_name[0]))
+ {
+ char buf[BUFSIZE];
+ FILE *fd;
+
+ snprintf(buf, BUFSIZE-1, PROCDIR"/%d/status", atoi(entry->d_name));
+
+ if(NULL!=(fd=fopen(buf, "r")))
+ {
+ char format[32],
+ tagformat[32],
+ tag[32],
+ name[64];
+ int found=0;
+
+ found=0;
+ sprintf(format, "%%%d[^\n]\n", (int) sizeof(buf) - 1);
+ sprintf(tagformat, "%%%ds", (int) sizeof(tag) - 1);
+ for(;found<FOUND_ALL;)
+ {
+ if (fscanf(fd, format, buf)!=1)
+ break;
+ buf[sizeof(buf)-1]='\0';
+ sscanf(buf, tagformat, tag);
+ tag[sizeof(tag) - 1] = '\0';
+ if(0==strcmp(tag, "Name:"))
+ {
+ sscanf(buf, "%*s %63s", name);
+ if(NULL==name || 0!=strcmp(name, proc))
+ break;
+ found|=FOUND_NAME;
+ }
+ else if(0==strcmp(tag, "PPid:"))
+ {
+ unsigned int proc_ppid;
+
+ sscanf(buf, "%*s %u", &proc_ppid);
+ if(ppid!=proc_ppid)
+ break;
+ found|=FOUND_PPID;
+ }
+ }
+ if(FOUND_ALL==found)
+ {
+ if(pid)
+ error=true;
+ else
+ pid=atoi(entry->d_name);
+ }
+ fclose(fd);
+ }
+ }
+ closedir(dir);
+ }
+
+ return error ? 0 : pid;
+}
+
+#elif defined OS_FreeBSD || defined OS_NetBSD || defined __FreeBSD__ || defined __NetBSD__ || defined OS_Darwin
+
+#include <ctype.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <sys/param.h>
+#if __FreeBSD_version > 500015
+#include <sys/priority.h>
+#endif
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/user.h>
+#include <unistd.h>
+unsigned int kfi_getPid(const char *proc, unsigned int ppid)
+{
+ bool error=false;
+ unsigned int pid=0;
+ int mib[4];
+ size_t len,
+ num;
+ struct kinfo_proc *p;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ sysctl(mib, 3, NULL, &len, NULL, 0);
+ p=(struct kinfo_proc*)malloc(len);
+ sysctl(mib, 3, p, &len, NULL, 0);
+
+ for(num=0; num < len / sizeof(struct kinfo_proc) && !error; num++)
+ {
+ struct kinfo_proc proc_p;
+ size_t len;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+#if __FreeBSD_version >= 500015
+ mib[3] = p[num].ki_pid;
+#elif defined(__DragonFly__) && __DragonFly_version >= 190000
+ mib[3] = p[num].kp_pid;
+#else
+ mib[3] = p[num].kp_proc.p_pid;
+#endif
+
+ len=sizeof(proc_p);
+ if(-1==sysctl(mib, 4, &proc_p, &len, NULL, 0) || !len)
+ break;
+ else
+ {
+#if __FreeBSD_version >= 500015
+ if(proc_p.ki_ppid==ppid && p[num].ki_comm && 0==strcmp(p[num].ki_comm, proc))
+ if(pid)
+ error=true;
+ else
+ pid=p[num].ki_pid;
+#elif defined (__DragonFly__) && __DragonFly_version >= 190000
+ if(proc_p.kp_ppid==ppid && p[num].kp_comm && 0==strcmp(p[num].kp_comm, proc))
+ if(pid)
+ error=true;
+ else
+ pid=p[num].kp_pid;
+#else
+#if defined(__DragonFly__)
+ if(proc_p.kp_eproc.e_ppid==ppid && p[num].kp_thread.td_comm && 0==strcmp(p[num].kp_thread.td_comm, proc))
+#else
+ if(proc_p.kp_eproc.e_ppid==ppid && p[num].kp_proc.p_comm && 0==strcmp(p[num].kp_proc.p_comm, proc))
+#endif
+ if(pid)
+ error=true;
+ else
+ pid=p[num].kp_proc.p_pid;
+#endif
+ }
+ }
+ free(p);
+
+ return error ? 0 : pid;
+}
+
+#elif defined OS_Irix || defined OS_Solaris
+
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/resource.h>
+#ifdef OS_Solaris
+
+#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
+#define PROCFS_FILE_OFFSET_BITS_HACK 1
+#undef _FILE_OFFSET_BITS
+#else
+#define PROCFS_FILE_OFFSET_BITS_HACK 0
+#endif
+
+#include <procfs.h>
+
+#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+#else
+#include <sys/procfs.h>
+#include <sys/sysmp.h>
+#endif
+#include <sys/sysinfo.h>
+
+unsigned int kfi_getPid(const char *proc, pid_t ppid)
+{
+ DIR *procdir;
+ bool error=false;
+ pid_t pid=(pid_t)0;
+
+ if(NULL!=(procdir=opendir(PROCDIR)))
+ {
+ struct dirent *de;
+
+ rewinddir(procdir);
+ while((de=readdir(procdir)) && !error)
+ if('.'==de->d_name[0])
+ continue;
+ else
+ {
+ int fd;
+ char buf[BUFSIZE];
+#ifdef OS_Solaris
+ psinfo_t psinfo;
+
+ snprintf(buf, BUFSIZE - 1, "%s/%s/psinfo", PROCDIR, de->d_name);
+#else
+ prpsinfo_t psinfo;
+
+ sprintf(buf, PROCDIR"/pinfo/%ld", pid);
+#endif
+
+ if((fd=open(buf, O_RDONLY))<0)
+ continue;
+
+#ifdef OS_Solaris
+ if(sizeof(psinfo_t)!=read(fd, &psinfo, sizeof(psinfo_t)))
+#else
+ if(ioctl(fd, PIOCPSINFO, &psinfo)<0)
+#endif
+ {
+ close(fd);
+ continue;
+ }
+ close(fd);
+
+ if(psinfo.pr_ppid==ppid && psinfo.pr_fname && 0==strcmp(psinfo.pr_fname, proc))
+ if(pid)
+ error=true;
+ else
+ pid=psinfo.pr_pid;
+ }
+ closedir(procdir);
+ }
+
+ return error ? 0 : pid;
+}
+
+#elif defined OS_HPUX
+
+#include <sys/pstat.h>
+#define MAX_PROCS 50
+
+unsigned int kfi_getPid(const char *proc, unsigned int ppid)
+{
+ bool error=false;
+ unsigned int pid=0;
+ int i,
+ count,
+ idx=0;
+ struct pst_status pst[MAX_PROCS];
+
+ while((count=pstat_getproc(&pst[0], sizeof(pst[0]), MAX_PROCS, idx)) > 0 && !error)
+ {
+ for (i = 0; i<count && !error; i++)
+ if(pst[i].pst_ppid==ppid && pst[i].pst_ucomm && 0==strcmp(pst[i].pst_ucomm, proc))
+ if(pid)
+ error=true;
+ else
+ pid=pst[i].pst_pid;
+
+ idx=pst[count-1].pst_idx+1;
+ }
+
+ return error ? 0 : pid;
+}
+
+#elif defined OS_AIX
+
+#include <procinfo.h>
+#define MAX_PROCS 50
+
+unsigned int kfi_getPid(const char *proc, unsigned int ppid)
+{
+ bool error=false;
+ unsigned int pid=0;
+ int i,
+ count,
+ idx=0;
+ struct procsinfo pi[MAX_PROCS];
+
+ while((count=getprocs(&pi, sizeof(pi[0]), 0, 0, &pid, 1)) >0 && !error)
+ {
+ for (i = 0; i<count && !error; i++)
+ if(pi[i].pi_ppid==ppid && pi[i].pi_comm && 0==strcmp(pi[i].pi_comm, proc))
+ if(pid)
+ error=true;
+ else
+ pid=pi[i].pi_pid;
+
+ idx=pi[count-1].pi_idx+1;
+ }
+
+ return error ? 0 : pid;
+}
+
+#else
+#warning "Unable to determine operating system version! This may cause the getPid() function to fail at random!"
+
+/* Default to reading "ps -eaf" output */
+
+#include <pwd.h>
+#include <limits.h>
+#include <ctype.h>
+
+#define FOUND_PID 1
+#define FOUND_PPID 2
+#define FOUND_CMD 4
+#define FOUND_ALL (FOUND_PID+FOUND_PPID+FOUND_CMD)
+
+static int checkCmd(const char *proc, const char *cmd)
+{
+ int len=(int)strlen(cmd),
+ ch;
+
+ if(len>1)
+ for(ch=len-2; ch>=0; --ch)
+ if('/'==cmd[ch])
+ return strcmp(proc, &cmd[ch+1]);
+
+ return strcmp(proc, cmd);
+}
+
+unsigned int kfi_getPid(const char *proc, unsigned int ppid)
+{
+ bool error=false;
+ unsigned int pid=0;
+ static int pid_c=-1,
+ ppid_c=-1,
+ time_c=-1,
+ cmd_c=-1;
+
+ char cmd[BUFSIZE+1];
+ FILE *p;
+
+ /* If this function has been run before, and we know the column positions, then we can grep for just our command */
+ if(-1!=pid_c && -1!=ppid_c && -1!=time_c && -1!=cmd_c)
+ snprintf(cmd, BUFSIZE, "ps -eaf | grep %s", proc);
+ else
+ strcpy(cmd, "ps -eaf");
+
+ if(NULL!=(p=popen(cmd, "r")))
+ {
+ char line[BUFSIZE+1];
+ int c=0;
+ char *linep=NULL,
+ *token=NULL;
+
+ /* Read 1st line to determine columns... */
+ if((-1==pid_c || -1==ppid_c || -1==time_c || -1==cmd_c) && NULL!=fgets(line, BUFSIZE, p))
+ {
+ for(linep=line; -1==pid_c || -1==ppid_c || -1==time_c || -1==cmd_c; linep=NULL)
+ if(NULL!=(token=strtok(linep, " \t\n")))
+ {
+ if(0==strcmp("PID", token))
+ pid_c=c;
+ else if(0==strcmp("PPID", token))
+ ppid_c=c;
+ else if(NULL!=strstr("TIME", token))
+ time_c=c;
+ else if(0==strcmp("COMMAND", token) || 0==strcmp("CMD", token))
+ cmd_c=c;
+ c++;
+ }
+ else
+ break;
+ }
+
+ /* If all column headings read, then look for details... */
+ if(-1!=pid_c && -1!=ppid_c && -1!=time_c && -1!=cmd_c)
+ while(NULL!=fgets(line, BUFSIZE, p) && !error)
+ {
+ int found=0,
+ ps_pid=0,
+ offset=0;
+
+ c=0;
+ for(linep=line; FOUND_ALL!=found; linep=NULL)
+ if(NULL!=(token=strtok(linep, " \t\n")))
+ {
+ if(c==pid_c)
+ {
+ found|=FOUND_PID;
+ ps_pid=atoi(token);
+ }
+ else if(c==ppid_c)
+ {
+ if(((unsigned int)atoi(token))!=ppid)
+ break;
+ found|=FOUND_PPID;
+ }
+ else if(c==time_c)
+ offset=isdigit(token[0]) ? 0 : 1;
+ else if(c==(cmd_c+offset))
+ {
+ if(0!=checkCmd(proc, token))
+ break;
+ found|=FOUND_CMD;
+ }
+ c++;
+ }
+ else
+ break;
+
+ if(FOUND_ALL==found)
+ {
+ if(pid)
+ error=true;
+ else
+ pid=ps_pid;
+ }
+ }
+ pclose(p);
+ }
+
+ return error ? 0 : pid;
+}
+
+#endif
+
+#ifdef TEST_GETPID
+int main(int argc, char *argv[])
+{
+ if(3==argc)
+ printf("PID %u\n", kfi_getPid(argv[1], atoi(argv[2])));
+ else
+ printf("Usage: %s <process> <parent-process-id>\n", argv[0]);
+ return 0;
+}
+#endif
diff --git a/kcontrol/kfontinst/kfontinst/Main.cpp b/kcontrol/kfontinst/kfontinst/Main.cpp
new file mode 100644
index 000000000..2da9a8997
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/Main.cpp
@@ -0,0 +1,335 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// File Name : Main.cpp
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 20/03/2003
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "Misc.h"
+#include "FontEngine.h"
+#include "Fontmap.h"
+#include "XConfig.h"
+#include "kxftconfig.h"
+#include <fontconfig/fontconfig.h>
+#include <qfile.h>
+#include <stdio.h>
+
+//
+// Bug#99335 Solaris 2.6 does not have getopt.h :-(
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#include <iostream>
+
+#define KFI_XF86CFG "XF86Config"
+#define KFI_XORGCFG "xorg.conf"
+
+static const char * getFile(const char *entry, const char **posibilities)
+{
+ if(KFI::Misc::fExists(entry))
+ return entry;
+ else
+ {
+ int f;
+
+ for(f=0; posibilities[f]; ++f)
+ if(KFI::Misc::fExists(posibilities[f]))
+ break;
+
+ return posibilities[f];
+ }
+}
+
+static const char * constXConfigFiles[]=
+{
+ "/etc/X11/"KFI_XORGCFG,
+ "/etc/X11/"KFI_XORGCFG"-4",
+ "/etc/"KFI_XORGCFG,
+ "/usr/X11R6/etc/X11/"KFI_XORGCFG,
+ "/usr/X11R6/etc/X11/"KFI_XORGCFG"-4",
+ "/usr/X11R6/lib/X11/"KFI_XORGCFG,
+ "/usr/X11R6/lib/X11/"KFI_XORGCFG"-4",
+
+ "/etc/X11/"KFI_XF86CFG"-4",
+ "/etc/X11/"KFI_XF86CFG,
+ "/etc/"KFI_XF86CFG"-4",
+ "/etc/"KFI_XF86CFG,
+ "/usr/X11R6/etc/X11/"KFI_XF86CFG"-4",
+ "/usr/X11R6/etc/X11/"KFI_XF86CFG,
+ "/usr/X11R6/lib/X11/"KFI_XF86CFG"-4",
+ "/usr/X11R6/lib/X11/"KFI_XF86CFG,
+
+ NULL
+};
+
+static const char * constXfsConfigFiles[]=
+{
+ "/etc/X11/fs/config",
+ "/usr/openwin/lib/X11/fonts/fontserver.cfg",
+ NULL
+};
+
+KFI::CXConfig * getXCfg(bool root)
+{
+ if(root)
+ {
+ //
+ // Try to determine location for X and xfs config files...
+ // ...note on some systems (Solaris and HP-UX) only the xfs file will be found
+ bool xfs=false;
+ KFI::CXConfig *xcfg=NULL;
+ QString xConfigFile=getFile(QFile::encodeName(constXConfigFiles[0]), constXConfigFiles),
+ xfsConfigFile=getFile(QFile::encodeName(constXfsConfigFiles[0]), constXfsConfigFiles);
+
+ // If found xfs, but not X - then assume that xfs is being used...
+ if(!xfsConfigFile.isEmpty() && xConfigFile.isEmpty())
+ xfs=true;
+ else if(!xConfigFile.isEmpty()) // Read xConfig file to determine which one...
+ {
+ xcfg=new KFI::CXConfig(KFI::CXConfig::X11, xConfigFile);
+
+ if(!xfsConfigFile.isEmpty() && xcfg->xfsInPath())
+ {
+ delete xcfg;
+ xfs=true;
+ }
+ }
+
+ // OK, if still set to X11 config, but this mentions fontconfig FPE, then delete - as we're not interested
+ // anymore...
+ if(xcfg && xcfg->fcInPath())
+ delete xcfg;
+
+ return xfs ? new KFI::CXConfig(KFI::CXConfig::XFS, xfsConfigFile) : xcfg;
+ }
+
+ return NULL;
+}
+
+static void usage(char *app)
+{
+ std::cerr << "Usage: " << app << " [OPTIONS]... [FOLDER]..." << std::endl
+ << std::endl
+ << " Helper application for KDE's fonts:/ ioslave." << std::endl
+ << std::endl
+#ifdef HAVE_GETOPT_H
+ << " -x, --configure_x Configure FOLDER for regular x - i.e." << std::endl
+ << " create fonts.dir, fonts.scale and encodngs.dir" << std::endl
+ << std::endl
+ << " -g, --configure_gs Create Fontmap file. If run as root, then " << std::endl
+ << " no paramter is required as all fonts are " << std::endl
+ << " configured, and Fontmap placed in /etc/fonts" << std::endl
+ << " For non-root, fonts located in FOLDER are" << std::endl
+ << " configured, and Fontmap placed there." << std::endl
+ << std::endl
+ << " -f, --add_to_fc_cfg Add FOLDER to fontconfig config files." << std::endl
+ << std::endl
+ << " -a, --add_to_x_cfg Add FOLDER to X config files only when run as root.," << std::endl
+ << std::endl
+ << " -r, --refresh_x Refresh X." << std::endl
+ << std::endl
+ << " -s, --refresh_xfs Refresh Xfs." << std::endl
+#else
+ << " -x Configure FOLDER for regular x - i.e." << std::endl
+ << " create fonts.dir, fonts.scale and encodngs.dir" << std::endl
+ << std::endl
+ << " -g Create Fontmap file. If run as root, then " << std::endl
+ << " no paramter is required as all fonts are " << std::endl
+ << " configured, and Fontmap placed in /etc/fonts" << std::endl
+ << " For non-root, fonts located in FOLDER are" << std::endl
+ << " configured, and Fontmap placed there." << std::endl
+ << std::endl
+ << " -f Add FOLDER to fontconfig config files." << std::endl
+ << std::endl
+ << " -a Add FOLDER to X config files only when run as root.," << std::endl
+ << std::endl
+ << " -r Refresh X." << std::endl
+ << std::endl
+ << " -s Refresh Xfs." << std::endl
+#endif
+ << std::endl
+ << std::endl
+ << " (C) Craig Drummond, 2003, 2004." << std::endl
+ << std::endl;
+
+ exit(-1);
+}
+
+void refresh(bool refreshX, bool refreshXfs, bool root)
+{
+ if(refreshX)
+ KFI::CXConfig::refreshPaths(false);
+ if(refreshXfs && root)
+ KFI::CXConfig::refreshPaths(true);
+}
+
+int main(int argc, char *argv[])
+{
+#ifdef HAVE_GETOPT_H
+ static struct option options[]=
+ {
+ { "configure_x", 0, 0, 'x' },
+ { "configure_gs", 0, 0, 'g' },
+ { "add_to_fc_cfg", 0, 0, 'f' },
+ { "add_to_x_cfg", 0, 0, 'a' },
+ { "refresh_x", 0, 0, 'r' },
+ { "refresh_xfs", 0, 0, 's' },
+ { 0, 0, 0, 0 }
+ };
+#endif
+
+ int c=0,
+ rv=0;
+ bool doX=false,
+ doGs=false,
+ addToX=false,
+ addToFc=false,
+ refreshX=false,
+ refreshXfs=false,
+ root=KFI::Misc::root();
+
+#ifdef HAVE_GETOPT_H
+ int optIndex;
+ while(-1!=(c=getopt_long(argc, argv, "xgfars", options, &optIndex)))
+#else
+ while(-1!=(c=getopt(argc, argv, "xgfars")))
+#endif
+ switch(c)
+ {
+ case 'x':
+ doX=true;
+ break;
+ case 'g':
+ doGs=true;
+ break;
+ case 'f':
+ addToFc=true;
+ break;
+ case 'a':
+ addToX=true;
+ break;
+ case 'r':
+ refreshX=true;
+ break;
+ case 's':
+ refreshXfs=true;
+ break;
+ case '?':
+ usage(argv[0]);
+ break;
+ }
+
+ int left=argc-optind;
+ bool folderRequired=doX || addToX || addToFc || (!root && doGs);
+
+ if (left>1 || (0==left && folderRequired) || (!doX && !doGs && !addToX && !addToFc))
+ usage(argv[0]);
+ else
+ {
+ QString folder;
+
+ if(folderRequired)
+ {
+ folder=argv[optind];
+ unsigned int len=folder.length();
+
+ // Remove quotes...
+ if( (folder[0]==QChar('\'') || folder[0]==QChar('\"')) &&
+ (folder[len-1]==QChar('\'') || folder[len-1]==QChar('\"')))
+ folder=folder.mid(1, len-2);
+ folder=KFI::Misc::dirSyntax(folder);
+ }
+
+ if(folderRequired && !KFI::Misc::dExists(folder))
+ {
+ std::cerr << "ERROR: " << QFile::encodeName(folder) << " does not exist!" << std::endl;
+ rv=-2;
+ }
+ else
+ {
+ if(!folder.isEmpty())
+ {
+ if(0==rv && addToFc)
+ {
+ //
+ // Only add folder to fontconfig's config if its not already there...
+ FcStrList *list=FcConfigGetFontDirs(FcConfigGetCurrent());
+ FcChar8 *dir;
+ bool found=false;
+
+ while((dir=FcStrListNext(list)))
+ if(0==KFI::Misc::dirSyntax((const char *)dir).find(folder))
+ found=true;
+
+ if(!found)
+ {
+ KXftConfig *xft=new KXftConfig(KXftConfig::Dirs, root);
+
+ xft->addDir(folder);
+ rv=xft->apply() ? 0 : -3;
+ delete xft;
+ }
+ }
+
+ if(0==rv && addToX && root)
+ {
+ KFI::CXConfig *x=NULL;
+
+ if((x=getXCfg(true)))
+ {
+ x->addPath(folder);
+ rv=x->writeConfig() ? 0 : -4;
+ delete x;
+ }
+ else
+ rv=-5;
+ }
+ }
+
+ if(0==rv && (doX || doGs))
+ {
+ if(0==rv && doX)
+ rv=KFI::CXConfig::configureDir(folder) ? 0 : -5;
+
+ refresh(refreshX, refreshXfs, root);
+
+ if(0==rv && doGs)
+ {
+ KFI::CFontEngine fe;
+ rv=KFI::Fontmap::create(root ? QString::null : folder, fe) ? 0 : -6;
+ }
+ }
+ else if(0==rv)
+ refresh(refreshX, refreshXfs, root);
+ }
+ }
+
+ return rv;
+}
diff --git a/kcontrol/kfontinst/kfontinst/Makefile.am b/kcontrol/kfontinst/kfontinst/Makefile.am
new file mode 100644
index 000000000..3cfcfa689
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/Makefile.am
@@ -0,0 +1,16 @@
+bin_PROGRAMS = kfontinst
+kfontinst_SOURCES = \
+Main.cpp \
+FontEngine.cpp \
+Fontmap.cpp \
+GetPid.c \
+XConfig.cpp
+
+noinst_HEADERS= \
+FontEngine.h \
+Fontmap.h \
+XConfig.h
+
+kfontinst_LDADD = ../../fonts/libkxftconfig.la $(LIBFONTCONFIG_LIBS) $(LIBFREETYPE_LIBS) $(LIBZ) $(LIB_KIO) ../lib/libkfontinst.la
+kfontinst_LDFLAGS = $(all_libraries) $(LIBFONTCONFIG_RPATH) $(LIBFREETYPE_RPATH) $(KDE_RPATH)
+AM_CPPFLAGS= -DOS_$(UNAME) -I$(srcdir)/../lib -I$(srcdir)/../../fonts $(all_includes) $(LIBFREETYPE_CFLAGS) $(LIBFONTCONFIG_CFLAGS)
diff --git a/kcontrol/kfontinst/kfontinst/XConfig.cpp b/kcontrol/kfontinst/kfontinst/XConfig.cpp
new file mode 100644
index 000000000..490c8dfe5
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/XConfig.cpp
@@ -0,0 +1,760 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Class Name : KFI::CXConfig
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 05/05/2001
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2001, 2002, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#include "XConfig.h"
+#include "FontEngine.h"
+#include "kxftconfig.h"
+#include <ksavefile.h>
+#include <qtextstream.h>
+#include <fstream>
+#include <string.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <klocale.h>
+#include <sys/types.h>
+#include <signal.h>
+
+#if defined OS_Irix || defined OS_Solaris
+extern "C" unsigned int kfi_getPid(const char *proc, pid_t ppid);
+#else
+extern "C" unsigned int kfi_getPid(const char *proc, unsigned int ppid);
+#endif
+
+#define UNSCALED ":unscaled"
+
+namespace KFI
+{
+
+CXConfig::CXConfig(EType type, const QString &file)
+ : itsType(type),
+ itsFileName(file),
+ itsOk(false),
+ itsWritable(false)
+{
+ itsPaths.setAutoDelete(true);
+ readConfig();
+}
+
+bool CXConfig::configureDir(const QString &dir)
+{
+ //
+ // On systems without mkfontscale, the following will fail, so cant base
+ // return value upon that - hence only check return value of mkfontdir
+ Misc::doCmd("mkfontscale", QFile::encodeName(dir));
+ return Misc::doCmd("mkfontdir", QFile::encodeName(dir));
+}
+
+bool CXConfig::readConfig()
+{
+ itsOk=false;
+
+ switch(itsType)
+ {
+ case XFS:
+ itsOk=processXfs(true);
+ break;
+ case X11:
+ itsOk=processX11(true);
+ break;
+ }
+
+ if(itsOk)
+ itsWritable=Misc::fExists(itsFileName) ? Misc::fWritable(itsFileName)
+ : Misc::dWritable(Misc::getDir(itsFileName));
+ else
+ itsWritable=false;
+
+ return itsOk;
+}
+
+bool CXConfig::writeConfig()
+{
+ bool written=false;
+
+ //
+ // Check if file has been written since we last read it. If so, then re-read
+ // and add any new paths that we've added...
+ if(Misc::fExists(itsFileName) && Misc::getTimeStamp(itsFileName)!=itsTime)
+ {
+ CXConfig newConfig(itsType, itsFileName);
+
+ if(newConfig.ok())
+ {
+ TPath *path;
+
+ for(path=itsPaths.first(); path; path=itsPaths.next())
+ if(TPath::DIR==path->type && !path->orig)
+ newConfig.addPath(path->dir, path->unscaled);
+
+ written=newConfig.madeChanges() ? newConfig.writeConfig() : true;
+ }
+ }
+ else
+ switch(itsType)
+ {
+ case XFS:
+ written=processXfs(false);
+ break;
+ case X11:
+ written=processX11(false);
+ break;
+ }
+ if(written)
+ readConfig();
+
+ return written;
+}
+
+bool CXConfig::madeChanges()
+{
+ if(itsOk && itsWritable)
+ {
+ TPath *path;
+
+ for(path=itsPaths.first(); path; path=itsPaths.next())
+ if(!path->orig)
+ return true;
+ }
+
+ return false;
+}
+
+void CXConfig::addPath(const QString &dir, bool unscaled)
+{
+ if(itsWritable)
+ {
+ QString ds(Misc::dirSyntax(dir));
+
+ if(Misc::dExists(dir))
+ {
+ TPath *path=findPath(ds);
+
+ if(NULL==path)
+ itsPaths.append(new TPath(ds, unscaled, TPath::DIR, false));
+ }
+ }
+}
+
+bool CXConfig::inPath(TPath::EType type)
+{
+ if(itsOk && X11==itsType)
+ {
+ TPath *path=NULL;
+
+ for(path=itsPaths.first(); path; path=itsPaths.next())
+ if(type==path->type)
+ return true;
+ }
+
+ return false;
+}
+
+void CXConfig::refreshPaths(bool xfs)
+{
+ if(xfs)
+ {
+ if(Misc::root())
+ {
+ unsigned int xfsPid=kfi_getPid("xfs", 1);
+
+ if(xfsPid)
+ {
+ QString pid;
+
+ kill(xfsPid, SIGUSR1);
+ }
+ }
+ }
+ else
+ Misc::doCmd("xset", "fp", "rehash");
+}
+
+CXConfig::TPath * CXConfig::findPath(const QString &dir)
+{
+ TPath *path=NULL;
+ QString ds(Misc::dirSyntax(dir));
+
+ for(path=itsPaths.first(); path; path=itsPaths.next())
+ if(path->dir==ds)
+ return path;
+
+ return NULL;
+}
+
+static void processPath(char *str, QString &path, bool &unscaled)
+{
+ char *unsc=NULL;
+
+ unscaled=false;
+
+ if(NULL!=(unsc=strstr(str, UNSCALED)))
+ {
+ *unsc='\0';
+ unscaled=true;
+ }
+
+ path=str;
+
+ if(str[strlen(str)-1]!='/')
+ path+="/";
+}
+
+inline bool isWhitespace(char ch)
+{
+ return (' '==ch || '\t'==ch || '\n'==ch) ? true : false;
+}
+
+static unsigned int commentChars(char *buffer)
+{
+ unsigned int num=0;
+
+ if(buffer[0]=='#')
+ for(num=1; num<strlen(buffer)+1; ++num)
+ if(buffer[num]=='\n' || buffer[num]=='\0')
+ break;
+
+ return num;
+}
+
+static bool commentedOut(char *buffer, char *sect)
+{
+ if(sect!=buffer && '\n'!=*(sect-1))
+ {
+ char *ch;
+
+ for(ch=sect-1; ch>=buffer; ch--)
+ if(*ch=='\n')
+ break;
+ else if(*ch=='#')
+ return true;
+ }
+
+ return false;
+}
+
+static char * locateSection(char *buffer, const char *section)
+{
+ const char *sectionMarker ="Section";
+ const int sectionMarkerLen=7;
+
+ char *s=NULL,
+ *buf=buffer;
+
+ do
+ {
+ s=strstr(buf, sectionMarker);
+
+ if(s)
+ {
+ bool com=commentedOut(buffer, s);
+
+ buf=s+sectionMarkerLen;
+ if(com)
+ s=NULL;
+ else
+ {
+ // Skip any whitespace
+ for(s+=sectionMarkerLen; s && isWhitespace(*s); s++)
+ ;
+
+ // Now check section type
+ if(s && s==strstr(s, section)) // If found, then again skip past whitespace
+ for(s+=strlen(section); s && isWhitespace(*s); s++)
+ ;
+ else
+ s=NULL;
+ }
+ }
+ else
+ break;
+ }
+ while(!s);
+
+ return s;
+}
+
+static const char *endSectionMarker ="EndSection";
+static const int endSectionMarkerLen=10;
+
+static char *locateEndSection(char *buffer)
+{
+ char *s=NULL,
+ *buf=buffer;
+
+ do
+ {
+ s=strstr(buf, endSectionMarker);
+
+ if(s)
+ {
+ bool com=commentedOut(buffer, s);
+
+ buf=s+endSectionMarkerLen;
+ if(com)
+ s=NULL;
+ }
+ else
+ break;
+ }
+ while(!s);
+
+ return s;
+}
+
+static char * getItem(char **start, char **end, const char *key, unsigned int &size, bool remove, char *buffer)
+{
+ static const int constMaxItemLen = 1024;
+ static char item[constMaxItemLen+1];
+
+ unsigned int keyLen=strlen(key);
+
+ char *s=NULL,
+ *buf=*start;
+
+ do
+ {
+ s=strstr(buf, key);
+
+ if(s && s<*end)
+ {
+ bool com=commentedOut(buf, s);
+
+ buf=s+keyLen;
+ if(com)
+ s=NULL;
+ else
+ {
+ char *beg=s;
+ // Skip any whitespace
+ for(s+=keyLen; s && isWhitespace(*s); s++)
+ ;
+
+ if(s && *s=='\"' && s<*end)
+ {
+ char *e=strchr(s+1, '\"'),
+ *nl=strchr(s+1, '\n');
+
+ if(e && e<*end && (!nl || nl>e) && e-s<=constMaxItemLen)
+ {
+ memcpy(item, s+1, (e-s)-1);
+ item[(e-s)-1]='\0';
+
+ if(remove)
+ {
+ for(beg--; beg>=buffer && *beg!='\n' && *beg !='\"'; beg--)
+ ;
+ if(!nl)
+ nl=e+1;
+ memmove(beg, nl, ((buffer+size)-nl)+1);
+ size-=nl-beg;
+ *end-=nl-beg;
+ }
+ else
+ *start=e+1;
+
+ return item;
+ }
+ else
+ s=NULL;
+ }
+ else
+ s=NULL;
+ }
+ }
+ else
+ break;
+ }
+ while(!s);
+
+ return NULL;
+}
+
+bool CXConfig::processX11(bool read)
+{
+ std::ifstream x11(QFile::encodeName(itsFileName));
+ bool ok=false;
+
+ if(x11)
+ {
+ itsTime=Misc::getTimeStamp(itsFileName);
+
+ bool closed=false;
+
+ x11.seekg(0, std::ios::end);
+ unsigned int size=(std::streamoff) x11.tellg();
+
+ if(read)
+ itsPaths.clear();
+
+ if(size<65536) // Just incase...
+ {
+ char *buffer=new char [size+1];
+
+ if(buffer)
+ {
+ x11.seekg(0, std::ios::beg);
+ x11.read(buffer, size);
+
+ if(x11.good())
+ {
+ char *filesStart=NULL,
+ *filesEnd=NULL;
+
+ closed=true;
+ x11.close();
+ buffer[size]='\0';
+
+ if(NULL!=(filesStart=locateSection(buffer, "\"Files\"")) && NULL!=(filesEnd=locateEndSection(filesStart)))
+ {
+ char *pos=filesStart,
+ *item;
+
+ while(NULL!=(item=getItem(&pos, &filesEnd, "FontPath", size, !read, buffer)))
+ if(read) // Then save paths...
+ {
+ QString path;
+ bool unscaled;
+
+ processPath(item, path, unscaled);
+
+ if(NULL==findPath(path))
+ itsPaths.append(new TPath(path, unscaled, TPath::getType(path)));
+ }
+
+ if(read)
+ ok=true;
+ else
+ {
+ Misc::createBackup(itsFileName);
+
+ KSaveFile out(itsFileName);
+ FILE *fstream=out.fstream();
+
+ if(fstream)
+ {
+ char *from=buffer,
+ *modStart=NULL,
+ *modEnd=NULL;
+ bool foundFt=false;
+ TPath *path;
+
+ // Check if "freetype" OR "xtt" is loaded for usage of TTF's
+ if(NULL!=(modStart=locateSection(buffer, "\"Module\"")) && NULL!=(modEnd=locateEndSection(modStart)))
+ {
+ pos=modStart;
+
+ while(NULL!=(item=getItem(&pos, &modEnd, "Load", size, false, buffer)) && !foundFt)
+ if(0==strcmp(item, "freetype") || 0==strcmp(item, "xtt"))
+ foundFt=true;
+ }
+
+ if(!foundFt && modStart && modEnd && modStart<filesStart) // Then write mod section first...
+ {
+ fwrite(from, 1, modEnd-from, fstream);
+ if(!foundFt)
+ fputs(" Load \"freetype\"\n", fstream); // CPD TODO: Which is better xtt of freetype? Perhaps check locale?
+ fwrite(modEnd, 1, endSectionMarkerLen, fstream);
+ from=modEnd+endSectionMarkerLen;
+ }
+
+ fwrite(from, 1, filesEnd-from, fstream);
+
+ for(path=itsPaths.first(); path; path=itsPaths.next())
+ if(TPath::DIR!=path->type || Misc::dExists(path->dir))
+ {
+ QCString cPath(QFile::encodeName(Misc::xDirSyntax(path->dir)));
+
+ fputs(" FontPath \t\"", fstream);
+ fwrite(cPath.data(), 1, cPath.length(), fstream);
+ if(path->unscaled)
+ fputs(UNSCALED, fstream);
+ fputs("\"\n", fstream);
+ }
+
+ fwrite(filesEnd, 1, endSectionMarkerLen, fstream);
+ from=filesEnd+endSectionMarkerLen;
+
+ if(!foundFt && modStart && modEnd && modStart>filesStart) // Then write mod section last...
+ {
+ fwrite(from, 1, modEnd-from, fstream);
+ if(!foundFt)
+ fputs(" Load \"freetype\"\n", fstream);
+ fwrite(modEnd, 1, endSectionMarkerLen, fstream);
+ from=modEnd+endSectionMarkerLen;
+ }
+ if(((unsigned int)(from-buffer))<size)
+ fwrite(from, 1, size-(from-buffer), fstream);
+ ok=true;
+ }
+ }
+ }
+ }
+ delete [] buffer;
+ }
+ }
+ if(!closed)
+ x11.close();
+ }
+
+ return ok;
+}
+
+static bool isXfsKey(const char *str)
+{
+ static const char *constKeys[]=
+ {
+ "alternate-servers",
+ "cache-balance",
+ "cache-hi-mark",
+ "cache-low-mark",
+ "catalogue",
+ "client-limit",
+ "clone-self",
+ "default-point-size",
+ "default-resolutions",
+ "deferglyphs",
+ "error-file",
+ "no-listen",
+ "port",
+ "server-number",
+ "snf-format",
+ "trusted-clients",
+ "use-syslog",
+ NULL
+ };
+
+ for(unsigned int key=0; NULL!=constKeys[key]; ++key)
+ if(strstr(str, constKeys[key])==str)
+ {
+ unsigned int sLen=strlen(str),
+ kLen=strlen(constKeys[key]);
+
+ if(sLen>kLen && isWhitespace(str[kLen]) || '\0'==str[kLen] || '#'==str[kLen] || '='==str[kLen])
+ return true;
+ }
+
+ return false;
+}
+
+static char * getXfsPath(char *buffer, unsigned int &totalSize, unsigned int offsetSize)
+{
+ // Remove & return a path from the buffer
+ const unsigned int constMaxPathLen=8192;
+
+ static char path[constMaxPathLen];
+ bool found=false;
+
+ if(offsetSize<totalSize) // Just to make sure soething hasn't gone horribly wrong!
+ {
+ unsigned int i;
+
+ for(i=0; i<offsetSize && !found; i++)
+ if(!isWhitespace(buffer[i]) && ','!=buffer[i])
+ {
+ unsigned int comChars=commentChars(&buffer[i]);
+
+ if(comChars)
+ i+=comChars;
+ else
+ if(isXfsKey(&buffer[i]))
+ break;
+ else
+ {
+ // A path is terminated by either a comma, another key, or eof...
+
+ unsigned int j=0;
+
+ for(j=1; j<offsetSize-i && !found; j++)
+ if(buffer[i+j]==',' || buffer[i+j]=='\n' || buffer[i+j]=='\0' || isXfsKey(&buffer[i+j]))
+ {
+ if(j>0 && j<constMaxPathLen)
+ {
+ memcpy(path, &buffer[i], j);
+ path[j]='\0';
+ if(buffer[i+j]==',')
+ j++;
+ memmove(buffer, &buffer[i+j], (offsetSize-(i+j))+1);
+ totalSize-=(i+j);
+ found=true;
+ }
+ }
+ }
+ }
+ }
+
+ return found ? path : NULL;
+}
+
+bool CXConfig::processXfs(bool read)
+{
+ std::ifstream xfs(QFile::encodeName(itsFileName));
+ bool ok=false;
+
+ if(xfs)
+ {
+ itsTime=Misc::getTimeStamp(itsFileName);
+
+ bool closed=false;
+
+ xfs.seekg(0, std::ios::end);
+ unsigned int size= (std::streamoff) xfs.tellg();
+
+ if(read)
+ itsPaths.clear();
+
+ if(size<32768) // Just incase...
+ {
+ char *buffer=new char [size+1];
+
+ if(buffer)
+ {
+ xfs.seekg(0, std::ios::beg);
+ xfs.read(buffer, size);
+
+ if(xfs.good())
+ {
+ const char *constCatalogueStr="catalogue";
+ char *cat=NULL;
+ bool found=false,
+ formatError=false;
+
+ closed=true;
+ xfs.close();
+ buffer[size]='\0';
+
+ // Now remove the directory lists from the buffer...
+ do
+ if(NULL!=(cat=strstr(buffer, constCatalogueStr)))
+ {
+ cat+=strlen(constCatalogueStr);
+
+ if(!isWhitespace(*(cat-1)))
+ {
+ // Check it's not been commented out - by searching back until we get to the start of the buffer,
+ // a carriage-return, or a hash...
+
+ if(!commentedOut(buffer, cat))
+ {
+ // Look for '='
+ unsigned int i;
+
+ for(i=1; i<size-(cat-buffer) && !found && !formatError; ++i)
+ if(!isWhitespace(cat[i]))
+ {
+ unsigned int comChars=commentChars(&cat[i]);
+
+ if(comChars)
+ i+=comChars;
+ else
+ if(cat[i]!='=' || i+1>=size-(cat-buffer))
+ formatError=true;
+ else
+ {
+ char *path;
+
+ cat=&cat[i+1]; // skip equals sign
+ while(NULL!=(path=getXfsPath(cat, size, size-(cat-buffer))))
+ if(read)
+ {
+ QString str;
+ bool unscaled;
+ processPath(path, str, unscaled);
+
+ if(NULL==findPath(path))
+ itsPaths.append(new TPath(str, unscaled));
+ }
+
+ if(!read) // then must be write...
+ {
+ Misc::createBackup(itsFileName);
+
+ KSaveFile out(itsFileName);
+ FILE *fstream=out.fstream();
+
+ if(fstream)
+ {
+ bool first=true;
+ TPath *p=NULL;
+
+ fwrite(buffer, 1, cat-buffer, fstream);
+ fputc(' ', fstream);
+ for(p=itsPaths.first(); p; p=itsPaths.next())
+ if(Misc::dExists(p->dir))
+ {
+ QCString cPath(QFile::encodeName(Misc::xDirSyntax(p->dir)));
+
+ if(!first)
+ {
+ fputc(',', fstream);
+ fputc('\n', fstream);
+ }
+ fwrite(cPath.data(), 1, cPath.length(), fstream);
+ if(p->unscaled)
+ fputs(UNSCALED, fstream);
+ first=false;
+ }
+ fwrite(cat, 1, size-(cat-buffer), fstream);
+ ok=true;
+ }
+ }
+ else
+ ok=true;
+
+ found=true;
+ }
+ }
+ }
+ }
+ }
+ while(NULL!=cat && !found && !formatError);
+ }
+ delete [] buffer;
+ }
+ }
+ if(!closed)
+ xfs.close();
+ }
+
+ return ok;
+}
+
+
+CXConfig::TPath::EType CXConfig::TPath::getType(const QString &d)
+{
+ QString str(d);
+
+ str.replace(QRegExp("\\s*"), "");
+
+ return 0==str.find("unix/:")
+ ? FONT_SERVER
+ : "fontconfig"==str
+ ? FONT_CONFIG
+ : DIR;
+}
+
+}
diff --git a/kcontrol/kfontinst/kfontinst/XConfig.h b/kcontrol/kfontinst/kfontinst/XConfig.h
new file mode 100644
index 000000000..5a8ed1624
--- /dev/null
+++ b/kcontrol/kfontinst/kfontinst/XConfig.h
@@ -0,0 +1,114 @@
+#ifndef __X_CONFIG_H__
+#define __X_CONFIG_H__
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Class Name : KFI::CXConfig
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 05/05/2001
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2001, 2002, 2003, 2004
+///////////////////////////////////////////////////////////////////////////////
+
+#include "Misc.h"
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <time.h>
+
+namespace KFI
+{
+
+class CFontEngine;
+
+class CXConfig
+{
+ public:
+
+ struct TPath
+ {
+ enum EType
+ {
+ DIR,
+ FONT_SERVER,
+ FONT_CONFIG
+ };
+
+ TPath(const QString &d, bool u=false, EType t=DIR, bool o=true)
+ : dir(DIR==t ? Misc::dirSyntax(d) : d), unscaled(u), orig(o), type(t) {}
+
+ static EType getType(const QString &d);
+
+ QString dir;
+ bool unscaled,
+ orig; // Was dir in file when read?
+ EType type;
+ };
+
+ enum EType
+ {
+ XFS,
+ X11
+ };
+
+ public:
+
+ CXConfig(EType type, const QString &file);
+
+ static bool configureDir(const QString &dir);
+
+ bool ok() { return itsOk; }
+ bool writable() { return itsWritable; }
+ bool readConfig();
+ bool writeConfig();
+ bool madeChanges();
+ void addPath(const QString &dir, bool unscaled=false);
+ bool inPath(TPath::EType type);
+ bool xfsInPath() { return inPath(TPath::FONT_SERVER); }
+ bool fcInPath() { return inPath(TPath::FONT_CONFIG); }
+ void refreshPaths() { refreshPaths(XFS==itsType); }
+ void restart();
+ EType getType() { return itsType; }
+
+ static void refreshPaths(bool xfs);
+
+ private:
+
+ bool processX11(bool read);
+ bool processXfs(bool read);
+
+ TPath * findPath(const QString &dir);
+
+ private:
+
+ EType itsType;
+ QPtrList<TPath> itsPaths;
+ QString itsFileName,
+ itsInsertPos;
+ bool itsOk,
+ itsWritable;
+ time_t itsTime;
+};
+
+}
+
+#endif