26 #ifdef HAVE_SYS_MMAN_H
29 #include <sys/types.h>
30 #ifdef HAVE_SYS_STAT_H
38 #include <tqfileinfo.h>
39 #include <tqtextcodec.h>
40 #include <tqtextstream.h>
42 #include "tdeconfigbackend.h"
43 #include "tdeconfigbase.h"
44 #include <tdeapplication.h>
45 #include <tdeglobal.h>
46 #include <tdeprocess.h>
48 #include <kstandarddirs.h>
49 #include <ksavefile.h>
53 extern bool checkAccess(
const TQString& pathname,
int mode);
55 static TQCString printableToString(
const char *str,
int l)
59 ((*str ==
' ') || (*str ==
'\t') || (*str ==
'\r')))
66 ((str[l-1] ==
' ') || (str[l-1] ==
'\t') || (str[l-1] ==
'\r')))
71 TQCString result(l + 1);
72 char *r = result.data();
74 for(
int i = 0; i < l;i++, str++)
111 result.truncate(r-result.data());
115 static TQCString stringToPrintable(
const TQCString& str){
116 TQCString result(str.length()*2);
117 char *r =
const_cast<TQCString&
>(result).data();
118 char *s =
const_cast<TQCString&
>(str).data();
120 if (!s)
return TQCString(
"");
125 *r++ =
'\\'; *r++ =
's';
135 *r++ =
'\\'; *r++ =
'n';
139 *r++ =
'\\'; *r++ =
't';
143 *r++ =
'\\'; *r++ =
'r';
147 *r++ =
'\\'; *r++ =
'\\';
158 *(r-1) =
'\\'; *r++ =
's';
162 result.truncate(r - result.data());
166 static TQCString decodeGroup(
const char*s,
int l)
169 char *r = result.data();
174 if ((*s ==
'[') && (l > 1))
182 if ((*s ==
']') && (l > 1))
193 result.truncate(r - result.data());
197 static TQCString encodeGroup(
const TQCString &str)
199 int l = str.length();
200 TQCString result(l*2+1);
201 char *r =
const_cast<TQCString&
>(result).data();
202 char *s =
const_cast<TQCString&
>(str).data();
205 if ((*s ==
'[') || (*s ==
']'))
210 result.truncate(r - result.data());
214 static TQCString encodeKey(
const char* key)
216 TQCString newKey(key);
218 newKey.replace(
'[',
"%5b");
219 newKey.replace(
']',
"%5d");
224 static TQCString decodeKey(
const char* key)
226 TQCString newKey(key);
228 newKey.replace(
"%5b",
"[");
229 newKey.replace(
"%5d",
"]");
234 class TDEConfigBackEnd::TDEConfigBackEndPrivate
237 TQDateTime localLastModified;
244 const char * _resType,
247 mfileName = _fileName;
249 useKDEGlobals = _useKDEGlobals;
250 if (mfileName.isEmpty()) {
251 mLocalFileName = TQString::null;
253 else if (!TQDir::isRelativePath(mfileName)) {
254 mLocalFileName = mfileName;
264 mGlobalFileName = TQString::null;
267 d->localLastModified = TQDateTime();
268 d->localLastSize = 0;
269 d->localLockFile = 0;
270 d->globalLockFile = 0;
277 if (d->globalLockFile)
278 return d->globalLockFile;
280 if (!mGlobalFileName.isEmpty())
282 d->globalLockFile =
new TDELockFile(mGlobalFileName+
".lock");
283 return d->globalLockFile;
288 if (d->localLockFile)
289 return d->localLockFile;
291 if (!mLocalFileName.isEmpty())
293 d->localLockFile =
new TDELockFile(mLocalFileName+
".lock");
294 return d->localLockFile;
301 const TQString &_fileName,
302 const char * _resType,
304 : pConfig(_config), bFileImmutable(false), mConfigState(
TDEConfigBase::NoAccess), mFileMode(-1)
306 d =
new TDEConfigBackEndPrivate;
323 mConfigState = TDEConfigBase::ReadOnly;
324 if (!mLocalFileName.isEmpty() && !pConfig->
isReadOnly())
326 if (checkAccess(mLocalFileName, W_OK))
328 mConfigState = TDEConfigBase::ReadWrite;
338 if (checkAccess(mLocalFileName, W_OK))
340 mConfigState = TDEConfigBase::ReadWrite;
343 TQFileInfo info(mLocalFileName);
344 d->localLastModified = info.lastModified();
345 d->localLastSize = info.size();
349 bFileImmutable =
false;
354 findAllResources(
"config", TQString::fromLatin1(
"kdeglobals"));
357 TQString etc_tderc = TQFile::decodeName( TQCString(getenv(
"WINDIR")) +
"\\tderc" );
359 TQString etc_tderc = TQString::fromLatin1(
"/etc/tderc");
362 if (checkAccess(etc_tderc, R_OK))
366 findAllResources(
"config", TQString::fromLatin1(
"system.kdeglobals"));
368 TQStringList::ConstIterator it;
370 for (it = tdercs.fromLast(); it != tdercs.end(); --it) {
372 TQFile aConfigFile( *it );
373 if (!aConfigFile.open( IO_ReadOnly ))
382 bool bReadFile = !mfileName.isEmpty();
385 TQString bootLanguage;
386 if (useKDEGlobals && localeString.isEmpty() && !TDEGlobal::_locale) {
388 bootLanguage = TDELocale::_initLanguage(pConfig);
392 bFileImmutable =
false;
394 if ( !TQDir::isRelativePath(mfileName) )
399 TQStringList::ConstIterator it;
401 for (it = list.fromLast(); it != list.end(); --it) {
403 TQFile aConfigFile( *it );
405 bool bIsLocal = (*it == mLocalFileName);
406 if (aConfigFile.open( IO_ReadOnly )) {
414 bFileImmutable =
true;
415 TQString currentLanguage;
416 if (!bootLanguage.isEmpty())
418 currentLanguage = TDELocale::_initLanguage(pConfig);
421 if (bootLanguage != currentLanguage)
429 mConfigState = TDEConfigBase::ReadOnly;
436 static sigjmp_buf mmap_jmpbuf;
437 struct sigaction mmap_old_sigact;
440 static void mmap_sigbus_handler(
int)
442 siglongjmp (mmap_jmpbuf, 1);
448 extern bool kde_kiosk_exception;
452 bool bGlobal,
bool bDefault)
466 TQCString aCurrentGroup(
"<default>");
468 unsigned int ll = localeString.length();
471 static volatile const char *map;
472 map = (
const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
475 if ( map != MAP_FAILED )
477 s = (
const char*) map;
478 eof = s + rFile.size();
481 struct sigaction act;
482 act.sa_handler = mmap_sigbus_handler;
483 sigemptyset( &act.sa_mask );
485 act.sa_flags = SA_ONESHOT;
487 act.sa_flags = SA_RESETHAND;
489 sigaction( SIGBUS, &act, &mmap_old_sigact );
491 if (sigsetjmp (mmap_jmpbuf, 1))
493 tqWarning(
"SIGBUS while reading %s", rFile.name().latin1());
494 munmap((
char* )map, rFile.size());
495 sigaction (SIGBUS, &mmap_old_sigact, 0);
504 data = rFile.readAll();
506 eof = s + data.size();
509 bool fileOptionImmutable =
false;
510 bool groupOptionImmutable =
false;
511 bool groupSkip =
false;
512 bool foundGettextDomain =
false;
513 TQCString gettextDomain;
520 while((s < eof) && isspace(*s) && (*s !=
'\n'))
524 if ((s < eof) && ((*s ==
'\n') || (*s ==
'#')))
527 while ((s < eof) && (*s !=
'\n'))
531 const char *startLine = s;
536 while ((s < eof) && (*s !=
'\n'))
540 if ((s+1 < eof) && (*(s+1) ==
']'))
549 while ((s < eof) && (*s !=
'\n')) s++;
550 if ((e >= eof) || (*e !=
']'))
552 fprintf(stderr,
"Invalid group header at %s:%d\n", rFile.name().latin1(), line);
557 if ((e-startLine == 3) &&
558 (startLine[1] ==
'$') &&
559 (startLine[2] ==
'i'))
561 if (!kde_kiosk_exception)
562 fileOptionImmutable =
true;
566 aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
570 if (aCurrentGroup ==
"KDE Desktop Entry")
571 aCurrentGroup =
"Desktop Entry";
573 groupOptionImmutable = fileOptionImmutable;
576 if ((e+2 < eof) && (*e++ ==
'[') && (*e++ ==
'$'))
578 if ((*e ==
'i') && !kde_kiosk_exception)
580 groupOptionImmutable =
true;
588 if (groupSkip && !bDefault)
592 pConfig->
putData(groupKey, entry,
false);
597 (*pWriteBackMap)[groupKey] = entry;
602 if (groupSkip && !bDefault)
606 bool optionImmutable = groupOptionImmutable;
607 bool optionDeleted =
false;
608 bool optionExpand =
false;
609 const char *endOfKey = 0, *locale = 0, *elocale = 0;
610 for (; (s < eof) && (*s !=
'\n'); s++)
626 if ((s >= eof) || (*s ==
'\n') || (*s ==
'=')) {
627 fprintf(stderr,
"Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
638 fprintf(stderr,
"Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
647 while (option < eoption)
650 if ((*option ==
'i') && !kde_kiosk_exception)
651 optionImmutable =
true;
652 else if (*option ==
'e')
654 else if (*option ==
'd')
656 optionDeleted =
true;
659 else if (*option ==
']')
665 fprintf(stderr,
"Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
669 for (endOfKey--; ; endOfKey--)
671 if (endOfKey < startLine)
673 fprintf(stderr,
"Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
676 if (!isspace(*endOfKey))
680 const char *st = ++s;
681 while ((s < eof) && (*s !=
'\n')) s++;
684 unsigned int cl =
static_cast<unsigned int>(elocale - locale);
685 if ((ll != cl) || memcmp(locale, localeString.data(), ll))
688 if ( cl != 1 || ll != 5 || *locale !=
'C' || memcmp(localeString.data(),
"en_US", 5)) {
701 TQCString key(startLine, endOfKey - startLine + 2);
702 TQCString val = printableToString(st, s - st);
705 if (TQString(key.data()) ==
"X-Ubuntu-Gettext-Domain") {
706 gettextDomain = val.data();
707 foundGettextDomain =
true;
710 KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
711 aEntryKey.
bLocal = (locale != 0);
720 aEntry.
bNLS = (locale != 0);
725 pWriteBackMap->insert(aEntryKey, aEntry);
730 pConfig->
putData(aEntryKey, aEntry,
false);
740 if (!pWriteBackMap) {
741 TQFile file(
"file.txt");
742 if (foundGettextDomain) {
746 TQString language = locale.
language();
747 translateKey(locale, aCurrentGroup, TQCString(
"Name"));
748 translateKey(locale, aCurrentGroup, TQCString(
"Comment"));
749 translateKey(locale, aCurrentGroup, TQCString(
"Language"));
750 translateKey(locale, aCurrentGroup, TQCString(
"Keywords"));
751 translateKey(locale, aCurrentGroup, TQCString(
"About"));
752 translateKey(locale, aCurrentGroup, TQCString(
"Description"));
753 translateKey(locale, aCurrentGroup, TQCString(
"GenericName"));
754 translateKey(locale, aCurrentGroup, TQCString(
"Query"));
755 translateKey(locale, aCurrentGroup, TQCString(
"ExtraNames"));
756 translateKey(locale, aCurrentGroup, TQCString(
"X-TDE-Submenu"));
761 if (fileOptionImmutable)
762 bFileImmutable =
true;
767 munmap((
char* )map, rFile.size());
769 sigaction (SIGBUS, &mmap_old_sigact, 0);
775 void TDEConfigINIBackEnd::translateKey(
TDELocale& locale, TQCString currentGroup, TQCString key) {
778 if (TQString(entry.mValue) !=
"") {
779 TQString orig = key +
"=" + entry.mValue;
780 TQString translate = locale.
translate(key +
"=" + entry.mValue);
781 if (TQString::compare(orig, translate) != 0) {
782 translate = translate.mid(key.length() + 1);
783 entry.mValue = translate.utf8();
786 pConfig->
putData(entryKey, entry,
false);
797 bool bEntriesLeft =
true;
802 if (!mfileName.isEmpty()) {
804 if ((resType!=
"config") && !TQDir::isRelativePath(mLocalFileName))
816 if (checkAccess(mLocalFileName, W_OK)) {
820 bool mergeLocalFile = bMerge;
834 TQFileInfo info(mLocalFileName);
835 if ((d->localLastSize == info.size()) &&
836 (d->localLastModified == info.lastModified()))
839 mergeLocalFile =
false;
844 d->localLastModified = TQDateTime();
845 d->localLastSize = 0;
849 bEntriesLeft =
writeConfigFile( mLocalFileName,
false, mergeLocalFile );
861 TQFileInfo info(mLocalFileName);
862 d->localLastModified = info.lastModified();
863 d->localLastSize = info.size();
872 if (bEntriesLeft && useKDEGlobals) {
875 if (checkAccess ( mGlobalFileName, W_OK )) {
892 static void writeEntries(FILE *pStream,
const KEntryMap& entryMap,
bool defaultGroup,
bool &firstEntry,
const TQCString &localeString)
895 TQCString currentGroup;
897 aIt != entryMap.end(); ++aIt)
902 if ((key.mGroup !=
"<default>") == defaultGroup)
906 if ((key.bDefault) || key.mKey.isEmpty())
909 const KEntry ¤tEntry = *aIt;
913 bool hasDefault = (aTestIt != entryMap.end());
916 const KEntryKey &defaultKey = aTestIt.key();
917 if ((!defaultKey.bDefault) ||
918 (defaultKey.mKey != key.mKey) ||
919 (defaultKey.mGroup != key.mGroup) ||
920 (defaultKey.bLocal != key.bLocal))
928 if ((currentEntry.mValue == (*aTestIt).mValue) &&
929 (currentEntry.
bDeleted == (*aTestIt).bDeleted))
939 if (!defaultGroup && (currentGroup !=
key.mGroup)) {
941 fprintf(pStream,
"\n");
942 currentGroup =
key.mGroup;
943 fprintf(pStream,
"[%s]\n", encodeGroup(currentGroup).data());
948 fputs(encodeKey(
key.mKey.data()), pStream);
950 if ( currentEntry.
bNLS )
953 fputs(localeString.data(), pStream);
959 fputs(
"[$d]\n", pStream);
975 fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
976 fputc(
'\n', pStream);
984 bool bEntriesLeft =
false;
985 bFileImmutable =
false;
988 if (mergeFile && mergeFile->open(IO_ReadOnly))
1000 for (KEntryMapIterator aIt = aMap.begin();
1001 aIt != aMap.end(); ++aIt)
1003 const KEntry ¤tEntry = *aIt;
1004 if(aIt.key().bDefault)
1006 aTempMap.replace(aIt.key(), currentEntry);
1010 if (mergeFile && !currentEntry.
bDirty)
1015 if (currentEntry.
bGlobal != bGlobal)
1018 bEntriesLeft =
true;
1024 KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
1025 if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
1028 aTempMap.insert(aIt.key(), currentEntry,
true);
1031 return bEntriesLeft;
1043 TQFile *mergeFile = (bMerge ?
new TQFile(
filename) : 0);
1044 bool bEntriesLeft =
getEntryMap(aTempMap, bGlobal, mergeFile);
1054 bool createNew =
true;
1056 KDE_struct_stat buf;
1057 if (KDE_stat(TQFile::encodeName(
filename), &buf) == 0)
1059 if (buf.st_uid == getuid())
1062 fileMode = buf.st_mode & 0777;
1079 if (pConfigFile->
status() != 0)
1082 return bEntriesLeft;
1085 if (!bGlobal && (fileMode == -1))
1086 fileMode = mFileMode;
1090 fchmod(pConfigFile->
handle(), fileMode);
1093 pStream = pConfigFile->
fstream();
1099 int fd = KDE_open( TQFile::encodeName(
filename), O_WRONLY | O_TRUNC );
1102 return bEntriesLeft;
1104 pStream = KDE_fdopen( fd,
"w");
1108 return bEntriesLeft;
1116 bool bEmptyFile = (ftell(pStream) == 0);
1117 if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
1120 ::unlink(TQFile::encodeName(
filename));
1121 pConfigFile->
abort();
1126 pConfigFile->
close();
1135 return bEntriesLeft;
1140 bool firstEntry =
true;
1143 ::writeEntries(pStream, aTempMap,
true, firstEntry, localeString);
1146 ::writeEntries(pStream, aTempMap,
false, firstEntry, localeString);
1149 void TDEConfigBackEnd::virtual_hook(
int,
void* )
1152 void TDEConfigINIBackEnd::virtual_hook(
int id,
void* data )
1153 { TDEConfigBackEnd::virtual_hook(
id, data ); }
1158 bool allWritable =
true;
1160 if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
1162 errorMsg = i18n(
"Will not save configuration.\n");
1163 allWritable =
false;
1164 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
1168 if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
1170 if ( errorMsg.isEmpty() )
1171 errorMsg = i18n(
"Will not save configuration.\n");
1172 errorMsg += i18n(
"Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
1173 allWritable =
false;
1176 if (warnUser && !allWritable)
1179 errorMsg += i18n(
"Please contact your system administrator.");
1182 if (!cmdToExec.isEmpty() && app)
1185 lprocess << cmdToExec <<
"--title" << app->
instanceName() <<
"--msgbox" << TQCString(errorMsg.local8Bit());
The KSaveFile class has been made to write out changes to an existing file atomically.
int status() const
Returns the status of the file based on errno.
FILE * fstream()
A FILE* stream open for writing to the file.
bool close()
Closes the file and makes the changes definitive.
void abort()
Aborts the write operation and removes any intermediate files This implies a close.
int handle() const
An integer file descriptor open for writing to the file.
Represents and parses a URL.
TQString directory(bool _strip_trailing_slash_from_result=true, bool _ignore_trailing_slash_in_path=true) const
Returns the directory of the path.
void setPath(const TQString &path)
Sets the decoded path of the URL.
Controls and provides information to all KDE applications.
TDELockFile::Ptr lockFile(bool bGlobal=false)
Returns a lock file object for the configuration file.
void setLocaleString(const TQCString &_localeString)
Set the locale string that defines the current language.
TDEConfigBackEnd(TDEConfigBase *_config, const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Constructs a configuration back end.
bool checkConfigFilesWritable(bool warnUser)
Check whether the config files are writable.
virtual ~TDEConfigBackEnd()
Destructs the configuration backend.
TDE_DEPRECATED TQString filename() const
void setFileWriteMode(int mode)
Set the file mode for newly created files.
void changeFileName(const TQString &_fileName, const char *_resType, bool _useKDEGlobals)
Changes the filenames associated with this back end.
KDE Configuration Management abstract base class.
virtual KEntry lookupData(const KEntryKey &_key) const =0
Looks up an entry in the config object's internal structure.
bool isReadOnly() const
Returns the read-only status of the config object.
virtual void putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup=true)=0
Inserts a (key/value) pair into the internal storage mechanism of the configuration object.
bool isDirty() const
Checks whether the config file has any dirty (modified) entries.
virtual KEntryMap internalEntryMap(const TQString &pGroup) const =0
Returns a map (tree) of the entries in the specified group.
void writeEntries(FILE *pStream, const KEntryMap &aTempMap)
Write the entries in aTempMap to the file stream.
virtual void sync(bool bMerge=true)
Writes configuration data to file(s).
bool parseConfigFiles()
Parses all INI-style configuration files for a config object.
bool getEntryMap(KEntryMap &map, bool bGlobal, TQFile *mergeFile)
Get the entry map.
void parseSingleConfigFile(TQFile &rFile, KEntryMap *pWriteBackMap=0L, bool bGlobal=false, bool bDefault=false)
Parses one configuration file.
bool writeConfigFile(TQString filename, bool bGlobal=false, bool bMerge=true)
Writes configuration file back.
static TDEStandardDirs * dirs()
Returns the application standard dirs object.
bool checkAccess(const TQString &pathname, int mode)
Check, if a file may be accessed in a given mode.
TQCString instanceName() const
Returns the name of the instance.
TDELocale provides support for country specific stuff like the national language.
TQString language() const
Returns the language used by this object.
TQString translate(const char *index) const
Translates the string into the corresponding string in the national language, if available.
The TDELockFile class provides NFS safe lockfiles.
@ LockForce
Automatically remove a lock when a lock is detected that is stale for more than staleTime() seconds.
bool isLocked() const
Returns whether the lock is held or not.
void unlock()
Release the lock.
LockResult lock(int options=0)
Attempt to acquire the lock.
Child process invocation, monitoring and control.
virtual bool start(RunMode runmode=NotifyOnExit, Communication comm=NoCommunication)
Starts the process.
@ Block
The application is suspended until the started process is finished.
TQString saveLocation(const char *type, const TQString &suffix=TQString::null, bool create=true) const
Finds a location to save files into for the given type in the user's home directory.
static TQString findExe(const TQString &appname, const TQString &pathstr=TQString::null, bool ignoreExecBit=false)
Finds the executable in the system path.
static bool makeDir(const TQString &dir, int mode=0755)
Recursively creates still-missing directories in the given path.
TQStringList findAllResources(const char *type, const TQString &filter=TQString::null, bool recursive=false, bool unique=false) const
Tries to find all resources with the specified type.
key structure holding both the actual key and the the group to which it belongs.
bool bDefault
Entry indicates if this is a default value.
bool bLocal
Entry is localised or not.
map/dict/list config node entry.
bool bImmutable
Entry can not be modified.
bool bNLS
Entry should be written with locale tag.
TQMap< KEntryKey, KEntry >::ConstIterator KEntryMapConstIterator
type for iterating over keys in a KEntryMap in sorted order.
bool bGlobal
Entry should be written to the global config file.
bool bExpand
Whether to apply dollar expansion or not.
bool bDirty
Must the entry be written back to disk?
TQMap< KEntryKey, KEntry > KEntryMap
type specifying a map of entries (key,value pairs).
bool bDeleted
Entry has been deleted.