diff options
Diffstat (limited to 'kcontrol/kfontinst/kfontinst')
-rw-r--r-- | kcontrol/kfontinst/kfontinst/FontEngine.cpp | 376 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/FontEngine.h | 142 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/Fontmap.cpp | 596 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/Fontmap.h | 79 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/GetPid.c | 519 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/Main.cpp | 335 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/Makefile.am | 16 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/XConfig.cpp | 760 | ||||
-rw-r--r-- | kcontrol/kfontinst/kfontinst/XConfig.h | 114 |
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(¤t, 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 |