summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/src/snippets/qprocess-environment/main.cpp6
-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
-rw-r--r--tests/auto/qprocess/tst_qprocess.cpp37
7 files changed, 300 insertions, 86 deletions
diff --git a/doc/src/snippets/qprocess-environment/main.cpp b/doc/src/snippets/qprocess-environment/main.cpp
index a143bf8..0fa0896 100644
--- a/doc/src/snippets/qprocess-environment/main.cpp
+++ b/doc/src/snippets/qprocess-environment/main.cpp
@@ -57,10 +57,10 @@ process.start("myapp");
{
//! [1]
QProcess process;
-QHash<QString, QString> env = QProcess::systemEnvironmentHash();
+QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
env.insert("TMPDIR", "C:\\MyApp\\temp"); // Add an environment variable
-env["PATH"] += ";C:\\Bin";
-process.setEnvironment(env);
+env.insert("PATH", env.value("Path") + ";C:\\Bin");
+process.setProcessEnvironment(env);
process.start("myapp");
//! [1]
}
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);
diff --git a/tests/auto/qprocess/tst_qprocess.cpp b/tests/auto/qprocess/tst_qprocess.cpp
index b57139b..d2af86a 100644
--- a/tests/auto/qprocess/tst_qprocess.cpp
+++ b/tests/auto/qprocess/tst_qprocess.cpp
@@ -130,6 +130,8 @@ private slots:
void exitCodeTest();
void setEnvironment_data();
void setEnvironment();
+ void setProcessEnvironment_data();
+ void setProcessEnvironment();
void systemEnvironment();
void spaceInName();
void lockupsInStartDetached();
@@ -1697,16 +1699,39 @@ void tst_QProcess::setEnvironment()
QCOMPARE(process.readAll(), value.toLocal8Bit());
}
+#endif
+}
+
+//-----------------------------------------------------------------------------
+void tst_QProcess::setProcessEnvironment_data()
+{
+ setEnvironment_data();
+}
+
+void tst_QProcess::setProcessEnvironment()
+{
+#if !defined (Q_OS_WINCE)
+ // there is no concept of system variables on Windows CE as there is no console
+
+ // make sure our environment variables are correct
+ QVERIFY(qgetenv("tst_QProcess").isEmpty());
+ QVERIFY(!qgetenv("PATH").isEmpty());
+#ifdef Q_OS_WIN
+ QVERIFY(!qgetenv("PROMPT").isEmpty());
+#endif
+
+ QFETCH(QString, name);
+ QFETCH(QString, value);
+ QString executable = QDir::currentPath() + "/testProcessEnvironment/testProcessEnvironment";
- // use the hash variant now
{
QProcess process;
- QHash<QString, QString> environment = QProcess::systemEnvironmentHash();
+ QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
if (value.isNull())
environment.remove(name);
else
environment.insert(name, value);
- process.setEnvironmentHash(environment);
+ process.setProcessEnvironment(environment);
process.start(executable, QStringList() << name);
QVERIFY(process.waitForFinished());
@@ -1725,12 +1750,12 @@ void tst_QProcess::systemEnvironment()
#if defined (Q_OS_WINCE)
// there is no concept of system variables on Windows CE as there is no console
QVERIFY(QProcess::systemEnvironment().isEmpty());
- QVERIFY(QProcess::systemEnvironmentHash().isEmpty());
+ QVERIFY(QProcessEnvironment::systemEnvironment().isEmpty());
#else
QVERIFY(!QProcess::systemEnvironment().isEmpty());
- QVERIFY(!QProcess::systemEnvironmentHash().isEmpty());
+ QVERIFY(!QProcessEnvironment::systemEnvironment().isEmpty());
- QVERIFY(QProcess::systemEnvironmentHash().contains("PATH"));
+ QVERIFY(QProcessEnvironment::systemEnvironment().contains("PATH"));
QVERIFY(!QProcess::systemEnvironment().filter(QRegExp("^PATH=", Qt::CaseInsensitive)).isEmpty());
#endif
}