Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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#if defined(Q_OS_WIN)
357 // QTBUG-83881 MS's mktime() seems to need _tzset() called first.
358 _tzset();
359#endif
360 return mktime(when);
361}
362
363/* For localtime(), POSIX mandates that it behave as if it called tzset().
364 For the alternatives to it, we need (if only for compatibility) to do the
365 same explicitly, which should ensure a re-parse of timezone info.
366*/
367bool qLocalTime(time_t utc, struct tm *local)
368{
369 const auto locker = qt_scoped_lock(environmentMutex);
370#if defined(Q_OS_WIN)
371 // The doc of localtime_s() says that it corrects for the same things
372 // _tzset() sets the globals for, but QTBUG-109974 reveals a need for an
373 // explicit call, all the same.
374 _tzset();
375 return !localtime_s(local, &utc);
376#elif QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
377 // Use the reentrant version of localtime() where available, as it is
378 // thread-safe and doesn't use a shared static data area.
379 // As localtime_r() is not specified to work as if it called tzset(),
380 // make an explicit call.
381 tzset();
382 if (tm *res = localtime_r(&utc, local)) {
383 Q_ASSERT(res == local);
384 Q_UNUSED(res);
385 return true;
386 }
387 return false;
388#else
389 // POSIX mandates that localtime() behaves as if it called tzset().
390 // Returns shared static data which may be overwritten at any time (albeit
391 // our lock probably keeps it safe). So copy the result promptly:
392 if (tm *res = localtime(&utc)) {
393 *local = *res;
394 return true;
395 }
396 return false;
397#endif
398}
399
400/* Access to the tzname[] global in one thread is UB if any other is calling
401 tzset() or anything that behaves as if it called tzset(). So also lock this
402 access to prevent such collisions.
403
404 Parameter dstIndex must be 1 for DST or 0 for standard time.
405 Returns the relevant form of the name of local-time's zone.
406*/
407QString qTzName(int dstIndex)
408{
409 char name[512];
410 bool ok;
411#if defined(_UCRT) // i.e., MSVC and MinGW-UCRT
412 size_t s = 0;
413 {
414 const auto locker = qt_scoped_lock(environmentMutex);
415 ok = _get_tzname(&s, name, 512, dstIndex) != 0;
416 }
417#else
418 {
419 const auto locker = qt_scoped_lock(environmentMutex);
420 const char *const src = tzname[dstIndex];
421 ok = src != nullptr;
422 if (ok)
423 memcpy(name, src, std::min(sizeof(name), strlen(src) + 1));
424 }
425#endif // Q_OS_WIN
427}
428
int toInt(bool *ok=nullptr, int base=10) const
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
\inmodule QtCore
Definition qmutex.h:281
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
@ NormalizationForm_C
Definition qstring.h:619
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
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum src
GLenum GLuint buffer
GLuint name
GLdouble s
[6]
Definition qopenglext.h:235
GLuint res
GLuint64EXT * result
[6]
#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:32
ptrdiff_t qsizetype
Definition qtypes.h:165