• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

kconfigini.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE libraries
00003    Copyright (c) 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
00004    Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00005    Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org)
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "kconfigini_p.h"
00024 
00025 #include <config.h>
00026 
00027 #include <fcntl.h>
00028 
00029 #include "kconfig.h"
00030 #include "kconfigbackend.h"
00031 #include "bufferfragment_p.h"
00032 #include "kconfigdata.h"
00033 #include <ksavefile.h>
00034 #include <kde_file.h>
00035 #include "kstandarddirs.h"
00036 
00037 #include <qdatetime.h>
00038 #include <qdir.h>
00039 #include <qfile.h>
00040 #include <qfileinfo.h>
00041 #include <qdebug.h>
00042 #include <qmetaobject.h>
00043 #include <qregexp.h>
00044 
00045 extern bool kde_kiosk_exception;
00046 
00047 QString KConfigIniBackend::warningProlog(const QFile &file, int line)
00048 {
00049     return QString("KConfigIni: In file %2, line %1: ")
00050             .arg(line).arg(file.fileName());
00051 }
00052 
00053 KConfigIniBackend::KConfigIniBackend()
00054  : KConfigBackend()
00055 {
00056 }
00057 
00058 KConfigIniBackend::~KConfigIniBackend()
00059 {
00060 }
00061 
00062 KConfigBackend::ParseInfo
00063         KConfigIniBackend::parseConfig(const QByteArray& currentLocale, KEntryMap& entryMap,
00064                                        ParseOptions options)
00065 {
00066     return parseConfig(currentLocale, entryMap, options, false);
00067 }
00068 
00069 KConfigBackend::ParseInfo
00070 KConfigIniBackend::parseConfig(const QByteArray& currentLocale, KEntryMap& entryMap,
00071                                ParseOptions options, bool merging)
00072 {
00073     if (filePath().isEmpty() || !QFile::exists(filePath()))
00074         return ParseOk;
00075 
00076     bool bDefault = options&ParseDefaults;
00077     bool allowExecutableValues = options&ParseExpansions;
00078 
00079     QByteArray currentGroup("<default>");
00080 
00081     QFile file(filePath());
00082     if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
00083         return ParseOpenError;
00084 
00085     QList<QByteArray> immutableGroups;
00086 
00087     bool fileOptionImmutable = false;
00088     bool groupOptionImmutable = false;
00089     bool groupSkip = false;
00090 
00091     int lineNo = 0;
00092     // on systems using \r\n as end of line, \r will be taken care of by 
00093     // trim() below
00094     QByteArray buffer = file.readAll();
00095     BufferFragment contents(buffer.data(), buffer.size());
00096     unsigned int len = contents.length();
00097     unsigned int startOfLine = 0;
00098 
00099     while (startOfLine < len) {
00100         BufferFragment line = contents.split('\n', &startOfLine);
00101         line.trim();
00102         lineNo++;
00103 
00104         // skip empty lines and lines beginning with '#'
00105         if (line.isEmpty() || line.at(0) == '#')
00106             continue;
00107 
00108         if (line.at(0) == '[') { // found a group
00109             groupOptionImmutable = fileOptionImmutable;
00110 
00111             QByteArray newGroup;
00112             int start = 1, end;
00113             do {
00114                 end = start;
00115                 for (;;) {
00116                     if (end == line.length()) {
00117                         qWarning() << warningProlog(file, lineNo) << "Invalid group header.";
00118                         // XXX maybe reset the current group here?
00119                         goto next_line;
00120                     }
00121                     if (line.at(end) == ']')
00122                         break;
00123                     end++;
00124                 }
00125                 if (end + 1 == line.length() && start + 2 == end &&
00126                     line.at(start) == '$' && line.at(start + 1) == 'i')
00127                 {
00128                     if (newGroup.isEmpty())
00129                         fileOptionImmutable = !kde_kiosk_exception;
00130                     else
00131                         groupOptionImmutable = !kde_kiosk_exception;
00132                 }
00133                 else {
00134                     if (!newGroup.isEmpty())
00135                         newGroup += '\x1d';
00136                     BufferFragment namePart=line.mid(start, end - start);
00137                     printableToString(&namePart, file, lineNo);
00138                     newGroup += namePart.toByteArray();
00139                 }
00140             } while ((start = end + 2) <= line.length() && line.at(end + 1) == '[');
00141             currentGroup = newGroup;
00142 
00143             groupSkip = entryMap.getEntryOption(currentGroup, 0, 0, KEntryMap::EntryImmutable);
00144 
00145             if (groupSkip && !bDefault)
00146                 continue;
00147 
00148             if (groupOptionImmutable)
00149                 // Do not make the groups immutable until the entries from
00150                 // this file have been added.
00151                 immutableGroups.append(currentGroup);
00152         } else {
00153             if (groupSkip && !bDefault)
00154                 continue; // skip entry
00155 
00156             BufferFragment aKey;
00157             int eqpos = line.indexOf('=');
00158             if (eqpos < 0) {
00159                 aKey = line;
00160                 line.clear();
00161             } else {
00162                 BufferFragment temp = line.left(eqpos);
00163                 temp.trim();
00164                 aKey = temp;
00165                 line.truncateLeft(eqpos + 1);
00166             }
00167             if (aKey.isEmpty()) {
00168                 qWarning() << warningProlog(file, lineNo) << "Invalid entry (empty key)";
00169                 continue;
00170             }
00171 
00172             KEntryMap::EntryOptions entryOptions=0;
00173             if (groupOptionImmutable)
00174                 entryOptions |= KEntryMap::EntryImmutable;
00175 
00176             BufferFragment locale;
00177             int start;
00178             while ((start = aKey.lastIndexOf('[')) >= 0) {
00179                 int end = aKey.indexOf(']', start);
00180                 if (end < 0) {
00181                     qWarning() << warningProlog(file, lineNo)
00182                             << "Invalid entry (missing ']')";
00183                     goto next_line;
00184                 } else if (end > start + 1 && aKey.at(start + 1) == '$') { // found option(s)
00185                     int i = start + 2;
00186                     while (i < end) {
00187                         switch (aKey.at(i)) {
00188                             case 'i':
00189                                 if (!kde_kiosk_exception)
00190                                     entryOptions |= KEntryMap::EntryImmutable;
00191                                 break;
00192                             case 'e':
00193                                 if (allowExecutableValues)
00194                                     entryOptions |= KEntryMap::EntryExpansion;
00195                                 break;
00196                             case 'd':
00197                                 entryOptions |= KEntryMap::EntryDeleted;
00198                                 aKey = aKey.left(start);
00199                                 printableToString(&aKey, file, lineNo);
00200                                 entryMap.setEntry(currentGroup, aKey.toByteArray(), QByteArray(), entryOptions);
00201                                 goto next_line;
00202                             default:
00203                                 break;
00204                         }
00205                         i++;
00206                     }
00207                 } else { // found a locale
00208                     if (!locale.isNull()) {
00209                         qWarning() << warningProlog(file, lineNo)
00210                                 << "Invalid entry (second locale!?)";
00211                         goto next_line;
00212                     }
00213 
00214                     locale = aKey.mid(start + 1,end - start - 1);
00215                 }
00216                 aKey.truncate(start);
00217             }
00218             if (eqpos < 0) { // Do this here after [$d] was checked
00219                 qWarning() << warningProlog(file, lineNo) << "Invalid entry (missing '=')";
00220                 continue;
00221             }
00222             printableToString(&aKey, file, lineNo);
00223             if (!locale.isEmpty()) {
00224                 if (locale != currentLocale) {
00225                     // backward compatibility. C == en_US
00226                     if (locale.at(0) != 'C' || currentLocale != "en_US") {
00227                         if (merging)
00228                             entryOptions |= KEntryMap::EntryRawKey;
00229                         else
00230                             goto next_line; // skip this entry if we're not merging
00231                     }
00232                 }
00233             } 
00234 
00235             if (!(entryOptions & KEntryMap::EntryRawKey)) 
00236                 printableToString(&aKey, file, lineNo);
00237 
00238             if (options&ParseGlobal)
00239                 entryOptions |= KEntryMap::EntryGlobal;
00240             if (bDefault)
00241                 entryOptions |= KEntryMap::EntryDefault;
00242             if (!locale.isNull())
00243                 entryOptions |= KEntryMap::EntryLocalized;
00244             printableToString(&line, file, lineNo);
00245             if (entryOptions & KEntryMap::EntryRawKey) {
00246                 QByteArray rawKey;
00247                 rawKey.reserve(aKey.length() + locale.length() + 2);
00248                 rawKey.append(aKey.toVolatileByteArray());
00249                 rawKey.append('[').append(locale.toVolatileByteArray()).append(']');
00250                 entryMap.setEntry(currentGroup, rawKey, line.toByteArray(), entryOptions);
00251             } else {
00252                 entryMap.setEntry(currentGroup, aKey.toByteArray(), line.toByteArray(), entryOptions);
00253             }
00254         }
00255 next_line:
00256         continue;
00257     }
00258 
00259     // now make sure immutable groups are marked immutable
00260     foreach(const QByteArray& group, immutableGroups) {
00261         entryMap.setEntry(group, QByteArray(), QByteArray(), KEntryMap::EntryImmutable);
00262     }
00263 
00264     return fileOptionImmutable ? ParseImmutable : ParseOk;
00265 }
00266 
00267 void KConfigIniBackend::writeEntries(const QByteArray& locale, QFile& file,
00268                                      const KEntryMap& map, bool defaultGroup, bool &firstEntry)
00269 {
00270     QByteArray currentGroup;
00271     bool groupIsImmutable = false;
00272     const KEntryMapConstIterator end = map.constEnd();
00273     for (KEntryMapConstIterator it = map.constBegin(); it != end; ++it) {
00274         const KEntryKey& key = it.key();
00275 
00276         // Either process the default group or all others
00277         if ((key.mGroup != "<default>") == defaultGroup)
00278             continue; // skip
00279 
00280         // the only thing we care about groups is, is it immutable?
00281         if (key.mKey.isNull()) {
00282             groupIsImmutable = it->bImmutable;
00283             continue; // skip
00284         }
00285 
00286         const KEntry& currentEntry = *it;
00287         if (!defaultGroup && currentGroup != key.mGroup) {
00288             if (!firstEntry)
00289                 file.putChar('\n');
00290             currentGroup = key.mGroup;
00291             for (int start = 0, end;; start = end + 1) {
00292                 file.putChar('[');
00293                 end = currentGroup.indexOf('\x1d', start);
00294                 if (end < 0) {
00295                     int cgl = currentGroup.length();
00296                     if (currentGroup.at(start) == '$' && cgl - start <= 10) {
00297                         for (int i = start + 1; i < cgl; i++) {
00298                             char c = currentGroup.at(i);
00299                             if (c < 'a' || c > 'z')
00300                                 goto nope;
00301                         }
00302                         file.write("\\x24");
00303                         start++;
00304                     }
00305                   nope:
00306                     file.write(stringToPrintable(currentGroup.mid(start), GroupString));
00307                     file.putChar(']');
00308                     if (groupIsImmutable) {
00309                         file.write("[$i]", 4);
00310                     }
00311                     file.putChar('\n');
00312                     break;
00313                 } else {
00314                     file.write(stringToPrintable(currentGroup.mid(start, end - start), GroupString));
00315                     file.putChar(']');
00316                 }
00317             }
00318         }
00319 
00320         firstEntry = false;
00321         // it is data for a group
00322 
00323         if (key.bRaw) // unprocessed key with attached locale from merge
00324             file.write(key.mKey);
00325         else {
00326             file.write(stringToPrintable(key.mKey, KeyString)); // Key
00327             if (key.bLocal && locale != "C") { // 'C' locale == untranslated
00328                 file.putChar('[');
00329                 file.write(locale); // locale tag
00330                 file.putChar(']');
00331             }
00332         }
00333         if (currentEntry.bDeleted) {
00334             if (currentEntry.bImmutable)
00335                 file.write("[$di]", 5); // Deleted + immutable
00336             else
00337                 file.write("[$d]", 4); // Deleted
00338         } else {
00339             if (currentEntry.bImmutable || currentEntry.bExpand) {
00340                 file.write("[$", 2);
00341                 if (currentEntry.bImmutable)
00342                     file.putChar('i');
00343                 if (currentEntry.bExpand)
00344                     file.putChar('e');
00345                 file.putChar(']');
00346             }
00347             file.putChar('=');
00348             file.write(stringToPrintable(currentEntry.mValue, ValueString));
00349         }
00350         file.putChar('\n');
00351     }
00352 }
00353 
00354 void KConfigIniBackend::writeEntries(const QByteArray& locale, QFile& file, const KEntryMap& map)
00355 {
00356     bool firstEntry = true;
00357 
00358     // write default group
00359     writeEntries(locale, file, map, true, firstEntry);
00360 
00361     // write all other groups
00362     writeEntries(locale, file, map, false, firstEntry);
00363 }
00364 
00365 bool KConfigIniBackend::writeConfig(const QByteArray& locale, KEntryMap& entryMap,
00366                                     WriteOptions options, const KComponentData &data)
00367 {
00368     Q_ASSERT(!filePath().isEmpty());
00369 
00370     KEntryMap writeMap;
00371     bool bGlobal = options & WriteGlobal;
00372 
00373     {
00374         ParseOptions opts = ParseExpansions;
00375         if (bGlobal)
00376             opts |= ParseGlobal;
00377         ParseInfo info = parseConfig(locale, writeMap, opts, true);
00378         if (info != ParseOk) // either there was an error or the file became immutable
00379             return false;
00380     }
00381     const KEntryMapIterator end = entryMap.end();
00382     for (KEntryMapIterator it=entryMap.begin(); it != end; ++it) {
00383         if (!it.key().mKey.isEmpty() && !it->bDirty) // not dirty, doesn't overwrite entry in writeMap. skips default entries, too.
00384             continue;
00385 
00386         const KEntryKey& key = it.key();
00387 
00388         // only write entries that have the same "globality" as the file
00389         if (it->bGlobal == bGlobal) {
00390             if (!it->bDeleted) {
00391                 writeMap[key] = *it;
00392             } else {
00393                 KEntryKey defaultKey = key;
00394                 defaultKey.bDefault = true;
00395                 if (!entryMap.contains(defaultKey))
00396                     writeMap.remove(key); // remove the deleted entry if there is no default
00397                 else
00398                     writeMap[key] = *it; // otherwise write an explicitly deleted entry
00399             }
00400             it->bDirty = false;
00401         }
00402     }
00403 
00404     // now writeMap should contain only entries to be written
00405     // so write it out to disk
00406 
00407     // check if file exists
00408     QFile::Permissions fileMode = QFile::ReadUser | QFile::WriteUser;
00409     bool createNew = true;
00410 
00411     QFileInfo fi(filePath());
00412     if (fi.exists())
00413     {
00414         if (fi.ownerId() == ::getuid())
00415         {
00416             // Preserve file mode if file exists and is owned by user.
00417             fileMode = fi.permissions();
00418         }
00419         else
00420         {
00421             // File is not owned by user:
00422             // Don't create new file but write to existing file instead.
00423             createNew = false;
00424         }
00425     }
00426 
00427     if (createNew) {
00428         KSaveFile file( filePath(), data );
00429         if (!file.open()) {
00430             return false;
00431         }
00432 
00433         file.setPermissions(fileMode);
00434 
00435         file.setTextModeEnabled(true); // to get eol translation
00436         writeEntries(locale, file, writeMap);
00437 
00438         if (!file.flush()) {
00439             // Couldn't write. Disk full?
00440             kWarning() << "Couldn't write" << filePath() << ". Disk full?";
00441             file.abort();
00442             return false;
00443         }
00444 
00445         if (!file.size() && (fileMode == (QFile::ReadUser | QFile::WriteUser))) {
00446             // File is empty and doesn't have special permissions: delete it.
00447             file.abort();
00448 
00449             if (fi.exists()) {
00450                 // also remove the old file in case it existed. this can happen
00451                 // when we delete all the entries in an existing config file.
00452                 // if we don't do this, then deletions and revertToDefault's
00453                 // will mysteriously fail
00454                 QFile::remove(filePath());
00455             }
00456         } else {
00457             // Normal case: Close the file
00458             return file.finalize();
00459         }
00460     } else {
00461         // Open existing file. *DON'T* create it if it suddenly does not exist!
00462 #ifdef Q_OS_UNIX
00463         int fd = KDE_open(QFile::encodeName(filePath()), O_WRONLY | O_TRUNC);
00464         if (fd < 0) {
00465             return false;
00466         }
00467         FILE *fp = KDE_fdopen(fd, "w");
00468         if (!fp) {
00469             close(fd);
00470             return false;
00471         }
00472         QFile f;
00473         if (!f.open(fp, QIODevice::WriteOnly)) {
00474             fclose(fp);
00475             return false;
00476         }
00477         writeEntries(locale, f, writeMap);
00478         f.close();
00479         fclose(fp);
00480 #else
00481         QFile f( filePath() );
00482         // XXX This is broken - it DOES create the file if it is suddenly gone.
00483         if (!f.open( QIODevice::WriteOnly | QIODevice::Truncate )) {
00484             return false;
00485         }
00486         f.setTextModeEnabled(true);
00487         writeEntries(locale, f, writeMap);
00488 #endif
00489     }
00490     return true;
00491 }
00492 
00493 bool KConfigIniBackend::isWritable() const
00494 {
00495     if (!filePath().isEmpty()) {
00496         if (KStandardDirs::checkAccess(filePath(), W_OK)) {
00497             return true;
00498         }
00499         // The check might have failed because any of the containing dirs
00500         // did not exist. If the file does not exist, check if the deepest
00501         // existing dir is writable.
00502         if (!QFileInfo(filePath()).exists()) {
00503             QDir dir = QFileInfo(filePath()).absolutePath();
00504             while (!dir.exists()) {
00505                 if (!dir.cdUp()) {
00506                     return false;
00507                 }
00508             }
00509             return QFileInfo(dir.absolutePath()).isWritable();
00510         }
00511     }
00512 
00513     return false;
00514 }
00515 
00516 QString KConfigIniBackend::nonWritableErrorMessage() const
00517 {
00518     return i18n("Configuration file \"%1\" not writable.\n", filePath());
00519 }
00520 
00521 void KConfigIniBackend::createEnclosing()
00522 {
00523     const QString file = filePath();
00524     if (file.isEmpty())
00525         return; // nothing to do
00526 
00527     // Create the containing dir, maybe it wasn't there
00528     QDir dir;
00529     dir.mkpath(QFileInfo(file).absolutePath());
00530 }
00531 
00532 void KConfigIniBackend::setFilePath(const QString& file)
00533 {
00534     if (file.isEmpty())
00535         return;
00536 
00537     Q_ASSERT(QDir::isAbsolutePath(file));
00538 
00539     if (QFile::exists(file)) {
00540         const QFileInfo info(file);
00541         setLocalFilePath(info.canonicalFilePath());
00542         setLastModified(info.lastModified());
00543         setSize(info.size());
00544     } else {
00545         setLocalFilePath(file);
00546         setSize(0);
00547         QDateTime dummy;
00548         dummy.setTime_t(0);
00549         setLastModified(dummy);
00550     }
00551 }
00552 
00553 KConfigBase::AccessMode KConfigIniBackend::accessMode() const
00554 {
00555     if (filePath().isEmpty())
00556         return KConfigBase::NoAccess;
00557 
00558     if (isWritable())
00559         return KConfigBase::ReadWrite;
00560 
00561     return KConfigBase::ReadOnly;
00562 }
00563 
00564 bool KConfigIniBackend::lock(const KComponentData& componentData)
00565 {
00566     Q_ASSERT(!filePath().isEmpty());
00567 
00568     if (!lockFile) {
00569         lockFile = new KLockFile(filePath() + QLatin1String(".lock"), componentData);
00570     }
00571 
00572     if (lockFile->lock() == KLockFile::LockStale) // attempt to break the lock
00573         lockFile->lock(KLockFile::ForceFlag);
00574     return lockFile->isLocked();
00575 }
00576 
00577 void KConfigIniBackend::unlock()
00578 {
00579     lockFile->unlock();
00580     lockFile.clear();
00581 }
00582 
00583 bool KConfigIniBackend::isLocked() const
00584 {
00585     return lockFile && lockFile->isLocked();
00586 }
00587 
00588 QByteArray KConfigIniBackend::stringToPrintable(const QByteArray& aString, StringType type)
00589 {
00590     static const char nibbleLookup[] = {
00591         '0', '1', '2', '3', '4', '5', '6', '7',
00592         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
00593     };
00594 
00595     if (aString.isEmpty())
00596         return aString;
00597     const int l = aString.length();
00598 
00599     QByteArray result; // Guesstimated that it's good to avoid data() initialization for a length of l*4
00600     result.resize(l * 4); // Maximum 4x as long as source string due to \x<ab> escape sequences
00601     register const char *s = aString.constData();
00602     int i = 0;
00603     char *data = result.data();
00604     char *start = data;
00605 
00606     // Protect leading space
00607     if (s[0] == ' ' && type != GroupString) {
00608         *data++ = '\\';
00609         *data++ = 's';
00610         i++;
00611     }
00612 
00613     for (; i < l; ++i/*, r++*/) {
00614         switch (s[i]) {
00615             default:
00616             // The \n, \t, \r cases (all < 32) are handled below; we can ignore them here
00617                 if (((unsigned char)s[i]) < 32)
00618                     goto doEscape;
00619                 *data++ = s[i];
00620                 break;
00621             case '\n':
00622                 *data++ = '\\';
00623                 *data++ = 'n';
00624                 break;
00625             case '\t':
00626                 *data++ = '\\';
00627                 *data++ = 't';
00628                 break;
00629             case '\r':
00630                 *data++ = '\\';
00631                 *data++ = 'r';
00632                 break;
00633             case '\\':
00634                 *data++ = '\\';
00635                 *data++ = '\\';
00636                 break;
00637             case '=':
00638                 if (type != KeyString) {
00639                     *data++ = s[i];
00640                     break;
00641                 }
00642                 goto doEscape;
00643             case '[':
00644             case ']':
00645             // Above chars are OK to put in *value* strings as plaintext
00646                 if (type == ValueString) {
00647                     *data++ = s[i];
00648                     break;
00649                 }
00650         doEscape:
00651                 *data++ = '\\';
00652                 *data++ = 'x';
00653                 *data++ = nibbleLookup[((unsigned char)s[i]) >> 4];
00654                 *data++ = nibbleLookup[((unsigned char)s[i]) & 0x0f];
00655                 break;
00656         }
00657     }
00658     *data = 0;
00659     result.resize(data - start);
00660 
00661     // Protect trailing space
00662     if (result.endsWith(' ') && type != GroupString) {
00663         result.replace(result.length() - 1, 1, "\\s");
00664     }
00665     result.squeeze();
00666 
00667     return result;
00668 }
00669 
00670 char KConfigIniBackend::charFromHex(const char *str, const QFile& file, int line)
00671 {
00672     unsigned char ret = 0;
00673     for (int i = 0; i < 2; i++) {
00674         ret <<= 4;
00675         quint8 c = quint8(str[i]);
00676 
00677         if (c >= '0' && c <= '9') {
00678             ret |= c - '0';
00679         } else if (c >= 'a' && c <= 'f') {
00680             ret |= c - 'a' + 0x0a;
00681         } else if (c >= 'A' && c <= 'F') {
00682             ret |= c - 'A' + 0x0a;
00683         } else {
00684             QByteArray e(str, 2);
00685             e.prepend("\\x");
00686             qWarning() << warningProlog(file, line) << "Invalid hex character " << c
00687                     << " in \\x<nn>-type escape sequence \"" << e.constData() << "\".";
00688             return 'x';
00689         }
00690     }
00691     return char(ret);
00692 }
00693 
00694 void KConfigIniBackend::printableToString(BufferFragment* aString, const QFile& file, int line)
00695 {
00696     if (aString->isEmpty() || aString->indexOf('\\')==-1) 
00697         return;
00698     aString->trim();
00699     int l = aString->length();
00700     char *r = aString->data();
00701     char *str=r;
00702 
00703     for(int i = 0; i < l; i++, r++) {
00704         if (str[i]!= '\\') {
00705             *r=str[i];
00706         } else {
00707             // Probable escape sequence
00708             i++;
00709             if (i >= l) { // Line ends after backslash - stop.
00710                 *r = '\\';
00711                 break;
00712             }
00713 
00714             switch(str[i]) {
00715                 case 's':
00716                     *r = ' ';
00717                     break;
00718                 case 't':
00719                     *r = '\t';
00720                     break;
00721                 case 'n':
00722                     *r = '\n';
00723                     break;
00724                 case 'r':
00725                     *r = '\r';
00726                     break;
00727                 case '\\':
00728                     *r = '\\';
00729                     break;
00730                 case 'x':
00731                     if (i + 2 < l) {
00732                         *r = charFromHex(str + i + 1, file, line);
00733                         i += 2;
00734                     } else {
00735                         *r = 'x';
00736                         i = l - 1;
00737                     }
00738                     break;
00739                 default:
00740                     *r = '\\';
00741                     qWarning() << warningProlog(file, line)
00742                             << QString("Invalid escape sequence \"\\%1\".").arg(str[i]);
00743             }
00744         }
00745     }
00746     aString->truncate(r - aString->constData());
00747 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal