summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@nokia.com>2008-11-25 15:44:11 (GMT)
committerThiago Macieira <thiago.macieira@nokia.com>2009-08-21 13:03:05 (GMT)
commit02ef8fab7e511f50e901676eac15229eb456b01c (patch)
tree107d58effefa02942f3a715b8b60894852aee83d /src/corelib
parentf13908359f08d856c2825988e65651dbf744c0e4 (diff)
downloadQt-02ef8fab7e511f50e901676eac15229eb456b01c.zip
Qt-02ef8fab7e511f50e901676eac15229eb456b01c.tar.gz
Qt-02ef8fab7e511f50e901676eac15229eb456b01c.tar.bz2
Add a new class for handling a process's environment variables.
First of all, make it a lot easier to access individual variables by having them in an associative container (a QHash). This fixes task 232427, albeit one release later than I had originally planned. On Windows, the variable names in the environment are case-insensitive, so a direct QHash isn't a good solution. Implement code that does the uppercasing on Windows and leaves untransformed on other platforms. Since we're doing this anyways, use QByteArray on Unix systems, since, in theory, the environment could contain any random binary data, which is not representable in QString. Task-number: 232427
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/io/qprocess.cpp242
-rw-r--r--src/corelib/io/qprocess.h44
-rw-r--r--src/corelib/io/qprocess_p.h17
-rw-r--r--src/corelib/io/qprocess_unix.cpp26
-rw-r--r--src/corelib/io/qprocess_win.cpp14
5 files changed, 266 insertions, 77 deletions
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index ccc16b2..3d143e9 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -101,27 +101,169 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
-static QHash<QString, QString> environmentHashFromList(const QStringList &environment)
+#ifdef Q_OS_WIN
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QString &name)
+{ return name.toUpper(); }
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QByteArray &name)
+{ return QString::fromLocal8Bit(name).toUpper(); }
+static inline QString nameToString(const QProcessEnvironmentPrivate::Unit &name)
+{ return name; }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QString &value)
+{ return value; }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QByteArray &value)
+{ return QString::fromLocal8Bit(value); }
+static inline QString valueToString(const QProcessEnvironmentPrivate::Unit &value)
+{ return value; }
+static inline QByteArray valueToByteArray(const QProcessEnvironmentPrivate::Unit &value)
+{ return value.toLocal8Bit(); }
+#else
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QByteArray &name)
+{ return name; }
+static inline QProcessEnvironmentPrivate::Unit prepareName(const QString &name)
+{ return name.toLocal8Bit(); }
+static inline QString nameToString(const QProcessEnvironmentPrivate::Unit &name)
+{ return QString::fromLocal8Bit(name); }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QByteArray &value)
+{ return value; }
+static inline QProcessEnvironmentPrivate::Unit prepareValue(const QString &value)
+{ return value.toLocal8Bit(); }
+static inline QString valueToString(const QProcessEnvironmentPrivate::Unit &value)
+{ return QString::fromLocal8Bit(value); }
+static inline QByteArray valueToByteArray(const QProcessEnvironmentPrivate::Unit &value)
+{ return value; }
+#endif
+
+template<> void QSharedDataPointer<QProcessEnvironmentPrivate>::detach()
{
- QHash<QString, QString> result;
- QStringList::ConstIterator it = environment.constBegin(),
- end = environment.constEnd();
+ if (d && d->ref == 1)
+ return;
+ QProcessEnvironmentPrivate *x = (d ? new QProcessEnvironmentPrivate(*d)
+ : new QProcessEnvironmentPrivate);
+ x->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = x;
+}
+
+QStringList QProcessEnvironmentPrivate::toList() const
+{
+ QStringList result;
+ QHash<Unit, Unit>::ConstIterator it = hash.constBegin(),
+ end = hash.constEnd();
for ( ; it != end; ++it) {
- int equals = it->indexOf(QLatin1Char('='));
+ QString data = nameToString(it.key());
+ QString value = valueToString(it.value());
+ data.reserve(data.length() + value.length() + 1);
+ data.append(QLatin1Char('='));
+ data.append(value);
+ result << data;
+ }
+ return result;
+}
+
+QProcessEnvironment QProcessEnvironmentPrivate::fromList(const QStringList &list)
+{
+ QProcessEnvironment env;
+ QStringList::ConstIterator it = list.constBegin(),
+ end = list.constEnd();
+ for ( ; it != end; ++it) {
+ int pos = it->indexOf(QLatin1Char('='));
+ if (pos < 1)
+ continue;
+ QString value = it->mid(pos + 1);
QString name = *it;
- QString value;
- if (equals != -1) {
- name.truncate(equals);
-#ifdef Q_OS_WIN
- name = name.toUpper();
-#endif
- value = it->mid(equals + 1);
- }
- result.insert(name, value);
+ name.truncate(pos);
+ env.insert(name, value);
}
+ return env;
+}
- return result;
+QProcessEnvironment::QProcessEnvironment()
+ : d(0)
+{
+}
+
+QProcessEnvironment::~QProcessEnvironment()
+{
+}
+
+QProcessEnvironment::QProcessEnvironment(const QProcessEnvironment &other)
+ : d(other.d)
+{
+}
+
+QProcessEnvironment &QProcessEnvironment::operator=(const QProcessEnvironment &other)
+{
+ d = other.d;
+ return *this;
+}
+
+bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const
+{
+ return d->hash == other.d->hash;
+}
+
+bool QProcessEnvironment::isEmpty() const
+{
+ return d ? d->hash.isEmpty() : true;
+}
+
+void QProcessEnvironment::clear()
+{
+ d->hash.clear();
+}
+
+bool QProcessEnvironment::contains(const QString &name) const
+{
+ return d ? d->hash.contains(prepareName(name)) : false;
+}
+
+void QProcessEnvironment::insert(const QString &name, const QString &value)
+{
+ d->hash.insert(prepareName(name), prepareValue(value));
+}
+
+void QProcessEnvironment::remove(const QString &name)
+{
+ d->hash.remove(prepareName(name));
+}
+
+QString QProcessEnvironment::value(const QString &name, const QString &defaultValue) const
+{
+ if (!d)
+ return defaultValue;
+
+ QProcessEnvironmentPrivate::Unit result = d->hash.value(prepareName(name), prepareValue(defaultValue));
+ return valueToString(result);
+}
+
+bool QProcessEnvironment::containsRaw(const QByteArray &name) const
+{
+ return d ? d->hash.contains(prepareName(name)) : false;
+}
+
+void QProcessEnvironment::insertRaw(const QByteArray &name, const QByteArray &value)
+{
+ d->hash.insert(prepareName(name), prepareValue(value));
+}
+
+void QProcessEnvironment::removeRaw(const QByteArray &name)
+{
+ d->hash.remove(prepareName(name));
+}
+
+QByteArray QProcessEnvironment::valueRaw(const QByteArray &name, const QByteArray &defaultValue) const
+{
+ if (!d)
+ return defaultValue;
+ QProcessEnvironmentPrivate::Unit result = d->hash.value(prepareName(name), prepareValue(defaultValue));
+ return valueToByteArray(result);
+}
+
+QStringList QProcessEnvironment::toStringList() const
+{
+ return d ? d->toList() : QStringList();
}
void QProcessPrivate::Channel::clear()
@@ -446,7 +588,6 @@ QProcessPrivate::QProcessPrivate()
sequenceNumber = 0;
exitCode = 0;
exitStatus = QProcess::NormalExit;
- environment = 0;
startupSocketNotifier = 0;
deathNotifier = 0;
notifier = 0;
@@ -473,7 +614,6 @@ QProcessPrivate::QProcessPrivate()
*/
QProcessPrivate::~QProcessPrivate()
{
- delete environment;
if (stdinChannel.process)
stdinChannel.process->stdoutChannel.clear();
if (stdoutChannel.process)
@@ -1215,6 +1355,7 @@ QProcess::ProcessState QProcess::state() const
}
/*!
+ \deprecated
Sets the environment that QProcess will use when starting a process to the
\a environment specified which consists of a list of key=value pairs.
@@ -1223,14 +1364,15 @@ QProcess::ProcessState QProcess::state() const
\snippet doc/src/snippets/qprocess-environment/main.cpp 0
- \sa environment(), systemEnvironment(), setEnvironmentHash()
+ \sa environment(), setProcessEnvironment(), systemEnvironment()
*/
void QProcess::setEnvironment(const QStringList &environment)
{
- setEnvironmentHash(environmentHashFromList(environment));
+ setProcessEnvironment(QProcessEnvironmentPrivate::fromList(environment));
}
/*!
+ \deprecated
Returns the environment that QProcess will use when starting a
process, or an empty QStringList if no environment has been set
using setEnvironment() or setEnvironmentHash(). If no environment
@@ -1239,67 +1381,50 @@ void QProcess::setEnvironment(const QStringList &environment)
\note The environment settings are ignored on Windows CE,
as there is no concept of an environment.
- \sa environmentHash(), setEnvironment(), systemEnvironment()
+ \sa processEnvironment(), setEnvironment(), systemEnvironment()
*/
QStringList QProcess::environment() const
{
Q_D(const QProcess);
-
- QStringList result;
- if (!d->environment)
- return result;
-
- QHash<QString, QString>::ConstIterator it = d->environment->constBegin(),
- end = d->environment->constEnd();
- for ( ; it != end; ++it) {
- QString data = it.key();
- data.reserve(data.length() + it.value().length() + 1);
- data.append(QLatin1Char('='));
- data.append(it.value());
- result << data;
- }
- return result;
+ return d->environment.toStringList();
}
/*!
\since 4.5
Sets the environment that QProcess will use when starting a process to the
- \a environment hash map.
+ \a environment object.
For example, the following code adds the \c{C:\\BIN} directory to the list of
executable paths (\c{PATHS}) on Windows and sets \c{TMPDIR}:
\snippet doc/src/snippets/qprocess-environment/main.cpp 1
- \sa environment(), systemEnvironmentHash(), setEnvironment()
+ Note how, on Windows, environment variable names are case-insensitive.
+
+ \sa processEnvironment(), QProcessEnvironment::systemEnvironment(), setEnvironment()
*/
-void QProcess::setEnvironmentHash(const QHash<QString, QString> &environment)
+void QProcess::setProcessEnvironment(const QProcessEnvironment &environment)
{
Q_D(QProcess);
- if (!d->environment)
- d->environment = new QHash<QString, QString>(environment);
- else
- *d->environment = environment;
+ d->environment = environment;
}
/*!
\since 4.5
Returns the environment that QProcess will use when starting a
- process, or an empty QHash if no environment has been set using
- setEnvironment() or setEnvironmentHash(). If no environment has
+ process, or an empty object if no environment has been set using
+ setEnvironment() or setProcessEnvironment(). If no environment has
been set, the environment of the calling process will be used.
\note The environment settings are ignored on Windows CE,
as there is no concept of an environment.
- \sa setEnvironmentHash(), setEnvironment(), systemEnvironmentHash()
+ \sa setProcessEnvironment(), setEnvironment(), QProcessEnvironment::isValid()
*/
-QHash<QString, QString> QProcess::environmentHash() const
+QProcessEnvironment QProcess::processEnvironment() const
{
Q_D(const QProcess);
- if (d->environment)
- return *d->environment;
- return QHash<QString, QString>();
+ return d->environment;
}
/*!
@@ -1898,7 +2023,7 @@ QT_END_INCLUDE_NAMESPACE
\snippet doc/src/snippets/code/src_corelib_io_qprocess.cpp 8
- \sa systemEnvironmentHash(), environment(), setEnvironment()
+ \sa QProcessEnvironment::systemEnvironment(), environment(), setEnvironment()
*/
QStringList QProcess::systemEnvironment()
{
@@ -1915,11 +2040,22 @@ QStringList QProcess::systemEnvironment()
Returns the environment of the calling process as a QHash.
- \sa systemEnvironment(), environmentHash(), setEnvironmentHash()
+ \sa QProcess::systemEnvironment()
*/
-QHash<QString, QString> QProcess::systemEnvironmentHash()
+QProcessEnvironment QProcessEnvironment::systemEnvironment()
{
- return environmentHashFromList(systemEnvironment());
+ QProcessEnvironment env;
+ const char *entry;
+ for (int count = 0; (entry = environ[count]); ++count) {
+ const char *equal = strchr(entry, '=');
+ if (!equal)
+ continue;
+
+ QByteArray name(entry, equal - entry);
+ QByteArray value(equal + 1);
+ env.insertRaw(name, value);
+ }
+ return env;
}
/*!
diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h
index 096f625..116168b 100644
--- a/src/corelib/io/qprocess.h
+++ b/src/corelib/io/qprocess.h
@@ -44,6 +44,7 @@
#include <QtCore/qiodevice.h>
#include <QtCore/qstringlist.h>
+#include <QtCore/qshareddata.h>
QT_BEGIN_HEADER
@@ -53,8 +54,6 @@ QT_MODULE(Core)
#ifndef QT_NO_PROCESS
-template <class Key, class T> class QHash;
-
#if (!defined(Q_OS_WIN32) && !defined(Q_OS_WINCE)) || defined(qdoc)
typedef qint64 Q_PID;
#else
@@ -64,6 +63,42 @@ QT_BEGIN_NAMESPACE
#endif
class QProcessPrivate;
+class QProcessEnvironmentPrivate;
+
+class Q_CORE_EXPORT QProcessEnvironment
+{
+public:
+ QProcessEnvironment();
+ QProcessEnvironment(const QProcessEnvironment &other);
+ ~QProcessEnvironment();
+ QProcessEnvironment &operator=(const QProcessEnvironment &other);
+
+ bool operator==(const QProcessEnvironment &other) const;
+ inline bool operator!=(const QProcessEnvironment &other) const
+ { return !(*this == other); }
+
+ bool isEmpty() const;
+ void clear();
+
+ bool contains(const QString &name) const;
+ void insert(const QString &name, const QString &value);
+ void remove(const QString &name);
+ QString value(const QString &name, const QString &defaultValue = QString()) const;
+
+ bool containsRaw(const QByteArray &name) const;
+ void insertRaw(const QByteArray &name, const QByteArray &value);
+ void removeRaw(const QByteArray &name);
+ QByteArray valueRaw(const QByteArray &name, const QByteArray &defaultValue = QByteArray()) const;
+
+ QStringList toStringList() const;
+
+ static QProcessEnvironment systemEnvironment();
+
+private:
+ friend class QProcessPrivate;
+ friend class QProcessEnvironmentPrivate;
+ QSharedDataPointer<QProcessEnvironmentPrivate> d;
+};
class Q_CORE_EXPORT QProcess : public QIODevice
{
@@ -123,8 +158,8 @@ public:
void setEnvironment(const QStringList &environment);
QStringList environment() const;
- void setEnvironmentHash(const QHash<QString, QString> &environment);
- QHash<QString, QString> environmentHash() const;
+ void setProcessEnvironment(const QProcessEnvironment &environment);
+ QProcessEnvironment processEnvironment() const;
QProcess::ProcessError error() const;
QProcess::ProcessState state() const;
@@ -160,7 +195,6 @@ public:
static bool startDetached(const QString &program);
static QStringList systemEnvironment();
- static QHash<QString, QString> systemEnvironmentHash();
public Q_SLOTS:
void terminate();
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 5482871..3b04d88 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -55,6 +55,7 @@
#include "QtCore/qprocess.h"
#include "QtCore/qstringlist.h"
+#include "QtCore/qhash.h"
#include "private/qringbuffer_p.h"
#include "private/qiodevice_p.h"
@@ -76,6 +77,20 @@ class QWindowsPipeWriter;
class QWinEventNotifier;
class QTimer;
+class QProcessEnvironmentPrivate: public QSharedData
+{
+public:
+#ifdef Q_OS_WIN
+ typedef QString Unit;
+#else
+ typedef QByteArray Unit;
+#endif
+ QHash<Unit, Unit> hash;
+
+ static QProcessEnvironment fromList(const QStringList &list);
+ QStringList toList() const;
+};
+
class QProcessPrivate : public QIODevicePrivate
{
public:
@@ -161,7 +176,7 @@ public:
QString program;
QStringList arguments;
- QHash<QString, QString> *environment;
+ QProcessEnvironment environment;
QRingBuffer outputReadBuffer;
QRingBuffer errorReadBuffer;
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index d28cdc4..dfeeb71 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -458,11 +458,11 @@ bool QProcessPrivate::createChannel(Channel &channel)
}
}
-static char **_q_dupEnvironment(const QHash<QString, QString> *environment, int *envc)
+static char **_q_dupEnvironment(const QHash<QByteArray, QByteArray> &environment, int *envc)
{
*envc = 0;
- if (!environment)
- return 0; // use the default environment
+ if (environment.isEmpty())
+ return 0;
// if LD_LIBRARY_PATH exists in the current environment, but
// not in the environment list passed by the programmer, then
@@ -474,17 +474,17 @@ static char **_q_dupEnvironment(const QHash<QString, QString> *environment, int
#endif
const QByteArray envLibraryPath = qgetenv(libraryPath);
bool needToAddLibraryPath = !envLibraryPath.isEmpty() &&
- !environment->contains(QLatin1String(libraryPath));
+ !environment.contains(libraryPath);
- char **envp = new char *[environment->count() + 2];
- envp[environment->count()] = 0;
- envp[environment->count() + 1] = 0;
+ char **envp = new char *[environment.count() + 2];
+ envp[environment.count()] = 0;
+ envp[environment.count() + 1] = 0;
- QHash<QString, QString>::ConstIterator it = environment->constBegin();
- const QHash<QString, QString>::ConstIterator end = environment->constEnd();
+ QHash<QByteArray, QByteArray>::ConstIterator it = environment.constBegin();
+ const QHash<QByteArray, QByteArray>::ConstIterator end = environment.constEnd();
for ( ; it != end; ++it) {
- QByteArray key = it.key().toLocal8Bit();
- QByteArray value = it.value().toLocal8Bit();
+ QByteArray key = it.key();
+ QByteArray value = it.value();
key.reserve(key.length() + 1 + value.length());
key.append('=');
key.append(value);
@@ -590,7 +590,9 @@ void QProcessPrivate::startProcess()
// Duplicate the environment.
int envc = 0;
- char **envp = _q_dupEnvironment(environment, &envc);
+ char **envp = 0;
+ if (environment.d.constData())
+ envp = _q_dupEnvironment(environment.d.constData()->hash, &envc);
// Encode the working directory if it's non-empty, otherwise just pass 0.
const char *workingDirPtr = 0;
diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp
index acb169f..50a4a00 100644
--- a/src/corelib/io/qprocess_win.cpp
+++ b/src/corelib/io/qprocess_win.cpp
@@ -278,17 +278,17 @@ static QString qt_create_commandline(const QString &program, const QStringList &
return args;
}
-static QByteArray qt_create_environment(const QHash<QString, QString> *environment)
+static QByteArray qt_create_environment(const QHash<QString, QString> &environment)
{
QByteArray envlist;
- if (environment) {
- QHash<QString, QString> copy = *environment;
+ if (!environment.isEmpty()) {
+ QHash<QString, QString> copy = environment;
// add PATH if necessary (for DLL loading)
if (!copy.contains(QLatin1String("PATH"))) {
QByteArray path = qgetenv("PATH");
if (!path.isEmpty())
- copy.insert(QLatin1String("PATH"), QString::fromLocal8Bit(path));
+ copy.insert(QLatin1String("PATH"), QString::fromLocal8Bit(path));
}
// add systemroot if needed
@@ -362,7 +362,9 @@ void QProcessPrivate::startProcess()
QString args = qt_create_commandline(QString(), arguments);
#else
QString args = qt_create_commandline(program, arguments);
- QByteArray envlist = qt_create_environment(environment);
+ QByteArray envlist;
+ if (environment.d.constData())
+ envlist = qt_create_environment(environment.d.constData()->hash);
#endif
#if defined QPROCESS_DEBUG
@@ -393,7 +395,7 @@ void QProcessPrivate::startProcess()
};
success = CreateProcess(0, (wchar_t*)args.utf16(),
0, 0, TRUE, dwCreationFlags,
- environment ? envlist.data() : 0,
+ environment.isEmpty() ? 0 : envlist.data(),
workingDirectory.isEmpty() ? 0 : (wchar_t*)QDir::toNativeSeparators(workingDirectory).utf16(),
&startupInfo, pid);