diff options
Diffstat (limited to 'kcontrol/kfontinst/kfontinst/XConfig.cpp')
-rw-r--r-- | kcontrol/kfontinst/kfontinst/XConfig.cpp | 760 |
1 files changed, 760 insertions, 0 deletions
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; +} + +} |