diff options
-rw-r--r-- | src/corelib/io/qprocess.cpp | 59 | ||||
-rw-r--r-- | src/corelib/io/qprocess.h | 4 | ||||
-rw-r--r-- | src/corelib/io/qprocess_p.h | 2 | ||||
-rw-r--r-- | src/corelib/io/qprocess_win.cpp | 95 | ||||
-rw-r--r-- | tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp | 29 |
5 files changed, 126 insertions, 63 deletions
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 0f2de9e1ff..23c90daff4 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -152,10 +152,27 @@ void QProcessEnvironmentPrivate::insert(const QProcessEnvironmentPrivate &other) empty environment. If set on a QProcess, this will cause the current environment variables to be removed. */ -QProcessEnvironment::QProcessEnvironment() - : d(nullptr) -{ -} +QProcessEnvironment::QProcessEnvironment() : d(new QProcessEnvironmentPrivate) { } + +/*! + Creates an object that when set on QProcess will cause it to be executed with + environment variables inherited from the parent process. + + \note The created object does not store any environment variables by itself, + it just indicates to QProcess to arrange for inheriting the environment at the + time when the new process is started. Adding any environment variables to + the created object will disable inheritance of the environment and result in + an environment containing only the added environment variables. + + If a modified version of the parent environment is wanted, start with the + return value of \c systemEnvironment() and modify that (but note that changes to + the parent process's environment after that is created won't be reflected + in the modified environment). + + \sa inheritsFromParent(), systemEnvironment() + \since 6.3 +*/ +QProcessEnvironment::QProcessEnvironment(QProcessEnvironment::Initialization) : d(nullptr) { } /*! Frees the resources associated with this QProcessEnvironment object. @@ -211,22 +228,18 @@ bool QProcessEnvironment::operator==(const QProcessEnvironment &other) const { if (d == other.d) return true; - if (d) { - if (other.d) { - return d->vars == other.d->vars; - } else { - return isEmpty(); - } - } else { - return other.isEmpty(); - } + + return d && other.d && d->vars == other.d->vars; } /*! Returns \c true if this QProcessEnvironment object is empty: that is there are no key=value pairs set. - \sa clear(), systemEnvironment(), insert() + This method also returns \c true for objects that were constructed using + \c{QProcessEnvironment::InheritFromParent}. + + \sa clear(), systemEnvironment(), insert(), inheritsFromParent() */ bool QProcessEnvironment::isEmpty() const { @@ -235,9 +248,24 @@ bool QProcessEnvironment::isEmpty() const } /*! + Returns \c true if this QProcessEnvironment was constructed using + \c{QProcessEnvironment::InheritFromParent}. + + \since 6.3 + \sa isEmpty() +*/ +bool QProcessEnvironment::inheritsFromParent() const +{ + return !d; +} + +/*! Removes all key=value pairs from this QProcessEnvironment object, making it empty. + If the environment was constructed using \c{QProcessEnvironment::InheritFromParent} + it remains unchanged. + \sa isEmpty(), systemEnvironment() */ void QProcessEnvironment::clear() @@ -341,6 +369,9 @@ QStringList QProcessEnvironment::toStringList() const Returns a list containing all the variable names in this QProcessEnvironment object. + + The returned list is empty for objects constructed using + \c{QProcessEnvironment::InheritFromParent}. */ QStringList QProcessEnvironment::keys() const { diff --git a/src/corelib/io/qprocess.h b/src/corelib/io/qprocess.h index e1b8cc7f57..50740c092b 100644 --- a/src/corelib/io/qprocess.h +++ b/src/corelib/io/qprocess.h @@ -65,7 +65,10 @@ class QProcessEnvironmentPrivate; class Q_CORE_EXPORT QProcessEnvironment { public: + enum Initialization { InheritFromParent }; + QProcessEnvironment(); + QProcessEnvironment(Initialization); QProcessEnvironment(const QProcessEnvironment &other); ~QProcessEnvironment(); QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QProcessEnvironment) @@ -78,6 +81,7 @@ public: { return !(*this == other); } bool isEmpty() const; + [[nodiscard]] bool inheritsFromParent() const; void clear(); bool contains(const QString &name) const; diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h index 4b38f191d5..aec8f458fc 100644 --- a/src/corelib/io/qprocess_p.h +++ b/src/corelib/io/qprocess_p.h @@ -331,7 +331,7 @@ public: #else std::function<void(void)> childProcessModifier; #endif - QProcessEnvironment environment; + QProcessEnvironment environment = QProcessEnvironment::InheritFromParent; #ifdef Q_OS_UNIX Q_PIPE childStartedPipe[2] = {INVALID_Q_PIPE, INVALID_Q_PIPE}; diff --git a/src/corelib/io/qprocess_win.cpp b/src/corelib/io/qprocess_win.cpp index c1084d72a1..d316af7c38 100644 --- a/src/corelib/io/qprocess_win.cpp +++ b/src/corelib/io/qprocess_win.cpp @@ -438,60 +438,59 @@ static QString qt_create_commandline(const QString &program, const QStringList & static QByteArray qt_create_environment(const QProcessEnvironmentPrivate::Map &environment) { QByteArray envlist; - if (!environment.isEmpty()) { - QProcessEnvironmentPrivate::Map copy = environment; - - // add PATH if necessary (for DLL loading) - QProcessEnvironmentPrivate::Key pathKey(QLatin1String("PATH")); - if (!copy.contains(pathKey)) { - QByteArray path = qgetenv("PATH"); - if (!path.isEmpty()) - copy.insert(pathKey, QString::fromLocal8Bit(path)); - } + QProcessEnvironmentPrivate::Map copy = environment; - // add systemroot if needed - QProcessEnvironmentPrivate::Key rootKey(QLatin1String("SystemRoot")); - if (!copy.contains(rootKey)) { - QByteArray systemRoot = qgetenv("SystemRoot"); - if (!systemRoot.isEmpty()) - copy.insert(rootKey, QString::fromLocal8Bit(systemRoot)); - } + // add PATH if necessary (for DLL loading) + QProcessEnvironmentPrivate::Key pathKey(QLatin1String("PATH")); + if (!copy.contains(pathKey)) { + QByteArray path = qgetenv("PATH"); + if (!path.isEmpty()) + copy.insert(pathKey, QString::fromLocal8Bit(path)); + } - qsizetype pos = 0; - auto it = copy.constBegin(); - const auto end = copy.constEnd(); + // add systemroot if needed + QProcessEnvironmentPrivate::Key rootKey(QLatin1String("SystemRoot")); + if (!copy.contains(rootKey)) { + QByteArray systemRoot = qgetenv("SystemRoot"); + if (!systemRoot.isEmpty()) + copy.insert(rootKey, QString::fromLocal8Bit(systemRoot)); + } - static const wchar_t equal = L'='; - static const wchar_t nul = L'\0'; + qsizetype pos = 0; + auto it = copy.constBegin(); + const auto end = copy.constEnd(); - for ( ; it != end; ++it) { - qsizetype tmpSize = sizeof(wchar_t) * (it.key().length() + it.value().length() + 2); - // ignore empty strings - if (tmpSize == sizeof(wchar_t) * 2) - continue; - envlist.resize(envlist.size() + tmpSize); + static const wchar_t equal = L'='; + static const wchar_t nul = L'\0'; - tmpSize = it.key().length() * sizeof(wchar_t); - memcpy(envlist.data()+pos, it.key().utf16(), tmpSize); - pos += tmpSize; + for (; it != end; ++it) { + qsizetype tmpSize = sizeof(wchar_t) * (it.key().length() + it.value().length() + 2); + // ignore empty strings + if (tmpSize == sizeof(wchar_t) * 2) + continue; + envlist.resize(envlist.size() + tmpSize); - memcpy(envlist.data()+pos, &equal, sizeof(wchar_t)); - pos += sizeof(wchar_t); + tmpSize = it.key().length() * sizeof(wchar_t); + memcpy(envlist.data() + pos, it.key().utf16(), tmpSize); + pos += tmpSize; - tmpSize = it.value().length() * sizeof(wchar_t); - memcpy(envlist.data()+pos, it.value().utf16(), tmpSize); - pos += tmpSize; + memcpy(envlist.data() + pos, &equal, sizeof(wchar_t)); + pos += sizeof(wchar_t); - memcpy(envlist.data()+pos, &nul, sizeof(wchar_t)); - pos += sizeof(wchar_t); - } - // add the 2 terminating 0 (actually 4, just to be on the safe side) - envlist.resize( envlist.size()+4 ); - envlist[pos++] = 0; - envlist[pos++] = 0; - envlist[pos++] = 0; - envlist[pos++] = 0; + tmpSize = it.value().length() * sizeof(wchar_t); + memcpy(envlist.data() + pos, it.value().utf16(), tmpSize); + pos += tmpSize; + + memcpy(envlist.data() + pos, &nul, sizeof(wchar_t)); + pos += sizeof(wchar_t); } + // add the 2 terminating 0 (actually 4, just to be on the safe side) + envlist.resize(envlist.size() + 4); + envlist[pos++] = 0; + envlist[pos++] = 0; + envlist[pos++] = 0; + envlist[pos++] = 0; + return envlist; } @@ -564,7 +563,7 @@ void QProcessPrivate::startProcess() const QString args = qt_create_commandline(program, arguments, nativeArguments); QByteArray envlist; - if (environment.d.constData()) + if (!environment.inheritsFromParent()) envlist = qt_create_environment(environment.d.constData()->vars); #if defined QPROCESS_DEBUG @@ -586,7 +585,7 @@ void QProcessPrivate::startProcess() QProcess::CreateProcessArguments cpargs = { nullptr, reinterpret_cast<wchar_t *>(const_cast<ushort *>(args.utf16())), nullptr, nullptr, true, dwCreationFlags, - environment.isEmpty() ? nullptr : envlist.data(), + environment.inheritsFromParent() ? nullptr : envlist.data(), nativeWorkingDirectory.isEmpty() ? nullptr : reinterpret_cast<const wchar_t *>(nativeWorkingDirectory.utf16()), &startupInfo, pid @@ -926,7 +925,7 @@ bool QProcessPrivate::startDetached(qint64 *pid) void *envPtr = nullptr; QByteArray envlist; - if (environment.d.constData()) { + if (!environment.inheritsFromParent()) { envlist = qt_create_environment(environment.d.constData()->vars); envPtr = envlist.data(); } diff --git a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp index e0f598e32e..d1035cb8c2 100644 --- a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp +++ b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp @@ -36,6 +36,7 @@ class tst_QProcessEnvironment: public QObject private slots: void operator_eq(); void clearAndIsEmpty(); + void clearAndInheritsFromParent(); void insert(); void emptyNull(); void toStringList(); @@ -58,6 +59,10 @@ void tst_QProcessEnvironment::operator_eq() QProcessEnvironment e2; QCOMPARE(e1, e2); + auto parentEnv = QProcessEnvironment(QProcessEnvironment::InheritFromParent); + QVERIFY(parentEnv != e2); + QVERIFY(e2 != parentEnv); + e1.clear(); QCOMPARE(e1, e2); @@ -72,15 +77,39 @@ void tst_QProcessEnvironment::operator_eq() e2.insert("FOO", "baz"); QVERIFY(e1 != e2); + + QVERIFY(e2 != parentEnv); + QVERIFY(parentEnv != e2); } void tst_QProcessEnvironment::clearAndIsEmpty() { QProcessEnvironment e; + QVERIFY(e.isEmpty()); + QVERIFY(!e.inheritsFromParent()); + e.insert("FOO", "bar"); + QVERIFY(!e.isEmpty()); + QVERIFY(!e.inheritsFromParent()); + e.clear(); + QVERIFY(e.isEmpty()); + QVERIFY(!e.inheritsFromParent()); +} + +void tst_QProcessEnvironment::clearAndInheritsFromParent() +{ + QProcessEnvironment e(QProcessEnvironment::InheritFromParent); + QVERIFY(e.isEmpty()); + QVERIFY(e.inheritsFromParent()); + // Clearing null environment keeps it null + e.clear(); + QVERIFY(e.isEmpty()); + QVERIFY(e.inheritsFromParent()); e.insert("FOO", "bar"); QVERIFY(!e.isEmpty()); + QVERIFY(!e.inheritsFromParent()); e.clear(); QVERIFY(e.isEmpty()); + QVERIFY(!e.inheritsFromParent()); } void tst_QProcessEnvironment::insert() |