summaryrefslogtreecommitdiffstats
path: root/src/corelib/global/qtenvironmentvariables.cpp
diff options
context:
space:
mode:
authorSona Kurazyan <sona.kurazyan@qt.io>2022-09-22 20:48:41 +0200
committerIvan Solovev <ivan.solovev@qt.io>2022-09-30 14:19:17 +0200
commitfce36ac86667cc4490487689fb4b29f9a824bca8 (patch)
treef7c65976d65f9eaf480976cc6b956e262f39f5fb /src/corelib/global/qtenvironmentvariables.cpp
parent7e58cd0ce2ad2862cc059f3c0a7035115d7af313 (diff)
Rename the header qenvironmentvariables.h -> qtenvironmentvariables.h
Change-Id: I8153c856c2cd93ec6932cd7dd5e9d7273d5712dd Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src/corelib/global/qtenvironmentvariables.cpp')
-rw-r--r--src/corelib/global/qtenvironmentvariables.cpp357
1 files changed, 357 insertions, 0 deletions
diff --git a/src/corelib/global/qtenvironmentvariables.cpp b/src/corelib/global/qtenvironmentvariables.cpp
new file mode 100644
index 00000000000..4046beae1f4
--- /dev/null
+++ b/src/corelib/global/qtenvironmentvariables.cpp
@@ -0,0 +1,357 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qtenvironmentvariables.h"
+
+#include <qplatformdefs.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qvarlengtharray.h>
+
+#include <QtCore/private/qlocking_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// In the C runtime on all platforms access to the environment is not thread-safe. We
+// add thread-safety for the Qt wrappers.
+Q_CONSTINIT static QBasicMutex environmentMutex;
+
+/*!
+ \relates <QtEnvironmentVariables>
+ \threadsafe
+
+ Returns the value of the environment variable with name \a varName as a
+ QByteArray. If no variable by that name is found in the environment, this
+ function returns a default-constructed QByteArray.
+
+ The Qt environment manipulation functions are thread-safe, but this
+ requires that the C library equivalent functions like getenv and putenv are
+ not directly called.
+
+ To convert the data to a QString use QString::fromLocal8Bit().
+
+ \note on desktop Windows, qgetenv() may produce data loss if the
+ original string contains Unicode characters not representable in the
+ ANSI encoding. Use qEnvironmentVariable() instead.
+ On Unix systems, this function is lossless.
+
+ \sa qputenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet(),
+ qEnvironmentVariableIsEmpty()
+*/
+QByteArray qgetenv(const char *varName)
+{
+ const auto locker = qt_scoped_lock(environmentMutex);
+#ifdef Q_CC_MSVC
+ size_t requiredSize = 0;
+ QByteArray buffer;
+ getenv_s(&requiredSize, 0, 0, varName);
+ if (requiredSize == 0)
+ return buffer;
+ buffer.resize(qsizetype(requiredSize));
+ getenv_s(&requiredSize, buffer.data(), requiredSize, varName);
+ // requiredSize includes the terminating null, which we don't want.
+ Q_ASSERT(buffer.endsWith('\0'));
+ buffer.chop(1);
+ return buffer;
+#else
+ return QByteArray(::getenv(varName));
+#endif
+}
+
+/*!
+ \fn QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
+ \fn QString qEnvironmentVariable(const char *varName)
+
+ \relates <QtEnvironmentVariables>
+ \since 5.10
+
+ These functions return the value of the environment variable, \a varName, as a
+ QString. If no variable \a varName is found in the environment and \a defaultValue
+ is provided, \a defaultValue is returned. Otherwise QString() is returned.
+
+ The Qt environment manipulation functions are thread-safe, but this
+ requires that the C library equivalent functions like getenv and putenv are
+ not directly called.
+
+ The following table describes how to choose between qgetenv() and
+ qEnvironmentVariable():
+ \table
+ \header \li Condition \li Recommendation
+ \row
+ \li Variable contains file paths or user text
+ \li qEnvironmentVariable()
+ \row
+ \li Windows-specific code
+ \li qEnvironmentVariable()
+ \row
+ \li Unix-specific code, destination variable is not QString and/or is
+ used to interface with non-Qt APIs
+ \li qgetenv()
+ \row
+ \li Destination variable is a QString
+ \li qEnvironmentVariable()
+ \row
+ \li Destination variable is a QByteArray or std::string
+ \li qgetenv()
+ \endtable
+
+ \note on Unix systems, this function may produce data loss if the original
+ string contains arbitrary binary data that cannot be decoded by the locale
+ codec. Use qgetenv() instead for that case. On Windows, this function is
+ lossless.
+
+ \note the variable name \a varName must contain only US-ASCII characters.
+
+ \sa qputenv(), qgetenv(), qEnvironmentVariableIsSet(), qEnvironmentVariableIsEmpty()
+*/
+QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
+{
+#if defined(Q_OS_WIN)
+ QVarLengthArray<wchar_t, 32> wname(qsizetype(strlen(varName)) + 1);
+ for (qsizetype i = 0; i < wname.size(); ++i) // wname.size() is correct: will copy terminating null
+ wname[i] = uchar(varName[i]);
+ size_t requiredSize = 0;
+ auto locker = qt_unique_lock(environmentMutex);
+ _wgetenv_s(&requiredSize, 0, 0, wname.data());
+ if (requiredSize == 0)
+ return defaultValue;
+ QString buffer(qsizetype(requiredSize), Qt::Uninitialized);
+ _wgetenv_s(&requiredSize, reinterpret_cast<wchar_t *>(buffer.data()), requiredSize,
+ wname.data());
+ locker.unlock();
+ // requiredSize includes the terminating null, which we don't want.
+ Q_ASSERT(buffer.endsWith(QChar(u'\0')));
+ buffer.chop(1);
+ return buffer;
+#else
+ QByteArray value = qgetenv(varName);
+ if (value.isNull())
+ return defaultValue;
+// duplicated in qfile.h (QFile::decodeName)
+#if defined(Q_OS_DARWIN)
+ return QString::fromUtf8(value).normalized(QString::NormalizationForm_C);
+#else // other Unix
+ return QString::fromLocal8Bit(value);
+#endif
+#endif
+}
+
+QString qEnvironmentVariable(const char *varName)
+{
+ return qEnvironmentVariable(varName, QString());
+}
+
+/*!
+ \relates <QtEnvironmentVariables>
+ \since 5.1
+
+ Returns whether the environment variable \a varName is empty.
+
+ Equivalent to
+ \snippet code/src_corelib_global_qglobal.cpp is-empty
+ except that it's potentially much faster, and can't throw exceptions.
+
+ \sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet()
+*/
+bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
+{
+ const auto locker = qt_scoped_lock(environmentMutex);
+#ifdef Q_CC_MSVC
+ // we provide a buffer that can only hold the empty string, so
+ // when the env.var isn't empty, we'll get an ERANGE error (buffer
+ // too small):
+ size_t dummy;
+ char buffer = '\0';
+ return getenv_s(&dummy, &buffer, 1, varName) != ERANGE;
+#else
+ const char * const value = ::getenv(varName);
+ return !value || !*value;
+#endif
+}
+
+/*!
+ \relates <QtEnvironmentVariables>
+ \since 5.5
+
+ Returns the numerical value of the environment variable \a varName.
+ If \a ok is not null, sets \c{*ok} to \c true or \c false depending
+ on the success of the conversion.
+
+ Equivalent to
+ \snippet code/src_corelib_global_qglobal.cpp to-int
+ except that it's much faster, and can't throw exceptions.
+
+ \note there's a limit on the length of the value, which is sufficient for
+ all valid values of int, not counting leading zeroes or spaces. Values that
+ are too long will either be truncated or this function will set \a ok to \c
+ false.
+
+ \sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsSet()
+*/
+int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept
+{
+ static const int NumBinaryDigitsPerOctalDigit = 3;
+ static const int MaxDigitsForOctalInt =
+ (std::numeric_limits<uint>::digits + NumBinaryDigitsPerOctalDigit - 1) / NumBinaryDigitsPerOctalDigit;
+
+ const auto locker = qt_scoped_lock(environmentMutex);
+ size_t size;
+#ifdef Q_CC_MSVC
+ // we provide a buffer that can hold any int value:
+ char buffer[MaxDigitsForOctalInt + 2]; // +1 for NUL +1 for optional '-'
+ size_t dummy;
+ if (getenv_s(&dummy, buffer, sizeof buffer, varName) != 0) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+ size = strlen(buffer);
+#else
+ const char * const buffer = ::getenv(varName);
+ if (!buffer || (size = strlen(buffer)) > MaxDigitsForOctalInt + 2) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+#endif
+ return QByteArrayView(buffer, size).toInt(ok, 0);
+}
+
+/*!
+ \relates <QtEnvironmentVariables>
+ \since 5.1
+
+ Returns whether the environment variable \a varName is set.
+
+ Equivalent to
+ \snippet code/src_corelib_global_qglobal.cpp is-null
+ except that it's potentially much faster, and can't throw exceptions.
+
+ \sa qgetenv(), qEnvironmentVariable(), qEnvironmentVariableIsEmpty()
+*/
+bool qEnvironmentVariableIsSet(const char *varName) noexcept
+{
+ const auto locker = qt_scoped_lock(environmentMutex);
+#ifdef Q_CC_MSVC
+ size_t requiredSize = 0;
+ (void)getenv_s(&requiredSize, 0, 0, varName);
+ return requiredSize != 0;
+#else
+ return ::getenv(varName) != nullptr;
+#endif
+}
+
+/*!
+ \fn bool qputenv(const char *varName, QByteArrayView value)
+ \relates <QtEnvironmentVariables>
+
+ This function sets the \a value of the environment variable named
+ \a varName. It will create the variable if it does not exist. It
+ returns 0 if the variable could not be set.
+
+ Calling qputenv with an empty value removes the environment variable on
+ Windows, and makes it set (but empty) on Unix. Prefer using qunsetenv()
+ for fully portable behavior.
+
+ \note qputenv() was introduced because putenv() from the standard
+ C library was deprecated in VC2005 (and later versions). qputenv()
+ uses the replacement function in VC, and calls the standard C
+ library's implementation on all other platforms.
+
+ \note In Qt versions prior to 6.5, the \a value argument was QByteArray,
+ not QByteArrayView.
+
+ \sa qgetenv(), qEnvironmentVariable()
+*/
+bool qputenv(const char *varName, QByteArrayView raw)
+{
+ auto protect = [](const char *str) { return str ? str : ""; };
+
+ std::string value{protect(raw.data()), size_t(raw.size())}; // NUL-terminates w/SSO
+
+#if defined(Q_CC_MSVC)
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return _putenv_s(varName, value.data()) == 0;
+#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU)
+ // POSIX.1-2001 has setenv
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return setenv(varName, value.data(), true) == 0;
+#else
+ std::string buffer;
+ buffer += protect(varName);
+ buffer += '=';
+ buffer += value;
+ char *envVar = qstrdup(buffer.data());
+ int result = [&] {
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return putenv(envVar);
+ }();
+ if (result != 0) // error. we have to delete the string.
+ delete[] envVar;
+ return result == 0;
+#endif
+}
+
+/*!
+ \relates <QtEnvironmentVariables>
+
+ This function deletes the variable \a varName from the environment.
+
+ Returns \c true on success.
+
+ \since 5.1
+
+ \sa qputenv(), qgetenv(), qEnvironmentVariable()
+*/
+bool qunsetenv(const char *varName)
+{
+#if defined(Q_CC_MSVC)
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return _putenv_s(varName, "") == 0;
+#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_BSD4) || defined(Q_OS_HAIKU)
+ // POSIX.1-2001, BSD and Haiku have unsetenv
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return unsetenv(varName) == 0;
+#elif defined(Q_CC_MINGW)
+ // On mingw, putenv("var=") removes "var" from the environment
+ QByteArray buffer(varName);
+ buffer += '=';
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return putenv(buffer.constData()) == 0;
+#else
+ // Fallback to putenv("var=") which will insert an empty var into the
+ // environment and leak it
+ QByteArray buffer(varName);
+ buffer += '=';
+ char *envVar = qstrdup(buffer.constData());
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return putenv(envVar) == 0;
+#endif
+}
+
+/*
+ Wraps tzset(), which accesses the environment, so should only be called while
+ we hold the lock on the environment mutex.
+*/
+void qTzSet()
+{
+ const auto locker = qt_scoped_lock(environmentMutex);
+#if defined(Q_OS_WIN)
+ _tzset();
+#else
+ tzset();
+#endif // Q_OS_WIN
+}
+
+/*
+ Wrap mktime(), which is specified to behave as if it called tzset(), hence
+ shares its implicit environment-dependence.
+*/
+time_t qMkTime(struct tm *when)
+{
+ const auto locker = qt_scoped_lock(environmentMutex);
+ return mktime(when);
+}
+
+QT_END_NAMESPACE