33 #include <qdatetime.h>
36 #include <qfileinfo.h>
38 #include <qmetaobject.h>
45 return QString::fromLatin1(
"KConfigIni: In file %2, line %1: ")
46 .arg(line).arg(file.fileName());
62 return parseConfig(currentLocale, entryMap, options,
false);
69 ParseOptions options,
bool merging)
77 QByteArray currentGroup(
"<default>");
80 if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
85 bool fileOptionImmutable =
false;
86 bool groupOptionImmutable =
false;
87 bool groupSkip =
false;
92 QByteArray buffer = file.readAll();
94 unsigned int len = contents.
length();
95 unsigned int startOfLine = 0;
97 while (startOfLine < len) {
106 if (line.
at(0) ==
'[') {
107 groupOptionImmutable = fileOptionImmutable;
114 if (end == line.
length()) {
115 qWarning() <<
warningProlog(file, lineNo) <<
"Invalid group header.";
119 if (line.
at(end) ==
']')
123 if (end + 1 == line.
length() && start + 2 == end &&
124 line.
at(start) ==
'$' && line.
at(start + 1) ==
'i')
126 if (newGroup.isEmpty())
127 fileOptionImmutable = !kde_kiosk_exception;
132 if (!newGroup.isEmpty())
138 }
while ((start = end + 2) <= line.
length() && line.
at(end + 1) ==
'[');
139 currentGroup = newGroup;
143 if (groupSkip && !bDefault)
146 if (groupOptionImmutable)
149 immutableGroups.append(currentGroup);
151 if (groupSkip && !bDefault)
166 qWarning() <<
warningProlog(file, lineNo) <<
"Invalid entry (empty key)";
170 KEntryMap::EntryOptions entryOptions=0;
171 if (groupOptionImmutable)
177 int end = aKey.
indexOf(
']', start);
180 <<
"Invalid entry (missing ']')";
182 }
else if (end > start + 1 && aKey.
at(start + 1) ==
'$') {
185 switch (aKey.
at(i)) {
187 if (!kde_kiosk_exception)
191 if (allowExecutableValues)
196 aKey = aKey.
left(start);
208 <<
"Invalid entry (second locale!?)";
212 locale = aKey.
mid(start + 1,end - start - 1);
217 qWarning() <<
warningProlog(file, lineNo) <<
"Invalid entry (missing '=')";
222 if (locale != currentLocale) {
224 if (locale.
at(0) !=
'C' || currentLocale !=
"en_US") {
243 if (entryOptions & KEntryMap::EntryRawKey) {
258 foreach(
const QByteArray&
group, immutableGroups) {
266 const KEntryMap& map,
bool defaultGroup,
bool &firstEntry)
268 QByteArray currentGroup;
269 bool groupIsImmutable =
false;
270 const KEntryMapConstIterator end = map.constEnd();
271 for (KEntryMapConstIterator it = map.constBegin(); it != end; ++it) {
275 if ((key.
mGroup !=
"<default>") == defaultGroup)
279 if (key.
mKey.isNull()) {
280 groupIsImmutable = it->bImmutable;
284 const KEntry& currentEntry = *it;
285 if (!defaultGroup && currentGroup != key.
mGroup) {
288 currentGroup = key.
mGroup;
289 for (
int start = 0, end;; start = end + 1) {
291 end = currentGroup.indexOf(
'\x1d', start);
293 int cgl = currentGroup.length();
294 if (currentGroup.at(start) ==
'$' && cgl - start <= 10) {
295 for (
int i = start + 1; i < cgl; i++) {
296 char c = currentGroup.at(i);
297 if (c < 'a' || c >
'z')
306 if (groupIsImmutable) {
307 file.write(
"[$i]", 4);
322 file.write(key.
mKey);
325 if (key.
bLocal && locale !=
"C") {
333 file.write(
"[$di]", 5);
335 file.write(
"[$d]", 4);
354 bool firstEntry =
true;
382 const KEntryMapIterator end = entryMap.end();
383 for (KEntryMapIterator it=entryMap.begin(); it != end; ++it) {
384 if (!it.key().mKey.isEmpty() && !it->bDirty)
390 if (it->bGlobal == bGlobal) {
392 writeMap.remove(key);
393 }
else if (!it->bDeleted) {
398 if (!entryMap.contains(defaultKey)) {
399 writeMap.remove(key);
414 QFile::Permissions fileMode = QFile::ReadUser | QFile::WriteUser;
415 bool createNew =
true;
420 if (fi.ownerId() == ::getuid())
423 fileMode = fi.permissions();
439 file.setPermissions(fileMode);
441 file.setTextModeEnabled(
true);
451 if (!file.size() && (fileMode == (QFile::ReadUser | QFile::WriteUser))) {
469 int fd = KDE_open(QFile::encodeName(
filePath()), O_WRONLY | O_TRUNC);
473 FILE *fp = KDE_fdopen(fd,
"w");
479 if (!f.open(fp, QIODevice::WriteOnly)) {
489 if (!f.open( QIODevice::WriteOnly | QIODevice::Truncate )) {
492 f.setTextModeEnabled(
true);
509 if (!file.exists()) {
510 QFileInfo dir(file.absolutePath());
511 while (!dir.exists()) {
512 QString parent = dir.absolutePath();
513 if (parent == dir.filePath()) {
519 return dir.isDir() && dir.isWritable();
528 return i18n(
"Configuration file \"%1\" not writable.\n",
filePath());
539 dir.mkpath(QFileInfo(file).absolutePath());
547 Q_ASSERT(QDir::isAbsolutePath(file));
549 const QFileInfo info(file);
595 return lockFile && lockFile->
isLocked();
600 static const char nibbleLookup[] = {
601 '0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
602 '8',
'9',
'a',
'b',
'c',
'd',
'e',
'f'
605 if (aString.isEmpty())
607 const int l = aString.length();
610 result.resize(l * 4);
611 register const char *s = aString.constData();
613 char *data = result.data();
627 if (((
unsigned char)s[i]) < 32)
663 *data++ = nibbleLookup[((
unsigned char)s[i]) >> 4];
664 *data++ = nibbleLookup[((
unsigned char)s[i]) & 0x0f];
669 result.resize(data - start);
673 result.replace(result.length() - 1, 1,
"\\s");
682 unsigned char ret = 0;
683 for (
int i = 0; i < 2; i++) {
685 quint8 c = quint8(str[i]);
687 if (c >=
'0' && c <=
'9') {
689 }
else if (c >=
'a' && c <=
'f') {
690 ret |= c -
'a' + 0x0a;
691 }
else if (c >=
'A' && c <=
'F') {
692 ret |= c -
'A' + 0x0a;
694 QByteArray e(str, 2);
696 qWarning() <<
warningProlog(file, line) <<
"Invalid hex character " << c
697 <<
" in \\x<nn>-type escape sequence \"" << e.constData() <<
"\".";
709 int l = aString->
length();
710 char *r = aString->
data();
713 for(
int i = 0; i < l; i++, r++) {
752 << QString::fromLatin1(
"Invalid escape sequence \"\\%1\".").arg(str[i]);