You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
761 lines
23 KiB
761 lines
23 KiB
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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 <tqtextstream.h>
|
|
#include <fstream>
|
|
#include <string.h>
|
|
#include <tqdir.h>
|
|
#include <tqregexp.h>
|
|
#include <tdelocale.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 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<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(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 && 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))
|
|
{
|
|
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))<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(TQFile::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)
|
|
{
|
|
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;
|
|
}
|
|
|
|
}
|