1 /**************************************************************************
3 ** This file is part of Qt Creator
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights. These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
32 **************************************************************************/
34 #include "environment.h"
36 #include <QtCore/QProcess>
37 #include <QtCore/QDir>
38 #include <QtCore/QString>
40 using namespace Utils;
42 QList<EnvironmentItem> EnvironmentItem::fromStringList(QStringList list)
44 QList<EnvironmentItem> result;
45 foreach (const QString &string, list) {
46 int pos = string.indexOf(QLatin1Char('='));
48 EnvironmentItem item(string, QString());
52 EnvironmentItem item(string.left(pos), string.mid(pos+1));
59 QStringList EnvironmentItem::toStringList(QList<EnvironmentItem> list)
62 foreach (const EnvironmentItem &item, list) {
64 result << QString(item.name);
66 result << QString(item.name + '=' + item.value);
71 Environment::Environment()
75 Environment::Environment(QStringList env)
77 foreach (const QString &s, env) {
78 int i = s.indexOf("=");
81 m_values.insert(s.left(i).toUpper(), s.mid(i+1));
83 m_values.insert(s.left(i), s.mid(i+1));
89 QStringList Environment::toStringList() const
92 const QMap<QString, QString>::const_iterator end = m_values.constEnd();
93 for (QMap<QString, QString>::const_iterator it = m_values.constBegin(); it != end; ++it) {
94 QString entry = it.key();
95 entry += QLatin1Char('=');
97 result.push_back(entry);
102 void Environment::set(const QString &key, const QString &value)
105 QString _key = key.toUpper();
107 const QString &_key = key;
109 m_values.insert(_key, value);
112 void Environment::unset(const QString &key)
115 QString _key = key.toUpper();
117 const QString &_key = key;
119 m_values.remove(_key);
122 void Environment::appendOrSet(const QString &key, const QString &value, const QString &sep)
125 QString _key = key.toUpper();
127 const QString &_key = key;
129 QMap<QString, QString>::iterator it = m_values.find(key);
130 if (it == m_values.end()) {
131 m_values.insert(_key, value);
133 // Append unless it is already there
134 const QString toAppend = sep + value;
135 if (!it.value().endsWith(toAppend))
136 it.value().append(toAppend);
140 void Environment::prependOrSet(const QString&key, const QString &value, const QString &sep)
143 QString _key = key.toUpper();
145 const QString &_key = key;
147 QMap<QString, QString>::iterator it = m_values.find(key);
148 if (it == m_values.end()) {
149 m_values.insert(_key, value);
151 // Prepend unless it is already there
152 const QString toPrepend = value + sep;
153 if (!it.value().startsWith(toPrepend))
154 it.value().prepend(toPrepend);
158 void Environment::appendOrSetPath(const QString &value)
161 const QChar sep = QLatin1Char(';');
163 const QChar sep = QLatin1Char(':');
165 appendOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep));
168 void Environment::prependOrSetPath(const QString &value)
171 const QChar sep = QLatin1Char(';');
173 const QChar sep = QLatin1Char(':');
175 prependOrSet(QLatin1String("PATH"), QDir::toNativeSeparators(value), QString(sep));
178 Environment Environment::systemEnvironment()
180 return Environment(QProcess::systemEnvironment());
183 void Environment::clear()
188 QString Environment::searchInPath(const QString &executable,
189 const QStringList &additionalDirs) const
194 // Check all the executable extensions on windows:
195 QStringList extensions = value(QLatin1String("PATHEXT")).split(QLatin1Char(';'));
197 // .exe.bat is legal (and run when starting new.exe), so always go through the complete list once:
198 foreach (const QString &ext, extensions)
199 execs << executable + ext.toLower();
201 return searchInPath(execs, additionalDirs);
204 QString Environment::searchInPath(const QStringList &executables,
205 const QStringList &additionalDirs) const
207 foreach (const QString &executable, executables) {
208 QString exec = expandVariables(executable);
213 QFileInfo baseFi(exec);
214 if (baseFi.isAbsolute() && baseFi.exists())
215 return QDir::toNativeSeparators(exec);
217 // Check in directories:
218 foreach (const QString &dir, additionalDirs) {
221 QFileInfo fi(dir + QLatin1Char('/') + exec);
222 if (fi.isFile() && fi.isExecutable())
223 return fi.absoluteFilePath();
227 const QChar slash = QLatin1Char('/');
228 if (exec.indexOf(slash) != -1)
230 foreach (const QString &p, path()) {
234 const QFileInfo fi(fp);
236 return fi.absoluteFilePath();
242 QStringList Environment::path() const
245 const QChar sep = QLatin1Char(';');
247 const QChar sep = QLatin1Char(':');
249 return m_values.value(QLatin1String("PATH")).split(sep, QString::SkipEmptyParts);
252 QString Environment::value(const QString &key) const
254 return m_values.value(key);
257 QString Environment::key(Environment::const_iterator it) const
262 QString Environment::value(Environment::const_iterator it) const
267 Environment::const_iterator Environment::constBegin() const
269 return m_values.constBegin();
272 Environment::const_iterator Environment::constEnd() const
274 return m_values.constEnd();
277 Environment::const_iterator Environment::constFind(const QString &name) const
279 QMap<QString, QString>::const_iterator it = m_values.constFind(name);
280 if (it == m_values.constEnd())
286 int Environment::size() const
288 return m_values.size();
291 void Environment::modify(const QList<EnvironmentItem> & list)
293 Environment resultEnvironment = *this;
294 foreach (const EnvironmentItem &item, list) {
296 resultEnvironment.unset(item.name);
298 // TODO use variable expansion
299 QString value = item.value;
300 for (int i=0; i < value.size(); ++i) {
301 if (value.at(i) == QLatin1Char('$')) {
302 if ((i + 1) < value.size()) {
303 const QChar &c = value.at(i+1);
306 end = value.indexOf(')', i);
308 end = value.indexOf('}', i);
310 const QString &name = value.mid(i+2, end-i-2);
311 Environment::const_iterator it = constFind(name);
312 if (it != constEnd())
313 value.replace(i, end-i+1, it.value());
318 resultEnvironment.set(item.name, value);
321 *this = resultEnvironment;
324 bool Environment::hasKey(const QString &key)
326 return m_values.contains(key);
329 bool Environment::operator!=(const Environment &other) const
331 return !(*this == other);
334 bool Environment::operator==(const Environment &other) const
336 return m_values == other.m_values;
339 /** Expand environment variables in a string.
341 * Environment variables are accepted in the following forms:
342 * $SOMEVAR, ${SOMEVAR} on Unix and %SOMEVAR% on Windows.
343 * No escapes and quoting are supported.
344 * If a variable is not found, it is not substituted.
346 QString Environment::expandVariables(const QString &input) const
348 QString result = input;
351 for (int vStart = -1, i = 0; i < result.length(); ) {
352 if (result.at(i++) == QLatin1Char('%')) {
354 const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1).toUpper());
355 if (it != m_values.constEnd()) {
356 result.replace(vStart - 1, i - vStart + 1, *it);
357 i = vStart - 1 + it->length();
368 enum { BASE, OPTIONALVARIABLEBRACE, VARIABLE, BRACEDVARIABLE } state = BASE;
371 for (int i = 0; i < result.length();) {
372 QChar c = result.at(i++);
374 if (c == QLatin1Char('$'))
375 state = OPTIONALVARIABLEBRACE;
376 } else if (state == OPTIONALVARIABLEBRACE) {
377 if (c == QLatin1Char('{')) {
378 state = BRACEDVARIABLE;
380 } else if (c.isLetterOrNumber() || c == QLatin1Char('_')) {
386 } else if (state == BRACEDVARIABLE) {
387 if (c == QLatin1Char('}')) {
388 const_iterator it = m_values.constFind(result.mid(vStart, i - 1 - vStart));
389 if (it != constEnd()) {
390 result.replace(vStart - 2, i - vStart + 2, *it);
391 i = vStart - 2 + it->length();
395 } else if (state == VARIABLE) {
396 if (!c.isLetterOrNumber() && c != QLatin1Char('_')) {
397 const_iterator it = m_values.constFind(result.mid(vStart, i - vStart - 1));
398 if (it != constEnd()) {
399 result.replace(vStart - 1, i - vStart, *it);
400 i = vStart - 1 + it->length();
406 if (state == VARIABLE) {
407 const_iterator it = m_values.constFind(result.mid(vStart));
408 if (it != constEnd())
409 result.replace(vStart - 1, result.length() - vStart + 1, *it);
415 QStringList Environment::expandVariables(const QStringList &variables) const
418 foreach (const QString & i, variables)
419 results << expandVariables(i);