//////////////////////////////////////////////////////////////////////////////// // // 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 #include #include #include #include #include #include #include #include #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 TQString &file) : itsType(type), itsFileName(file), itsOk(false), itsWritable(false) { itsPaths.setAutoDelete(true); readConfig(); } bool CXConfig::configureDir(const TQString &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", TQFile::encodeName(dir)); return Misc::doCmd("mkfontdir", TQFile::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 TQString &dir, bool unscaled) { if(itsWritable) { TQString 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) { TQString pid; kill(xfsPid, SIGUSR1); } } } else Misc::doCmd("xset", "fp", "rehash"); } CXConfig::TPath * CXConfig::findPath(const TQString &dir) { TPath *path=NULL; TQString 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, TQString &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=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(TQFile::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... { TQString 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 && modStarttype || Misc::dExists(path->dir)) { TQCString cPath(TQFile::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))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(offsetSize0 && j=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) { TQString 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)) { TQCString cPath(TQFile::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 TQString &d) { TQString str(d); str.replace(TQRegExp("\\s*"), ""); return 0==str.find("unix/:") ? FONT_SERVER : "fontconfig"==str ? FONT_CONFIG : DIR; } }