diff options
| author | Jenkins CI <null@kde.org> | 2013-12-18 00:45:18 +0000 |
|---|---|---|
| committer | Jenkins CI <null@kde.org> | 2013-12-18 00:45:18 +0000 |
| commit | 867e7a50e6396338ab4fe9aa22ad141e4cd344d2 (patch) | |
| tree | 1d6f8d6c912fa04dc268b5580bcfe696fa538743 /tier1/kconfig/src/kconf_update | |
| parent | c38b88497a833e482e6892b72c8f52adec6de857 (diff) | |
| download | kconfig-867e7a50e6396338ab4fe9aa22ad141e4cd344d2.tar.gz kconfig-867e7a50e6396338ab4fe9aa22ad141e4cd344d2.tar.bz2 | |
Move kconfig code to the root directory.
Diffstat (limited to 'tier1/kconfig/src/kconf_update')
| -rw-r--r-- | tier1/kconfig/src/kconf_update/CMakeLists.txt | 17 | ||||
| -rw-r--r-- | tier1/kconfig/src/kconf_update/Mainpage.dox | 31 | ||||
| -rw-r--r-- | tier1/kconfig/src/kconf_update/README.kconf_update | 248 | ||||
| -rw-r--r-- | tier1/kconfig/src/kconf_update/config-kconf.h.cmake | 4 | ||||
| -rw-r--r-- | tier1/kconfig/src/kconf_update/kconf_update.cpp | 967 | ||||
| -rw-r--r-- | tier1/kconfig/src/kconf_update/kconfigutils.cpp | 127 | ||||
| -rw-r--r-- | tier1/kconfig/src/kconf_update/kconfigutils.h | 43 |
7 files changed, 0 insertions, 1437 deletions
diff --git a/tier1/kconfig/src/kconf_update/CMakeLists.txt b/tier1/kconfig/src/kconf_update/CMakeLists.txt deleted file mode 100644 index e4e37ba9..00000000 --- a/tier1/kconfig/src/kconf_update/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -find_package(Qt5Core 5.2.0 REQUIRED NO_MODULE) - -remove_definitions(-DQT_NO_CAST_FROM_ASCII) - -configure_file(config-kconf.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kconf.h ) - -########### next target ############### - -set(kconf_update_SRCS - kconf_update.cpp - kconfigutils.cpp - ) - -add_executable(kconf_update ${kconf_update_SRCS}) -target_link_libraries(kconf_update Qt5::Core KF5::ConfigCore) - -install(TARGETS kconf_update DESTINATION ${LIBEXEC_INSTALL_DIR}) diff --git a/tier1/kconfig/src/kconf_update/Mainpage.dox b/tier1/kconfig/src/kconf_update/Mainpage.dox deleted file mode 100644 index 77d486ce..00000000 --- a/tier1/kconfig/src/kconf_update/Mainpage.dox +++ /dev/null @@ -1,31 +0,0 @@ -/** @mainpage ./kconf_update - -kconf_update is a tool designed to update config files. Over time applications -sometimes need to rearrange the way configuration options are stored. Since -such an update shouldn't influence the configuration options that the user -has selected, the application must take care that the options stored in the -old way will still be honored. - -What used to happen is that the application looks up both the old and the -new configuration option and then decides which one to use. This method has -several drawbacks: -- The application may need to read more configuration files than strictly - needed, resulting in a slower startup. -- The application becomes bigger with code that will only be used once. - -kconf_update addresses these problems by offering a framework to update -configuration files without adding code to the application itself. - -See the <a href="http://websvn.kde.org/trunk/KDE/kdelibs/kconf_update/README.kconf_update?view=markup">README file</a> for more information. - -@authors -Waldo Bastian \<bastian@kde.org\> - -@maintainers -[Unknown/None] - -@licenses -@lgpl - -*/ -// vim:ts=4:sw=4:expandtab:filetype=doxygen diff --git a/tier1/kconfig/src/kconf_update/README.kconf_update b/tier1/kconfig/src/kconf_update/README.kconf_update deleted file mode 100644 index 281fb9e5..00000000 --- a/tier1/kconfig/src/kconf_update/README.kconf_update +++ /dev/null @@ -1,248 +0,0 @@ -README kconf_update - -Version: 1.1 -Author: Waldo Bastian <bastian@kde.org>, <bastian@suse.com> - -What it does -============ - -kconf_update is a tool designed to update config files. Over time applications -sometimes need to rearrange the way configuration options are stored. Since -such an update shouldn't influence the configuration options that the user -has selected, the application must take care that the options stored in the -old way will still be honored. - -What used to happen is that the application looks up both the old and the -new configuration option and then decides which one to use. This method has -several drawbacks: -* The application may need to read more configuration files than strictly -needed, resulting in a slower startup. -* The application becomes bigger with code that will only be used once. - -kconf_update addresses these problems by offering a framework to update -configuration files without adding code to the application itself. - - -How it works -============ - -Applications can install so called "update files" under -$KDEDIR/share/apps/kconf_update. An update file has ".upd" as extension and -contains instructions for transferring/converting configuration information -from one place to another. - -Updating the configuration happens automatically, either when KDE gets started -or when kded detects a new update file in the above mentioned location. - -Update files are separated into sections. Each section has an Id. When a -section describing a configuration change has been applied, the Id will be -stored in the file "kconf_updaterc". This information is used to make sure -that a configuration update is only performed once. - -If you overwrite an existing update file with a new version that contains a -new section, only the update instructions from this extra section will be -performed. - -File format of the update file -============================== - -Empty lines or lines that start with '#' are considered comments. -Commas (,) are used to seperate fields and may not occur as part -of any field and all of the keywords are case-sensitive, i.e. you -cannot say "key" instead of "Key" for example. - -For the rest the file is parsed and executed sequentially from top to bottom. -Each line can contain one entry. The following entries are recognized: - - -Id=<id> - -With <id> identifying the group of update entries that follows. Once a group -of entries have been applied, their <id> is stored and this group of entries -will not be applied again. - - -File=<oldfile>,<newfile> -File=<oldfile> - -Specifies that configuration information is read from <oldfile> and written -to <newfile>. If you only specify <oldfile>, the information is read from -as well as written to <oldfile>. Note that if the file does not exist -at the time kconf_update first checks, no related update will be performed -(script won't be run at all, etc.). - - -Script=<script>[,<interpreter>] - -All entries from <oldfile> are piped into <script>. The output of script -is used as new entries for <newfile>. Existing entries can be deleted by -adding lines with "# DELETE [group]key" in the output of the script. -To delete a whole group use "# DELETEGROUP [group]". - -<script> should be installed into $(kde_datadir)/kconf_update, or -kconf_update will not be able to find it. It's also possible to install -kconf_update applications in $(kde_bindir)/kconf_update_bin, which opens the -door to kconf_update applications that are written in C++ and use Qt's -powerful string API instead. - -If Script was issued after a "Group" command the behavior is slightly -different: -All entries from <oldfile>/<oldgroup> are piped into <script>. The output -of script is used as new entries for <newfile>/<newgroup>, unless a different -group is specified with "[group]". Existing entries can be deleted from -<oldgroup> by adding lines with "# DELETE key" in the output of the script. -To delete <oldgroup> use "# DELETEGROUP". - -<interpreter> can be something like "perl". - -It is also possible to have a Script without specifying <oldfile> or -<newfile>. In that case the script is run but it will not be fed any input -and its output will simply be discarded. - -ScriptArguments=<arguments> - -If specified, the arguments will be passed to <script>. -IMPORTANT: It has to be specified before Script=. - -Group=<oldgroup>,<newgroup> -Group=<oldgroup> - -Specifies that configuration information is read from the group <oldgroup> -and written to <newgroup>. If you only specify <oldgroup>, the information -is read from as well as written to <oldgroup>. You can use <default> to -specify keys that are not under any group. -A group may be written either as "group" or as "[group]". The latter syntax -makes it possible to specify subgroups: "[group][subgroup]". - -RemoveGroup=<oldgroup> - -Specifies that <oldgroup> is removed entirely. This can be used -to remove obsolete entries or to force a revert to default values. - -Options=<option1>, <option2>, .... - -With this entry you can specify options that apply to the next "Script", -"Key" or "AllKeys" entry (only to the first!). Possible options are: - -- "copy" Copy the configuration item instead of moving it. This means that - the configuration item will not be deleted from <oldfile>/<oldgroup>. - -- "overwrite" Normally, a configuration item is not moved if an item with the - new name already exists. When this option is specified the old - configuration item will overwrite any existing item. - - -Key=<oldkey>,<newkey> -Key=<oldkey> - -Specifies that configuration information is read from the key <oldkey> -and written to <newkey>. If you only specify <oldkey>, the information -is read from as well as written to <oldkey>. - - -AllKeys - -Specifies that all configuration information in the selected group should -be moved (All keys). - -AllGroups - -Specifies that all configuration information from all keys in ALL -groups should be moved. - - -RemoveKey=<oldkey> - -Specifies that <oldkey> is removed from the selected group. This can be used -to remove obsolete entries or to force a revert to default values. - - -Example update file -=================== - -# This is comment -Id=kde2.2 -File=kioslaverc,kio_httprc -Group=Proxy Settings -Key=NoProxyFor -Key=UseProxy -Key=httpProxy,Proxy -Group=Cache Settings,Cache -Key=MaxCacheSize -Key=UseCache -Group=UserAgent -AllKeys -RemoveGroup=KDE -# End of file - - -The above update file extracts config information from the file "kioslaverc" -and stores it into the file "kio_httprc". - -It reads the keys "NoProxyFor", "UseProxy" and "httpProxy" from the group -"Proxy Settings" in the "kioslaverc" file. If any of these options are present -they are written to the keys "NoProxyFor", "UseProxy" and "Proxy" (!) in -the group "Proxy Settings" in the "kio_httprc" file. - -It also reads the keys "MaxCacheSize" and "UseCache" from the group -"Cache Settings" in the "kioslaverc" file and writes this information to the -keys "MaxCacheSize" and "UseCache" in the group "Cache" (!) in the -"kio_httprc" file. - -Then it takes all keys in the "UserAgent" group of the file "kioslaverc" -and moves then to the "UserAgent" group in the "kio_httprc" file. - -Finally it removes the entire "KDE" group in the kioslaverc file. - - -Debugging and testing -===================== - -If you are developing a kconf_update script and want to test or debug it you -need to make sure kconf_update runs again after each of your changes. There -are a number of ways to achieve this. - -The easiest is to not install the kconf_update script in the first place, but -manually call it through a pipe. If you want to test the update script for -your application KHello's config file khellorc, you can test by using - - cat ~/.kde/share/config/khellorc | khello_conf_update.sh - -(assuming khello_conf_update.sh is the kconf_update script and ~/.kde is your -$KDEHOME). This is easier than making install every time, but has the obvious -downside that you need to 'parse' your script's output yourself instead of -letting kconf_update do it and check the resulting output file. - -After 'make install' the kconf_update script is run by kded, but it does so -only once. This is of course the idea behind it, but while developing it can -be a problem. You can increase the revision number for each subsequent run -of 'make install' to force a new kconf_update run, but there's a better -approach that doesn't skyrocket the version number for a mediocre debug -session. - -kded doesn't really ignore scripts that it has already run right away. -Instead it checks the affected config file every time a .upd file is added -or changed. The reason it still doesn't run again on your config file lies -in the traces kconf_update leaves behind: it adds a special config group -'[$Version]' with a key 'update_info'. This key lists all kconf_update -scripts that have already been run on this config file. It also adds a group -for the script to $KDEHOME/share/config/kconf_updaterc. Just remove your -script entries from both your rcfile and kconf_updaterc, 'make install', -and kconf_update will happily run your script again, without you having to -increase the version number. - -If you want to know what kconf_update has been up to lately, have a look -at $KDEHOME/share/apps/kconf_update/log/update.log - - -Common Problems -=============== - -* kconf_update refuses to update an entry -If you change the value of an entry without changing the key or file, -make sure to tell kconf_update that it should overwrite the old entry -by adding "Options=overwrite". - - -Have fun, -Waldo diff --git a/tier1/kconfig/src/kconf_update/config-kconf.h.cmake b/tier1/kconfig/src/kconf_update/config-kconf.h.cmake deleted file mode 100644 index 0f70f8c8..00000000 --- a/tier1/kconfig/src/kconf_update/config-kconf.h.cmake +++ /dev/null @@ -1,4 +0,0 @@ -#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}" -#define LIBEXEC_INSTALL_DIR "${LIBEXEC_INSTALL_DIR}" -#define LIB_INSTALL_DIR "${LIB_INSTALL_DIR}" -#define KCONF_UPDATE_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}" diff --git a/tier1/kconfig/src/kconf_update/kconf_update.cpp b/tier1/kconfig/src/kconf_update/kconf_update.cpp deleted file mode 100644 index 60a61db3..00000000 --- a/tier1/kconfig/src/kconf_update/kconf_update.cpp +++ /dev/null @@ -1,967 +0,0 @@ -/* - * - * This file is part of the KDE libraries - * Copyright (c) 2001 Waldo Bastian <bastian@kde.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License version 2 as published by the Free Software Foundation. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - **/ - -#include <config-kconf.h> // CMAKE_INSTALL_PREFIX - -#include <QtCore/QDate> -#include <QtCore/QFile> -#include <QtCore/QTextStream> -#include <QtCore/QTextCodec> -#include <QUrl> -#include <QTemporaryFile> -#include <QCoreApplication> -#include <QtCore/QDir> - -#include <kconfig.h> -#include <kconfiggroup.h> - -#include <qstandardpaths.h> -#include <qcommandlineparser.h> -#include <qcommandlineoption.h> - -#include "kconfigutils.h" - -class KonfUpdate -{ -public: - KonfUpdate(QCommandLineParser *parser); - ~KonfUpdate(); - QStringList findUpdateFiles(bool dirtyOnly); - - QTextStream &log(); - QTextStream &logFileError(); - - bool checkFile(const QString &filename); - void checkGotFile(const QString &_file, const QString &id); - - bool updateFile(const QString &filename); - - void gotId(const QString &_id); - void gotFile(const QString &_file); - void gotGroup(const QString &_group); - void gotRemoveGroup(const QString &_group); - void gotKey(const QString &_key); - void gotRemoveKey(const QString &_key); - void gotAllKeys(); - void gotAllGroups(); - void gotOptions(const QString &_options); - void gotScript(const QString &_script); - void gotScriptArguments(const QString &_arguments); - void resetOptions(); - - void copyGroup(const KConfigBase *cfg1, const QString &group1, - KConfigBase *cfg2, const QString &group2); - void copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2); - void copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey); - void copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath); - - QStringList parseGroupString(const QString &_str); - -protected: - KConfig *m_config; - QString m_currentFilename; - bool m_skip; - bool m_skipFile; - bool m_debug; - QString m_id; - - QString m_oldFile; - QString m_newFile; - QString m_newFileName; - KConfig *m_oldConfig1; // Config to read keys from. - KConfig *m_oldConfig2; // Config to delete keys from. - KConfig *m_newConfig; - - QStringList m_oldGroup; - QStringList m_newGroup; - - bool m_bCopy; - bool m_bOverwrite; - bool m_bUseConfigInfo; - QString m_arguments; - QTextStream *m_textStream; - QFile *m_file; - QString m_line; - int m_lineCount; -}; - -KonfUpdate::KonfUpdate(QCommandLineParser * parser) - : m_textStream(0), m_file(0) -{ - bool updateAll = false; - m_oldConfig1 = 0; - m_oldConfig2 = 0; - m_newConfig = 0; - - m_config = new KConfig("kconf_updaterc"); - KConfigGroup cg(m_config, QString()); - - QStringList updateFiles; - - m_debug = parser->isSet("debug"); - - m_bUseConfigInfo = false; - if (parser->isSet("check")) { - m_bUseConfigInfo = true; - QString file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kconf_update/" + parser->value("check")); - if (file.isEmpty()) { - qWarning("File '%s' not found.", parser->value("check").toLocal8Bit().data()); - log() << "File '" << parser->value("check") << "' passed on command line not found" << endl; - return; - } - updateFiles.append(file); - } else if (parser->positionalArguments().count()) { - updateFiles += parser->positionalArguments(); - } else { - if (cg.readEntry("autoUpdateDisabled", false)) - return; - updateFiles = findUpdateFiles(true); - updateAll = true; - } - - for (QStringList::ConstIterator it = updateFiles.constBegin(); - it != updateFiles.constEnd(); - ++it) { - updateFile(*it); - } - - if (updateAll && !cg.readEntry("updateInfoAdded", false)) { - cg.writeEntry("updateInfoAdded", true); - updateFiles = findUpdateFiles(false); - - for (QStringList::ConstIterator it = updateFiles.constBegin(); - it != updateFiles.constEnd(); - ++it) { - checkFile(*it); - } - updateFiles.clear(); - } -} - -KonfUpdate::~KonfUpdate() -{ - delete m_config; - delete m_file; - delete m_textStream; -} - -QTextStream & operator<<(QTextStream & stream, const QStringList & lst) -{ - stream << lst.join(", "); - return stream; -} - -QTextStream & -KonfUpdate::log() -{ - if (!m_textStream) { - QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QLatin1Char('/') + "kconf_update/log"; - QDir().mkpath(dir); - QString file = dir + "/update.log"; - m_file = new QFile(file); - if (m_file->open(QIODevice::WriteOnly | QIODevice::Append)) { - m_textStream = new QTextStream(m_file); - } else { - // Error - m_textStream = new QTextStream(stderr, QIODevice::WriteOnly); - } - } - - (*m_textStream) << QDateTime::currentDateTime().toString(Qt::ISODate) << " "; - - return *m_textStream; -} - -QTextStream & -KonfUpdate::logFileError() -{ - return log() << m_currentFilename << ':' << m_lineCount << ":'" << m_line << "': "; -} - -QStringList KonfUpdate::findUpdateFiles(bool dirtyOnly) -{ - QStringList result; - - const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, "kconf_update", QStandardPaths::LocateDirectory); - Q_FOREACH(const QString& dir, dirs) { - const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.upd")); - Q_FOREACH(const QString& fileName, fileNames) { - const QString file = dir + '/' + fileName; - QFileInfo info(file); - - KConfigGroup cg(m_config, fileName); - const QDateTime ctime = QDateTime::fromTime_t(cg.readEntry("ctime", 0)); - const QDateTime mtime = QDateTime::fromTime_t(cg.readEntry("mtime", 0)); - if (!dirtyOnly || - (ctime != info.created()) || (mtime != info.lastModified())) { - result.append(file); - } - } - } - return result; -} - -bool KonfUpdate::checkFile(const QString &filename) -{ - m_currentFilename = filename; - int i = m_currentFilename.lastIndexOf('/'); - if (i != -1) { - m_currentFilename = m_currentFilename.mid(i + 1); - } - m_skip = true; - QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - QTextStream ts(&file); - ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); - int lineCount = 0; - resetOptions(); - QString id; - while (!ts.atEnd()) { - QString line = ts.readLine().trimmed(); - lineCount++; - if (line.isEmpty() || (line[0] == '#')) { - continue; - } - if (line.startsWith("Id=")) { - id = m_currentFilename + ':' + line.mid(3); - } else if (line.startsWith("File=")) { - checkGotFile(line.mid(5), id); - } - } - - return true; -} - -void KonfUpdate::checkGotFile(const QString &_file, const QString &id) -{ - QString file; - int i = _file.indexOf(','); - if (i == -1) { - file = _file.trimmed(); - } else { - file = _file.mid(i + 1).trimmed(); - } - -// qDebug("File %s, id %s", file.toLatin1().constData(), id.toLatin1().constData()); - - KConfig cfg(file, KConfig::SimpleConfig); - KConfigGroup cg(&cfg, "$Version"); - QStringList ids = cg.readEntry("update_info", QStringList()); - if (ids.contains(id)) { - return; - } - ids.append(id); - cg.writeEntry("update_info", ids); -} - -/** - * Syntax: - * # Comment - * Id=id - * File=oldfile[,newfile] - * AllGroups - * Group=oldgroup[,newgroup] - * RemoveGroup=oldgroup - * Options=[copy,][overwrite,] - * Key=oldkey[,newkey] - * RemoveKey=ldkey - * AllKeys - * Keys= [Options](AllKeys|(Key|RemoveKey)*) - * ScriptArguments=arguments - * Script=scriptfile[,interpreter] - * - * Sequence: - * (Id,(File(Group,Keys)*)*)* - **/ -bool KonfUpdate::updateFile(const QString &filename) -{ - m_currentFilename = filename; - int i = m_currentFilename.lastIndexOf('/'); - if (i != -1) { - m_currentFilename = m_currentFilename.mid(i + 1); - } - m_skip = true; - QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) { - return false; - } - - log() << "Checking update-file '" << filename << "' for new updates" << endl; - - QTextStream ts(&file); - ts.setCodec(QTextCodec::codecForName("ISO-8859-1")); - m_lineCount = 0; - resetOptions(); - while (!ts.atEnd()) { - m_line = ts.readLine().trimmed(); - m_lineCount++; - if (m_line.isEmpty() || (m_line[0] == '#')) { - continue; - } - if (m_line.startsWith(QLatin1String("Id="))) { - gotId(m_line.mid(3)); - } else if (m_skip) { - continue; - } else if (m_line.startsWith(QLatin1String("Options="))) { - gotOptions(m_line.mid(8)); - } else if (m_line.startsWith(QLatin1String("File="))) { - gotFile(m_line.mid(5)); - } else if (m_skipFile) { - continue; - } else if (m_line.startsWith(QLatin1String("Group="))) { - gotGroup(m_line.mid(6)); - } else if (m_line.startsWith(QLatin1String("RemoveGroup="))) { - gotRemoveGroup(m_line.mid(12)); - resetOptions(); - } else if (m_line.startsWith(QLatin1String("Script="))) { - gotScript(m_line.mid(7)); - resetOptions(); - } else if (m_line.startsWith(QLatin1String("ScriptArguments="))) { - gotScriptArguments(m_line.mid(16)); - } else if (m_line.startsWith(QLatin1String("Key="))) { - gotKey(m_line.mid(4)); - resetOptions(); - } else if (m_line.startsWith(QLatin1String("RemoveKey="))) { - gotRemoveKey(m_line.mid(10)); - resetOptions(); - } else if (m_line == "AllKeys") { - gotAllKeys(); - resetOptions(); - } else if (m_line == "AllGroups") { - gotAllGroups(); - resetOptions(); - } else { - logFileError() << "Parse error" << endl; - } - } - // Flush. - gotId(QString()); - - QFileInfo info(filename); - KConfigGroup cg(m_config, m_currentFilename); - cg.writeEntry("ctime", info.created().toTime_t()); - cg.writeEntry("mtime", info.lastModified().toTime_t()); - cg.sync(); - return true; -} - - - -void KonfUpdate::gotId(const QString &_id) -{ - if (!m_id.isEmpty() && !m_skip) { - KConfigGroup cg(m_config, m_currentFilename); - - QStringList ids = cg.readEntry("done", QStringList()); - if (!ids.contains(m_id)) { - ids.append(m_id); - cg.writeEntry("done", ids); - cg.sync(); - } - } - - // Flush pending changes - gotFile(QString()); - KConfigGroup cg(m_config, m_currentFilename); - - QStringList ids = cg.readEntry("done", QStringList()); - if (!_id.isEmpty()) { - if (ids.contains(_id)) { - //qDebug("Id '%s' was already in done-list", _id.toLatin1().constData()); - if (!m_bUseConfigInfo) { - m_skip = true; - return; - } - } - m_skip = false; - m_skipFile = false; - m_id = _id; - if (m_bUseConfigInfo) { - log() << m_currentFilename << ": Checking update '" << _id << "'" << endl; - } else { - log() << m_currentFilename << ": Found new update '" << _id << "'" << endl; - } - } -} - -void KonfUpdate::gotFile(const QString &_file) -{ - // Reset group - gotGroup(QString()); - - if (!m_oldFile.isEmpty()) { - // Close old file. - delete m_oldConfig1; - m_oldConfig1 = 0; - - KConfigGroup cg(m_oldConfig2, "$Version"); - QStringList ids = cg.readEntry("update_info", QStringList()); - QString cfg_id = m_currentFilename + ':' + m_id; - if (!ids.contains(cfg_id) && !m_skip) { - ids.append(cfg_id); - cg.writeEntry("update_info", ids); - } - cg.sync(); - delete m_oldConfig2; - m_oldConfig2 = 0; - - QString file = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QLatin1Char('/') + m_oldFile; - QFileInfo info(file); - if (info.exists() && info.size() == 0) { - // Delete empty file. - QFile::remove(file); - } - - m_oldFile.clear(); - } - if (!m_newFile.isEmpty()) { - // Close new file. - KConfigGroup cg(m_newConfig, "$Version"); - QStringList ids = cg.readEntry("update_info", QStringList()); - QString cfg_id = m_currentFilename + ':' + m_id; - if (!ids.contains(cfg_id) && !m_skip) { - ids.append(cfg_id); - cg.writeEntry("update_info", ids); - } - m_newConfig->sync(); - delete m_newConfig; - m_newConfig = 0; - - m_newFile.clear(); - } - m_newConfig = 0; - - int i = _file.indexOf(','); - if (i == -1) { - m_oldFile = _file.trimmed(); - } else { - m_oldFile = _file.left(i).trimmed(); - m_newFile = _file.mid(i + 1).trimmed(); - if (m_oldFile == m_newFile) { - m_newFile.clear(); - } - } - - if (!m_oldFile.isEmpty()) { - m_oldConfig2 = new KConfig(m_oldFile, KConfig::NoGlobals); - QString cfg_id = m_currentFilename + ':' + m_id; - KConfigGroup cg(m_oldConfig2, "$Version"); - QStringList ids = cg.readEntry("update_info", QStringList()); - if (ids.contains(cfg_id)) { - m_skip = true; - m_newFile.clear(); - log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl; - } - - if (!m_newFile.isEmpty()) { - m_newConfig = new KConfig(m_newFile, KConfig::NoGlobals); - KConfigGroup cg(m_newConfig, "$Version"); - ids = cg.readEntry("update_info", QStringList()); - if (ids.contains(cfg_id)) { - m_skip = true; - log() << m_currentFilename << ": Skipping update '" << m_id << "'" << endl; - } - } else { - m_newConfig = m_oldConfig2; - } - - m_oldConfig1 = new KConfig(m_oldFile, KConfig::NoGlobals); - } else { - m_newFile.clear(); - } - m_newFileName = m_newFile; - if (m_newFileName.isEmpty()) { - m_newFileName = m_oldFile; - } - - m_skipFile = false; - if (!m_oldFile.isEmpty()) { // if File= is specified, it doesn't exist, is empty or contains only kconf_update's [$Version] group, skip - if (m_oldConfig1 != NULL - && (m_oldConfig1->groupList().isEmpty() - || (m_oldConfig1->groupList().count() == 1 && m_oldConfig1->groupList().first() == "$Version"))) { - log() << m_currentFilename << ": File '" << m_oldFile << "' does not exist or empty, skipping" << endl; - m_skipFile = true; - } - } -} - -QStringList KonfUpdate::parseGroupString(const QString &str) -{ - bool ok; - QString error; - QStringList lst = KConfigUtils::parseGroupString(str, &ok, &error); - if (!ok) { - logFileError() << error; - } - return lst; -} - -void KonfUpdate::gotGroup(const QString &_group) -{ - QString group = _group.trimmed(); - if (group.isEmpty()) { - m_oldGroup = m_newGroup = QStringList(); - return; - } - - QStringList tokens = group.split(','); - m_oldGroup = parseGroupString(tokens.at(0)); - if (tokens.count() == 1) { - m_newGroup = m_oldGroup; - } else { - m_newGroup = parseGroupString(tokens.at(1)); - } -} - -void KonfUpdate::gotRemoveGroup(const QString &_group) -{ - m_oldGroup = parseGroupString(_group); - - if (!m_oldConfig1) { - logFileError() << "RemoveGroup without previous File specification" << endl; - return; - } - - KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup); - if (!cg.exists()) { - return; - } - // Delete group. - cg.deleteGroup(); - log() << m_currentFilename << ": RemoveGroup removes group " << m_oldFile << ":" << m_oldGroup << endl; -} - - -void KonfUpdate::gotKey(const QString &_key) -{ - QString oldKey, newKey; - int i = _key.indexOf(','); - if (i == -1) { - oldKey = _key.trimmed(); - newKey = oldKey; - } else { - oldKey = _key.left(i).trimmed(); - newKey = _key.mid(i + 1).trimmed(); - } - - if (oldKey.isEmpty() || newKey.isEmpty()) { - logFileError() << "Key specifies invalid key" << endl; - return; - } - if (!m_oldConfig1) { - logFileError() << "Key without previous File specification" << endl; - return; - } - copyOrMoveKey(m_oldGroup, oldKey, m_newGroup, newKey); -} - -void KonfUpdate::copyOrMoveKey(const QStringList &srcGroupPath, const QString &srcKey, const QStringList &dstGroupPath, const QString &dstKey) -{ - KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, dstGroupPath); - if (!m_bOverwrite && dstCg.hasKey(dstKey)) { - log() << m_currentFilename << ": Skipping " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << ", already exists." << endl; - return; - } - - KConfigGroup srcCg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath); - if (!srcCg.hasKey(srcKey)) - return; - QString value = srcCg.readEntry(srcKey, QString()); - log() << m_currentFilename << ": Updating " << m_newFileName << ":" << dstCg.name() << ":" << dstKey << " to '" << value << "'" << endl; - dstCg.writeEntry(dstKey, value); - - if (m_bCopy) { - return; // Done. - } - - // Delete old entry - if (m_oldConfig2 == m_newConfig - && srcGroupPath == dstGroupPath - && srcKey == dstKey) { - return; // Don't delete! - } - KConfigGroup srcCg2 = KConfigUtils::openGroup(m_oldConfig2, srcGroupPath); - srcCg2.deleteEntry(srcKey); - log() << m_currentFilename << ": Removing " << m_oldFile << ":" << srcCg2.name() << ":" << srcKey << ", moved." << endl; -} - -void KonfUpdate::copyOrMoveGroup(const QStringList &srcGroupPath, const QStringList &dstGroupPath) -{ - KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig1, srcGroupPath); - - // Keys - Q_FOREACH(const QString &key, cg.keyList()) { - copyOrMoveKey(srcGroupPath, key, dstGroupPath, key); - } - - // Subgroups - Q_FOREACH(const QString &group, cg.groupList()) { - QStringList groupPath = QStringList() << group; - copyOrMoveGroup(srcGroupPath + groupPath, dstGroupPath + groupPath); - } -} - -void KonfUpdate::gotRemoveKey(const QString &_key) -{ - QString key = _key.trimmed(); - - if (key.isEmpty()) { - logFileError() << "RemoveKey specifies invalid key" << endl; - return; - } - - if (!m_oldConfig1) { - logFileError() << "Key without previous File specification" << endl; - return; - } - - KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup); - if (!cg1.hasKey(key)) { - return; - } - log() << m_currentFilename << ": RemoveKey removes " << m_oldFile << ":" << m_oldGroup << ":" << key << endl; - - // Delete old entry - KConfigGroup cg2 = KConfigUtils::openGroup(m_oldConfig2, m_oldGroup); - cg2.deleteEntry(key); - /*if (m_oldConfig2->deleteGroup(m_oldGroup, KConfig::Normal)) { // Delete group if empty. - log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << m_oldGroup << endl; - } (this should be automatic)*/ -} - -void KonfUpdate::gotAllKeys() -{ - if (!m_oldConfig1) { - logFileError() << "AllKeys without previous File specification" << endl; - return; - } - - copyOrMoveGroup(m_oldGroup, m_newGroup); -} - -void KonfUpdate::gotAllGroups() -{ - if (!m_oldConfig1) { - logFileError() << "AllGroups without previous File specification" << endl; - return; - } - - const QStringList allGroups = m_oldConfig1->groupList(); - for (QStringList::ConstIterator it = allGroups.begin(); - it != allGroups.end(); ++it) { - m_oldGroup = QStringList() << *it; - m_newGroup = m_oldGroup; - gotAllKeys(); - } -} - -void KonfUpdate::gotOptions(const QString &_options) -{ - const QStringList options = _options.split(','); - for (QStringList::ConstIterator it = options.begin(); - it != options.end(); - ++it) { - if ((*it).toLower().trimmed() == "copy") { - m_bCopy = true; - } - - if ((*it).toLower().trimmed() == "overwrite") { - m_bOverwrite = true; - } - } -} - -void KonfUpdate::copyGroup(const KConfigBase *cfg1, const QString &group1, - KConfigBase *cfg2, const QString &group2) -{ - KConfigGroup cg1(cfg1, group1); - KConfigGroup cg2(cfg2, group2); - copyGroup(cg1, cg2); -} - -void KonfUpdate::copyGroup(const KConfigGroup &cg1, KConfigGroup &cg2) -{ - // Copy keys - QMap<QString, QString> list = cg1.entryMap(); - for (QMap<QString, QString>::ConstIterator it = list.constBegin(); - it != list.constEnd(); ++it) { - if (m_bOverwrite || !cg2.hasKey(it.key())) { - cg2.writeEntry(it.key(), it.value()); - } - } - - // Copy subgroups - Q_FOREACH(const QString &group, cg1.groupList()) { - copyGroup(&cg1, group, &cg2, group); - } -} - -void KonfUpdate::gotScriptArguments(const QString &_arguments) -{ - m_arguments = _arguments; -} - -void KonfUpdate::gotScript(const QString &_script) -{ - QString script, interpreter; - int i = _script.indexOf(','); - if (i == -1) { - script = _script.trimmed(); - } else { - script = _script.left(i).trimmed(); - interpreter = _script.mid(i + 1).trimmed(); - } - - - if (script.isEmpty()) { - logFileError() << "Script fails to specify filename"; - m_skip = true; - return; - } - - - - QString path = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kconf_update/" + script); - if (path.isEmpty()) { - if (interpreter.isEmpty()) { - // KDE4: this was looking into locate("lib", "kconf_update_bin/"). But QStandardPaths doesn't know the lib dirs. - // Let's look in the install prefix and in PATH. - path = CMAKE_INSTALL_PREFIX "/" LIB_INSTALL_DIR "/kconf_update_bin/" + script; - if (QFile::exists(path)) - path = QStandardPaths::findExecutable(script); - } - - if (path.isEmpty()) { - logFileError() << "Script '" << script << "' not found" << endl; - m_skip = true; - return; - } - } - - if (!m_arguments.isNull()) { - log() << m_currentFilename << ": Running script '" << script << "' with arguments '" << m_arguments << "'" << endl; - } else { - log() << m_currentFilename << ": Running script '" << script << "'" << endl; - } - - QString cmd; - if (interpreter.isEmpty()) { - cmd = path; - } else { - cmd = interpreter + ' ' + path; - } - - if (!m_arguments.isNull()) { - cmd += ' '; - cmd += m_arguments; - } - - QTemporaryFile scriptIn; - scriptIn.open(); - QTemporaryFile scriptOut; - scriptOut.open(); - QTemporaryFile scriptErr; - scriptErr.open(); - - int result; - if (m_oldConfig1) { - if (m_debug) { - scriptIn.setAutoRemove(false); - log() << "Script input stored in " << scriptIn.fileName() << endl; - } - KConfig cfg(scriptIn.fileName(), KConfig::SimpleConfig); - - if (m_oldGroup.isEmpty()) { - // Write all entries to tmpFile; - const QStringList grpList = m_oldConfig1->groupList(); - for (QStringList::ConstIterator it = grpList.begin(); - it != grpList.end(); - ++it) { - copyGroup(m_oldConfig1, *it, &cfg, *it); - } - } else { - KConfigGroup cg1 = KConfigUtils::openGroup(m_oldConfig1, m_oldGroup); - KConfigGroup cg2(&cfg, QString()); - copyGroup(cg1, cg2); - } - cfg.sync(); -#ifndef _WIN32_WCE - result = system(QFile::encodeName(QString("%1 < %2 > %3 2> %4").arg(cmd, scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName())).constData()); -#else - QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() ); - QString file_ = QFileInfo ( cmd ).fileName(); - SHELLEXECUTEINFO execInfo; - memset ( &execInfo,0,sizeof ( execInfo ) ); - execInfo.cbSize = sizeof ( execInfo ); - execInfo.fMask = SEE_MASK_FLAG_NO_UI; - execInfo.lpVerb = L"open"; - execInfo.lpFile = (LPCWSTR) path_.utf16(); - execInfo.lpDirectory = (LPCWSTR) file_.utf16(); - execInfo.lpParameters = (LPCWSTR) QString(" < %1 > %2 2> %3").arg( scriptIn.fileName(), scriptOut.fileName(), scriptErr.fileName()).utf16(); - result = ShellExecuteEx ( &execInfo ); - if (result != 0) - { - result = 0; - } - else - { - result = -1; - } -#endif - } else { - // No config file -#ifndef _WIN32_WCE - result = system(QFile::encodeName(QString("%1 2> %2").arg(cmd, scriptErr.fileName())).constData()); -#else - QString path_ = QDir::convertSeparators ( QFileInfo ( cmd ).absoluteFilePath() ); - QString file_ = QFileInfo ( cmd ).fileName(); - SHELLEXECUTEINFO execInfo; - memset ( &execInfo,0,sizeof ( execInfo ) ); - execInfo.cbSize = sizeof ( execInfo ); - execInfo.fMask = SEE_MASK_FLAG_NO_UI; - execInfo.lpVerb = L"open"; - execInfo.lpFile = (LPCWSTR) path_.utf16(); - execInfo.lpDirectory = (LPCWSTR) file_.utf16(); - execInfo.lpParameters = (LPCWSTR) QString(" 2> %1").arg( scriptErr.fileName()).utf16(); - result = ShellExecuteEx ( &execInfo ); - if (result != 0) - { - result = 0; - } - else - { - result = -1; - } -#endif - } - - // Copy script stderr to log file - { - QFile output(scriptErr.fileName()); - if (output.open(QIODevice::ReadOnly)) { - QTextStream ts(&output); - ts.setCodec(QTextCodec::codecForName("UTF-8")); - while (!ts.atEnd()) { - QString line = ts.readLine(); - log() << "[Script] " << line << endl; - } - } - } - - if (result) { - log() << m_currentFilename << ": !! An error occurred while running '" << cmd << "'" << endl; - return; - } - - if (!m_oldConfig1) { - return; // Nothing to merge - } - - if (m_debug) { - scriptOut.setAutoRemove(false); - log() << "Script output stored in " << scriptOut.fileName() << endl; - } - - // Deleting old entries - { - QStringList group = m_oldGroup; - QFile output(scriptOut.fileName()); - if (output.open(QIODevice::ReadOnly)) { - QTextStream ts(&output); - ts.setCodec(QTextCodec::codecForName("UTF-8")); - while (!ts.atEnd()) { - QString line = ts.readLine(); - if (line.startsWith('[')) { - group = parseGroupString(line); - } else if (line.startsWith(QLatin1String("# DELETE "))) { - QString key = line.mid(9); - if (key[0] == '[') { - int j = key.lastIndexOf(']') + 1; - if (j > 0) { - group = parseGroupString(key.left(j)); - key = key.mid(j); - } - } - KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group); - cg.deleteEntry(key); - log() << m_currentFilename << ": Script removes " << m_oldFile << ":" << group << ":" << key << endl; - /*if (m_oldConfig2->deleteGroup(group, KConfig::Normal)) { // Delete group if empty. - log() << m_currentFilename << ": Removing empty group " << m_oldFile << ":" << group << endl; - } (this should be automatic)*/ - } else if (line.startsWith(QLatin1String("# DELETEGROUP"))) { - QString str = line.mid(13).trimmed(); - if (!str.isEmpty()) { - group = parseGroupString(str); - } - KConfigGroup cg = KConfigUtils::openGroup(m_oldConfig2, group); - cg.deleteGroup(); - log() << m_currentFilename << ": Script removes group " << m_oldFile << ":" << group << endl; - } - } - } - } - - // Merging in new entries. - KConfig scriptOutConfig(scriptOut.fileName(), KConfig::NoGlobals); - if (m_newGroup.isEmpty()) { - // Copy "default" keys as members of "default" keys - copyGroup(&scriptOutConfig, QString(), m_newConfig, QString()); - } else { - // Copy default keys as members of m_newGroup - KConfigGroup srcCg = KConfigUtils::openGroup(&scriptOutConfig, QStringList()); - KConfigGroup dstCg = KConfigUtils::openGroup(m_newConfig, m_newGroup); - copyGroup(srcCg, dstCg); - } - Q_FOREACH(const QString &group, scriptOutConfig.groupList()) { - copyGroup(&scriptOutConfig, group, m_newConfig, group); - } -} - -void KonfUpdate::resetOptions() -{ - m_bCopy = false; - m_bOverwrite = false; - m_arguments.clear(); -} - - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); - app.setApplicationVersion("1.1"); - - QCommandLineParser parser; - parser.addVersionOption(); - parser.setApplicationDescription(QCoreApplication::translate("main", "KDE Tool for updating user configuration files")); - parser.addHelpOption(); - parser.addOption(QCommandLineOption(QStringList() << "debug", QCoreApplication::translate("main", "Keep output results from scripts"))); - parser.addOption(QCommandLineOption(QStringList() << "check", QCoreApplication::translate("main", "Check whether config file itself requires updating"), "update-file")); - //parser.addOption(QCommandLineOption(QStringList() << "+[file]", QCoreApplication::translate("main", "File to read update instructions from"))); - - // TODO aboutData.addAuthor(ki18n("Waldo Bastian"), KLocalizedString(), "bastian@kde.org"); - - parser.process(app); - KonfUpdate konfUpdate(&parser); - - return 0; -} diff --git a/tier1/kconfig/src/kconf_update/kconfigutils.cpp b/tier1/kconfig/src/kconf_update/kconfigutils.cpp deleted file mode 100644 index f2663e13..00000000 --- a/tier1/kconfig/src/kconf_update/kconfigutils.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* This file is part of the KDE libraries - Copyright 2010 Canonical Ltd - Author: Aurélien Gâteau <aurelien.gateau@canonical.com> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License (LGPL) as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later - version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -#include "kconfigutils.h" - -// KDE -#include <kconfig.h> -#include <kconfiggroup.h> - -namespace KConfigUtils -{ - -bool hasGroup(KConfig *config, const QStringList &lst) -{ - KConfigGroup group = openGroup(config, lst); - return group.exists(); -} - -KConfigGroup openGroup(KConfig *config, const QStringList &_lst) -{ - if (_lst.isEmpty()) { - return KConfigGroup(config, QString()); - } - - QStringList lst = _lst; - - KConfigGroup cg; - for (cg = KConfigGroup(config, lst.takeFirst()); !lst.isEmpty(); cg = KConfigGroup(&cg, lst.takeFirst())) {} - return cg; -} - -QStringList parseGroupString(const QString &_str, bool *ok, QString *error) -{ - QString str = unescapeString(_str.trimmed(), ok, error); - if (!ok) { - return QStringList(); - } - - *ok = true; - if (str[0] != '[') { - // Simplified notation, no '[' - return QStringList() << str; - } - - if (!str.endsWith(']')) { - *ok = false; - *error = QString("Missing closing ']' in %1").arg(_str); - return QStringList(); - } - // trim outer brackets - str.chop(1); - str.remove(0, 1); - - return str.split("]["); -} - -QString unescapeString(const QString &src, bool *ok, QString *error) -{ - QString dst; - int length = src.length(); - for (int pos = 0; pos < length; ++pos) { - QChar ch = src.at(pos); - if (ch != '\\') { - dst += ch; - } else { - ++pos; - if (pos == length) { - *ok = false; - *error = QString("Unfinished escape sequence in %1").arg(src); - return QString(); - } - ch = src.at(pos); - if (ch == 's') { - dst += ' '; - } else if (ch == 't') { - dst += '\t'; - } else if (ch == 'n') { - dst += '\n'; - } else if (ch == 'r') { - dst += '\r'; - } else if (ch == '\\') { - dst += '\\'; - } else if (ch == 'x') { - if (pos + 2 < length) { - char value = src.mid(pos + 1, 2).toInt(ok, 16); - if (*ok) { - dst += QChar::fromLatin1(value); - pos += 2; - } else { - *error = QString("Invalid hex escape sequence at column %1 in %2").arg(pos).arg(src); - return QString(); - } - } else { - *ok = false; - *error = QString("Unfinished hex escape sequence at column %1 in %2").arg(pos).arg(src); - return QString(); - } - } else { - *ok = false; - *error = QString("Invalid escape sequence at column %1 in %2").arg(pos).arg(src); - return QString(); - } - } - } - - *ok = true; - return dst; -} - -} // namespace diff --git a/tier1/kconfig/src/kconf_update/kconfigutils.h b/tier1/kconfig/src/kconf_update/kconfigutils.h deleted file mode 100644 index 606495e6..00000000 --- a/tier1/kconfig/src/kconf_update/kconfigutils.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of the KDE libraries - Copyright 2010 Canonical Ltd - Author: Aurélien Gâteau <aurelien.gateau@canonical.com> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License (LGPL) as published by the Free Software Foundation; - either version 2 of the License, or (at your option) any later - version. - - This library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -#ifndef KCONFIGUTILS_H -#define KCONFIGUTILS_H - -class QString; -class QStringList; - -class KConfig; -class KConfigGroup; - -namespace KConfigUtils -{ - -bool hasGroup(KConfig *, const QStringList &); - -KConfigGroup openGroup(KConfig *, const QStringList &); - -QStringList parseGroupString(const QString &str, bool *ok, QString *error); - -QString unescapeString(const QString &str, bool *ok, QString *error); - -} // namespace - -#endif /* KCONFIGUTILS_H */ |
