diff options
Diffstat (limited to 'src/libs')
-rw-r--r-- | src/libs/utils/environment.cpp | 443 | ||||
-rw-r--r-- | src/libs/utils/environment.h | 109 | ||||
-rw-r--r-- | src/libs/utils/utils-lib.pri | 6 |
3 files changed, 556 insertions, 2 deletions
diff --git a/src/libs/utils/environment.cpp b/src/libs/utils/environment.cpp new file mode 100644 index 00000000000..03b0084ecc6 --- /dev/null +++ b/src/libs/utils/environment.cpp @@ -0,0 +1,443 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation ([email protected]) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "environment.h" + +#include <QtCore/QProcess> +#include <QtCore/QDir> +#include <QtCore/QString> + +using namespace Utils; + +QList<EnvironmentItem> EnvironmentItem::fromStringList(QStringList list) +{ + QList<EnvironmentItem> result; + foreach (const QString &string, list) { + int pos = string.indexOf(QLatin1Char('=')); + if (pos == -1) { + EnvironmentItem item(string, QString()); + item.unset = true; + result.append(item); + } else { + EnvironmentItem item(string.left(pos), string.mid(pos+1)); + result.append(item); + } + } + return result; +} + +QStringList EnvironmentItem::toStringList(QList<EnvironmentItem> list) +{ + QStringList result; + foreach (const EnvironmentItem &item, list) { + if (item.unset) + result << QString(item.name); + else + result << QString(item.name + '=' + item.value); + } + return result; +} + +Environment::Environment() +{ +} + +Environment::Environment(QStringList env) +{ + foreach (const QString &s, env) { + int i = s.indexOf("="); + if (i >= 0) { +#ifdef Q_OS_WIN + m_values.insert(s.left(i).toUpper(), s.mid(i+1)); +#else + m_values.insert(s.left(i), s.mid(i+1)); +#endif + } + } +} + +QStringList Environment::toStringList() const +{ + QStringList result; + const QMap<QString, QString>::const_iterator end = m_values.constEnd(); + for (QMap<QString, QString>::const_iterator it = m_values.constBegin(); it != end; ++it) { + QString entry = it.key(); + entry += QLatin1Char('='); + entry += it.value(); + result.push_back(entry); + } + return result; +} + +void Environment::set(const QString &key, const QString &value) +{ +#ifdef Q_OS_WIN + QString _key = key.toUpper(); +#else + const QString &_key = key; +#endif + m_values.insert(_key, value); +} + +void Environment::unset(const QString &key) +{ +#ifdef Q_OS_WIN + QString _key = key.toUpper(); +#else + const QString &_key = key; +#endif + m_values.remove(_key); +} + +void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep) +{ +#ifdef Q_OS_WIN + QString _key = key.toUpper(); +#else + const QString &_key = key; +#endif + QMap<QString, QString>::iterator it = m_values.find(key); + if (it == m_values.end()) { + m_values.insert(_key, value); + } else { + // Append unless it is already there + const QString toAppend = sep + value; + if (!it.value().endsWith(toAppend)) + it.value().append(toAppend); + } +} + +void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep) +{ +#ifdef Q_OS_WIN + QString _key = key.toUpper(); +#else + const QString &_key = key; +#endif + QMap<QString, QString>::iterator it = m_values.find(key); + if (it == m_values.end()) { + m_values.insert(_key, value); + } else { + // Prepend unless it is already there + const QString toPrepend = value + sep; + if (!it.value().startsWith(toPrepend)) + it.value().prepend(toPrepend); + } +} + +void Environment::appendOrSetPath(const QString &value) +{ +#ifdef Q_OS_WIN + const QChar sep = QLatin1Char(';'); +#else + const QChar sep = QLatin1Char(':'); +#endif + appendOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep)); +} + +void Environment::prependOrSetPath(const QString &value) +{ +#ifdef Q_OS_WIN + const QChar sep = QLatin1Char(';'); +#else + const QChar sep = QLatin1Char(':'); +#endif + prependOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep)); +} + +Environment Environment::systemEnvironment() +{ + return Environment(QProcess::systemEnvironment()); +} + +void Environment::clear() +{ + m_values.clear(); +} + +QString Environment::searchInPath(QString executable) const +{ +// qDebug()<<"looking for "<<executable<< "in PATH: "<<m_values.value("PATH"); + if (executable.isEmpty()) + return QString(); + QFileInfo fi(executable); + if (fi.isAbsolute() && fi.exists()) + return executable; +#ifdef Q_OS_WIN + if (!executable.endsWith(QLatin1String(".exe"))) + executable.append(QLatin1String(".exe")); +#endif + const QChar slash = QLatin1Char('/'); + foreach (const QString &p, path()) { +// qDebug()<<"trying"<<p + '/' + executable; + QString fp = p; + fp += slash; + fp += executable; + const QFileInfo fi(fp); + if (fi.exists()) { +// qDebug()<<"returning "<<fi.absoluteFilePath(); + return fi.absoluteFilePath(); + } + } + return QString(); +} + +QStringList Environment::path() const +{ +#ifdef Q_OS_WIN + const QChar sep = QLatin1Char(';'); +#else + const QChar sep = QLatin1Char(':'); +#endif + return m_values.value(QLatin1String("PATH")).split(sep, QString::SkipEmptyParts); +} + +QString Environment::value(const QString &key) const +{ + return m_values.value(key); +} + +QString Environment::key(Environment::const_iterator it) const +{ + return it.key(); +} + +QString Environment::value(Environment::const_iterator it) const +{ + return it.value(); +} + +Environment::const_iterator Environment::constBegin() const +{ + return m_values.constBegin(); +} + +Environment::const_iterator Environment::constEnd() const +{ + return m_values.constEnd(); +} + +Environment::const_iterator Environment::find(const QString &name) +{ + QMap<QString, QString>::const_iterator it = m_values.constFind(name); + if (it == m_values.constEnd()) + return constEnd(); + else + return it; +} + +int Environment::size() const +{ + return m_values.size(); +} + +void Environment::modify(const QList<EnvironmentItem> & list) +{ + Environment resultEnvironment = *this; + foreach (const EnvironmentItem &item, list) { + if (item.unset) { + resultEnvironment.unset(item.name); + } else { + // TODO use variable expansion + QString value = item.value; + for (int i=0; i < value.size(); ++i) { + if (value.at(i) == QLatin1Char('$')) { + if ((i + 1) < value.size()) { + const QChar &c = value.at(i+1); + int end = -1; + if (c == '(') + end = value.indexOf(')', i); + else if (c == '{') + end = value.indexOf('}', i); + if (end != -1) { + const QString &name = value.mid(i+2, end-i-2); + Environment::const_iterator it = find(name); + if (it != constEnd()) + value.replace(i, end-i+1, it.value()); + } + } + } + } + resultEnvironment.set(item.name, value); + } + } + *this = resultEnvironment; +} + +bool Environment::hasKey(const QString &key) +{ + return m_values.contains(key); +} + +bool Environment::operator!=(const Environment &other) const +{ + return !(*this == other); +} + +bool Environment::operator==(const Environment &other) const +{ + return m_values == other.m_values; +} + +QStringList Environment::parseCombinedArgString(const QString &program) +{ + QStringList args; + QString tmp; + int quoteCount = 0; + bool inQuote = false; + + // handle quoting. tokens can be surrounded by double quotes + // "hello world". three consecutive double quotes represent + // the quote character itself. + for (int i = 0; i < program.size(); ++i) { + if (program.at(i) == QLatin1Char('"')) { + ++quoteCount; + if (quoteCount == 3) { + // third consecutive quote + quoteCount = 0; + tmp += program.at(i); + } + continue; + } + if (quoteCount) { + if (quoteCount == 1) + inQuote = !inQuote; + quoteCount = 0; + } + if (!inQuote && program.at(i).isSpace()) { + if (!tmp.isEmpty()) { + args += tmp; + tmp.clear(); + } + } else { + tmp += program.at(i); + } + } + if (!tmp.isEmpty()) + args += tmp; + return args; +} + +QString Environment::joinArgumentList(const QStringList &arguments) +{ + QString result; + const QChar doubleQuote = QLatin1Char('"'); + foreach (QString arg, arguments) { + if (!result.isEmpty()) + result += QLatin1Char(' '); + arg.replace(QString(doubleQuote), QLatin1String("\"\"\"")); + if (arg.contains(QLatin1Char(' '))) { + arg.insert(0, doubleQuote); + arg += doubleQuote; + } + result += arg; + } + return result; +} + +enum State { BASE, VARIABLE, OPTIONALVARIABLEBRACE, STRING, STRING_ESCAPE, ESCAPE }; + +/** Expand environment variables in a string. + * + * Environment variables are accepted in the following forms: + * $SOMEVAR, ${SOMEVAR} and %SOMEVAR%. + * + * The following escape sequences are supported: + * "\$", "\\" and "\"" which will be replaced by '$', '\' and '%' + * respectively. + * + * Strings enclosed in '"' characters do not get varaibles + * substituted. Escape codes are processed though. + * + */ +QString Environment::expandVariables(const QString &input) const +{ + QString result; + QString variable; + QChar endVariable; + State state = BASE; + + int length = input.count(); + for (int i = 0; i < length; ++i) { + QChar c = input.at(i); + if (state == BASE) { + if (c == '\\') { + state = ESCAPE; + } else if (c == '$') { + state = OPTIONALVARIABLEBRACE; + variable.clear(); + endVariable = QChar(0); + } else if (c == '%') { + state = VARIABLE; + variable.clear(); + endVariable = '%'; + } else if (c == '\"') { + state = STRING; + result += c; + } else { + result += c; + } + } else if (state == VARIABLE) { + if (c == endVariable) { + result += value(variable); + state = BASE; + } else if (c.isLetterOrNumber() || c == '_') { + variable += c; + } else { + result += value(variable); + result += c; + state = BASE; + } + } else if (state == OPTIONALVARIABLEBRACE) { + if (c == '{') + endVariable = '}'; + else + variable = c; + state = VARIABLE; + } else if (state == STRING) { + if (c == '\\') { + state = STRING_ESCAPE; + } else if (c == '\"') { + state = BASE; + result += c; + } else { + result += c; + } + } else if (state == STRING_ESCAPE) { + result += c; + state = STRING; + } else if (state == ESCAPE){ + result += c; + state = BASE; + } + } + if (state == VARIABLE) + result += value(variable); + return result; +} diff --git a/src/libs/utils/environment.h b/src/libs/utils/environment.h new file mode 100644 index 00000000000..1177c4dc1c1 --- /dev/null +++ b/src/libs/utils/environment.h @@ -0,0 +1,109 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation ([email protected]) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef UTILS_ENVIRONMENT_H +#define UTILS_ENVIRONMENT_H + +#include "utils_global.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QMap> +#include <QtCore/QList> + +namespace Utils { + +class QTCREATOR_UTILS_EXPORT EnvironmentItem +{ +public: + EnvironmentItem(QString n, QString v) + : name(n), value(v), unset(false) + {} + + QString name; + QString value; + bool unset; + + bool operator==(const EnvironmentItem &other) + { + return (unset == other.unset) && (name == other.name) && (value == other.value); + } + + static QList<EnvironmentItem> fromStringList(QStringList list); + static QStringList toStringList(QList<EnvironmentItem> list); +}; + +class QTCREATOR_UTILS_EXPORT Environment { +public: + typedef QMap<QString, QString>::const_iterator const_iterator; + + Environment(); + explicit Environment(QStringList env); + static Environment systemEnvironment(); + + QStringList toStringList() const; + QString value(const QString &key) const; + void set(const QString &key, const QString &value); + void unset(const QString &key); + void modify(const QList<EnvironmentItem> & list); + bool hasKey(const QString &key); + + void appendOrSet(const QString &key, const QString &value, const QString &sep = QString()); + void prependOrSet(const QString &key, const QString &value, const QString &sep = QString()); + + void appendOrSetPath(const QString &value); + void prependOrSetPath(const QString &value); + + void clear(); + int size() const; + + Environment::const_iterator find(const QString &name); + QString key(Environment::const_iterator it) const; + QString value(Environment::const_iterator it) const; + + Environment::const_iterator constBegin() const; + Environment::const_iterator constEnd() const; + + QString searchInPath(QString executable) const; + QStringList path() const; + + static QStringList parseCombinedArgString(const QString &program); + static QString joinArgumentList(const QStringList &arguments); + + QString expandVariables(const QString &) const; + + bool operator!=(const Environment &other) const; + bool operator==(const Environment &other) const; +private: + QMap<QString, QString> m_values; +}; + +} // namespace Utils + +#endif // UTILS_ENVIRONMENT_H diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index d338913edf3..bfae91f6345 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -6,7 +6,8 @@ dll { INCLUDEPATH += $$PWD -SOURCES += $$PWD/reloadpromptutils.cpp \ +SOURCES += $$PWD/environment.cpp \ + $$PWD/reloadpromptutils.cpp \ $$PWD/stringutils.cpp \ $$PWD/filesearch.cpp \ $$PWD/pathchooser.cpp \ @@ -61,7 +62,8 @@ unix:!macx { HEADERS += $$PWD/unixutils.h SOURCES += $$PWD/unixutils.cpp } -HEADERS += $$PWD/utils_global.h \ +HEADERS += $$PWD/environment.h \ + $$PWD/utils_global.h \ $$PWD/reloadpromptutils.h \ $$PWD/stringutils.h \ $$PWD/filesearch.h \ |