Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qtenvironmentvariables.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
6
7#include <qplatformdefs.h>
8#include <QtCore/qbytearray.h>
9#include <QtCore/qmutex.h>
10#include <QtCore/qstring.h>
11#include <QtCore/qvarlengtharray.h>
12
13#include <QtCore/private/qlocking_p.h>
14
16
17// In the C runtime on all platforms access to the environment is not thread-safe. We
18// add thread-safety for the Qt wrappers.
19Q_CONSTINIT static QBasicMutex environmentMutex;
20
43QByteArray qgetenv(const char *varName)
44{
45 const auto locker = qt_scoped_lock(environmentMutex);
46#ifdef Q_CC_MSVC
47 size_t requiredSize = 0;
49 getenv_s(&requiredSize, 0, 0, varName);
50 if (requiredSize == 0)
51 return buffer;
52 buffer.resize(qsizetype(requiredSize));
53 getenv_s(&requiredSize, buffer.data(), requiredSize, varName);
54 // requiredSize includes the terminating null, which we don't want.
55 Q_ASSERT(buffer.endsWith('\0'));
56 buffer.chop(1);
57 return buffer;
58#else
59 return QByteArray(::getenv(varName));
60#endif
61}
62
109QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
110{
111#if defined(Q_OS_WIN)
112 QVarLengthArray<wchar_t, 32> wname(qsizetype(strlen(varName)) + 1);
113 for (qsizetype i = 0; i < wname.size(); ++i) // wname.size() is correct: will copy terminating null
114 wname[i] = uchar(varName[i]);
115 size_t requiredSize = 0;
116 auto locker = qt_unique_lock(environmentMutex);
117 _wgetenv_s(&requiredSize, 0, 0, wname.data());
118 if (requiredSize == 0)
119 return defaultValue;
121 _wgetenv_s(&requiredSize, reinterpret_cast<wchar_t *>(buffer.data()), requiredSize,
122 wname.data());
123 locker.unlock();
124 // requiredSize includes the terminating null, which we don't want.
125 Q_ASSERT(buffer.endsWith(QChar(u'\0')));
126 buffer.chop(1);
127 return buffer;
128#else
129 QByteArray value = qgetenv(varName);
130 if (value.isNull())
131 return defaultValue;
132// duplicated in qfile.h (QFile::decodeName)
133#if defined(Q_OS_DARWIN)
135#else // other Unix
137#endif
138#endif
139}
140
141QString qEnvironmentVariable(const char *varName)
142{
143 return qEnvironmentVariable(varName, QString());
144}
145
158bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
159{
160 const auto locker = qt_scoped_lock(environmentMutex);
161#ifdef Q_CC_MSVC
162 // we provide a buffer that can only hold the empty string, so
163 // when the env.var isn't empty, we'll get an ERANGE error (buffer
164 // too small):
165 size_t dummy;
166 char buffer = '\0';
167 return getenv_s(&dummy, &buffer, 1, varName) != ERANGE;
168#else
169 const char * const value = ::getenv(varName);
170 return !value || !*value;
171#endif
172}
173
193int qEnvironmentVariableIntValue(const char *varName, bool *ok) noexcept
194{
195 static const int NumBinaryDigitsPerOctalDigit = 3;
196 static const int MaxDigitsForOctalInt =
197 (std::numeric_limits<uint>::digits + NumBinaryDigitsPerOctalDigit - 1) / NumBinaryDigitsPerOctalDigit;
198
199 const auto locker = qt_scoped_lock(environmentMutex);
200 size_t size;
201#ifdef Q_CC_MSVC
202 // we provide a buffer that can hold any int value:
203 char buffer[MaxDigitsForOctalInt + 2]; // +1 for NUL +1 for optional '-'
204 size_t dummy;
205 if (getenv_s(&dummy, buffer, sizeof buffer, varName) != 0) {
206 if (ok)
207 *ok = false;
208 return 0;
209 }
210 size = strlen(buffer);
211#else
212 const char * const buffer = ::getenv(varName);
213 if (!buffer || (size = strlen(buffer)) > MaxDigitsForOctalInt + 2) {
214 if (ok)
215 *ok = false;
216 return 0;
217 }
218#endif
219 return QByteArrayView(buffer, size).toInt(ok, 0);
220}
221
234bool qEnvironmentVariableIsSet(const char *varName) noexcept
235{
236 const auto locker = qt_scoped_lock(environmentMutex);
237#ifdef Q_CC_MSVC
238 size_t requiredSize = 0;
239 (void)getenv_s(&requiredSize, 0, 0, varName);
240 return requiredSize != 0;
241#else
242 return ::getenv(varName) != nullptr;
243#endif
244}
245
268bool qputenv(const char *varName, QByteArrayView raw)
269{
270 auto protect = [](const char *str) { return str ? str : ""; };
271
272 std::string value{protect(raw.data()), size_t(raw.size())}; // NUL-terminates w/SSO
273
274#if defined(Q_CC_MSVC)
275 const auto locker = qt_scoped_lock(environmentMutex);
276 return _putenv_s(varName, value.data()) == 0;
277#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_HAIKU)
278 // POSIX.1-2001 has setenv
279 const auto locker = qt_scoped_lock(environmentMutex);
280 return setenv(varName, value.data(), true) == 0;
281#else
282 std::string buffer;
283 buffer += protect(varName);
284 buffer += '=';
285 buffer += value;
286 char *envVar = qstrdup(buffer.data());
287 int result = [&] {
288 const auto locker = qt_scoped_lock(environmentMutex);
289 return putenv(envVar);
290 }();
291 if (result != 0) // error. we have to delete the string.
292 delete[] envVar;
293 return result == 0;
294#endif
295}
296
308bool qunsetenv(const char *varName)
309{
310#if defined(Q_CC_MSVC)
311 const auto locker = qt_scoped_lock(environmentMutex);
312 return _putenv_s(varName, "") == 0;
313#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION-0) >= 200112L) || defined(Q_OS_BSD4) || defined(Q_OS_HAIKU)
314 // POSIX.1-2001, BSD and Haiku have unsetenv
315 const auto locker = qt_scoped_lock(environmentMutex);
316 return unsetenv(varName) == 0;
317#elif defined(Q_CC_MINGW)
318 // On mingw, putenv("var=") removes "var" from the environment
319 QByteArray buffer(varName);
320 buffer += '=';
321 const auto locker = qt_scoped_lock(environmentMutex);
322 return putenv(buffer.constData()) == 0;
323#else
324 // Fallback to putenv("var=") which will insert an empty var into the
325 // environment and leak it
326 QByteArray buffer(varName);
327 buffer += '=';
328 char *envVar = qstrdup(buffer.constData());
329 const auto locker = qt_scoped_lock(environmentMutex);
330 return putenv(envVar) == 0;
331#endif
332}
333
334/* Various time-related APIs that need to consult system settings also need
335 protection with the same lock as the environment, since those system settings
336 include part of the environment (principally TZ).
337
338 First, tzset(), which POSIX explicitly says accesses the environment.
339*/
340void qTzSet()
341{
342 const auto locker = qt_scoped_lock(environmentMutex);
343#if defined(Q_OS_WIN)
344 _tzset();
345#else
346 tzset();
347#endif // Q_OS_WIN
348}
349
350/* Wrap mktime(), which is specified to behave as if it called tzset(), hence
351 shares its implicit environment-dependence.
352*/
353time_t qMkTime(struct tm *when)
354{
355 const auto locker = qt_scoped_lock(environmentMutex);
356 return mktime(when);
357}
358
359/* For localtime(), POSIX mandates that it behave as if it called tzset().
360 For the alternatives to it, we need (if only for compatibility) to do the
361 same explicitly, which should ensure a re-parse of timezone info.
362*/
363bool qLocalTime(time_t utc, struct tm *local)
364{
365 const auto locker = qt_scoped_lock(environmentMutex);
366#if defined(Q_OS_WIN)
367 // The doc of localtime_s() says that it corrects for the same things
368 // _tzset() sets the globals for, but QTBUG-109974 reveals a need for an
369 // explicit call, all the same.
370 _tzset();
371 return !localtime_s(local, &utc);
372#elif QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
373 // Use the reentrant version of localtime() where available, as it is
374 // thread-safe and doesn't use a shared static data area.
375 // As localtime_r() is not specified to work as if it called tzset(),
376 // make an explicit call.
377 tzset();
378 if (tm *res = localtime_r(&utc, local)) {
379 Q_ASSERT(res == local);
380 Q_UNUSED(res);
381 return true;
382 }
383 return false;
384#else
385 // POSIX mandates that localtime() behaves as if it called tzset().
386 // Returns shared static data which may be overwritten at any time (albeit
387 // our lock probably keeps it safe). So copy the result promptly:
388 if (tm *res = localtime(&utc)) {
389 *local = *res;
390 return true;
391 }
392 return false;
393#endif
394}
395
396/* Access to the tzname[] global in one thread is UB if any other is calling
397 tzset() or anything that behaves as if it called tzset(). So also lock this
398 access to prevent such collisions.
399
400 Parameter dstIndex must be 1 for DST or 0 for standard time.
401 Returns the relevant form of the name of local-time's zone.
402*/
403QString qTzName(int dstIndex)
404{
405 char name[512];
406 bool ok;
407#if defined(Q_CC_MSVC)
408 size_t s = 0;
409 {
410 const auto locker = qt_scoped_lock(environmentMutex);
411 ok = _get_tzname(&s, name, 512, dstIndex) != 0;
412 }
413#else
414 {
415 const auto locker = qt_scoped_lock(environmentMutex);
416 const char *const src = tzname[dstIndex];
417 ok = src != nullptr;
418 if (ok)
419 memcpy(name, src, std::min(sizeof(name), strlen(src) + 1));
420 }
421#endif // Q_OS_WIN
423}
424
int toInt(bool *ok=nullptr, int base=10) const
constexpr qsizetype size() const noexcept
constexpr const_pointer data() const noexcept
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
Definition qchar.h:48
\inmodule QtCore
Definition qmutex.h:285
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5788
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
@ NormalizationForm_C
Definition qstring.h:548
QString normalized(NormalizationForm mode, QChar::UnicodeVersion version=QChar::Unicode_Unassigned) const
Returns the string in the given Unicode normalization mode, according to the given version of the Uni...
Definition qstring.cpp:8212
constexpr size_type size() const noexcept
T * data() noexcept
QString str
[2]
Combined button and popup list for selecting options.
Lock qt_scoped_lock(Mutex &mutex)
Definition qlocking_p.h:58
constexpr Initialization Uninitialized
Q_CORE_EXPORT char * qstrdup(const char *)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum src
GLenum GLuint buffer
GLuint name
GLuint res
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
bool qLocalTime(time_t utc, struct tm *local)
QT_BEGIN_NAMESPACE static Q_CONSTINIT QBasicMutex environmentMutex
QString qEnvironmentVariable(const char *varName, const QString &defaultValue)
bool qputenv(const char *varName, QByteArrayView raw)
time_t qMkTime(struct tm *when)
void qTzSet()
QString qTzName(int dstIndex)
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
Q_CORE_EXPORT bool qunsetenv(const char *varName)
#define Q_UNUSED(x)
unsigned char uchar
Definition qtypes.h:27
ptrdiff_t qsizetype
Definition qtypes.h:70