10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric * kmp_environment.cpp -- Handle environment variables OS-independently.
30b57cec5SDimitry Andric */
40b57cec5SDimitry Andric
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
140b57cec5SDimitry Andric act of loading a DLL on Windows* OS makes any user-set environment variables
150b57cec5SDimitry Andric (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of
160b57cec5SDimitry Andric the env variables as they existed at the start of the run. JH 12/23/2002
170b57cec5SDimitry Andric
180b57cec5SDimitry Andric On Windows* OS, there are two environments (at least, see below):
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric 1. Environment maintained by Windows* OS on IA-32 architecture. Accessible
210b57cec5SDimitry Andric through GetEnvironmentVariable(), SetEnvironmentVariable(), and
220b57cec5SDimitry Andric GetEnvironmentStrings().
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric 2. Environment maintained by C RTL. Accessible through getenv(), putenv().
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric putenv() function updates both C and Windows* OS on IA-32 architecture.
270b57cec5SDimitry Andric getenv() function search for variables in C RTL environment only.
280b57cec5SDimitry Andric Windows* OS on IA-32 architecture functions work *only* with Windows* OS on
290b57cec5SDimitry Andric IA-32 architecture.
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric Windows* OS on IA-32 architecture maintained by OS, so there is always only
320b57cec5SDimitry Andric one Windows* OS on IA-32 architecture per process. Changes in Windows* OS on
330b57cec5SDimitry Andric IA-32 architecture are process-visible.
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric C environment maintained by C RTL. Multiple copies of C RTL may be present
360b57cec5SDimitry Andric in the process, and each C RTL maintains its own environment. :-(
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric Thus, proper way to work with environment on Windows* OS is:
390b57cec5SDimitry Andric
400b57cec5SDimitry Andric 1. Set variables with putenv() function -- both C and Windows* OS on IA-32
410b57cec5SDimitry Andric architecture are being updated. Windows* OS on IA-32 architecture may be
420b57cec5SDimitry Andric considered primary target, while updating C RTL environment is free bonus.
430b57cec5SDimitry Andric
440b57cec5SDimitry Andric 2. Get variables with GetEnvironmentVariable() -- getenv() does not
450b57cec5SDimitry Andric search Windows* OS on IA-32 architecture, and can not see variables
460b57cec5SDimitry Andric set with SetEnvironmentVariable().
470b57cec5SDimitry Andric
480b57cec5SDimitry Andric 2007-04-05 -- lev
490b57cec5SDimitry Andric */
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric #include "kmp_environment.h"
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric #include "kmp.h" //
540b57cec5SDimitry Andric #include "kmp_i18n.h"
550b57cec5SDimitry Andric #include "kmp_os.h" // KMP_OS_*.
560b57cec5SDimitry Andric #include "kmp_str.h" // __kmp_str_*().
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric #if KMP_OS_UNIX
590b57cec5SDimitry Andric #include <stdlib.h> // getenv, setenv, unsetenv.
600b57cec5SDimitry Andric #include <string.h> // strlen, strcpy.
610b57cec5SDimitry Andric #if KMP_OS_DARWIN
620b57cec5SDimitry Andric #include <crt_externs.h>
630b57cec5SDimitry Andric #define environ (*_NSGetEnviron())
640b57cec5SDimitry Andric #else
650b57cec5SDimitry Andric extern char **environ;
660b57cec5SDimitry Andric #endif
670b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
680b57cec5SDimitry Andric #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable,
690b57cec5SDimitry Andric // GetLastError.
700b57cec5SDimitry Andric #else
710b57cec5SDimitry Andric #error Unknown or unsupported OS.
720b57cec5SDimitry Andric #endif
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric // TODO: Eliminate direct memory allocations, use string operations instead.
750b57cec5SDimitry Andric
allocate(size_t size)760b57cec5SDimitry Andric static inline void *allocate(size_t size) {
770b57cec5SDimitry Andric void *ptr = KMP_INTERNAL_MALLOC(size);
780b57cec5SDimitry Andric if (ptr == NULL) {
790b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric return ptr;
820b57cec5SDimitry Andric } // allocate
830b57cec5SDimitry Andric
__kmp_env_get(char const * name)840b57cec5SDimitry Andric char *__kmp_env_get(char const *name) {
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric char *result = NULL;
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric #if KMP_OS_UNIX
890b57cec5SDimitry Andric char const *value = getenv(name);
900b57cec5SDimitry Andric if (value != NULL) {
910b57cec5SDimitry Andric size_t len = KMP_STRLEN(value) + 1;
920b57cec5SDimitry Andric result = (char *)KMP_INTERNAL_MALLOC(len);
930b57cec5SDimitry Andric if (result == NULL) {
940b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed);
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric KMP_STRNCPY_S(result, len, value, len);
970b57cec5SDimitry Andric }
980b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
990b57cec5SDimitry Andric /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the
1000b57cec5SDimitry Andric act of loading a DLL on Windows* OS makes any user-set environment
1010b57cec5SDimitry Andric variables (i.e. with putenv()) unavailable. getenv() apparently gets a
1020b57cec5SDimitry Andric clean copy of the env variables as they existed at the start of the run.
1030b57cec5SDimitry Andric JH 12/23/2002 */
1040b57cec5SDimitry Andric DWORD rc;
1050b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, NULL, 0);
1060b57cec5SDimitry Andric if (!rc) {
1070b57cec5SDimitry Andric DWORD error = GetLastError();
1080b57cec5SDimitry Andric if (error != ERROR_ENVVAR_NOT_FOUND) {
1090b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
1100b57cec5SDimitry Andric }
1110b57cec5SDimitry Andric // Variable is not found, it's ok, just continue.
1120b57cec5SDimitry Andric } else {
1130b57cec5SDimitry Andric DWORD len = rc;
1140b57cec5SDimitry Andric result = (char *)KMP_INTERNAL_MALLOC(len);
1150b57cec5SDimitry Andric if (result == NULL) {
1160b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed);
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, result, len);
1190b57cec5SDimitry Andric if (!rc) {
1200b57cec5SDimitry Andric // GetEnvironmentVariable() may return 0 if variable is empty.
1210b57cec5SDimitry Andric // In such a case GetLastError() returns ERROR_SUCCESS.
1220b57cec5SDimitry Andric DWORD error = GetLastError();
1230b57cec5SDimitry Andric if (error != ERROR_SUCCESS) {
1240b57cec5SDimitry Andric // Unexpected error. The variable should be in the environment,
1250b57cec5SDimitry Andric // and buffer should be large enough.
1260b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error),
1270b57cec5SDimitry Andric __kmp_msg_null);
1280b57cec5SDimitry Andric KMP_INTERNAL_FREE((void *)result);
1290b57cec5SDimitry Andric result = NULL;
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric }
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric #else
1340b57cec5SDimitry Andric #error Unknown or unsupported OS.
1350b57cec5SDimitry Andric #endif
1360b57cec5SDimitry Andric
1370b57cec5SDimitry Andric return result;
1380b57cec5SDimitry Andric
1390b57cec5SDimitry Andric } // func __kmp_env_get
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric // TODO: Find and replace all regular free() with __kmp_env_free().
1420b57cec5SDimitry Andric
__kmp_env_free(char const ** value)1430b57cec5SDimitry Andric void __kmp_env_free(char const **value) {
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric KMP_DEBUG_ASSERT(value != NULL);
1460b57cec5SDimitry Andric KMP_INTERNAL_FREE(CCAST(char *, *value));
1470b57cec5SDimitry Andric *value = NULL;
1480b57cec5SDimitry Andric
1490b57cec5SDimitry Andric } // func __kmp_env_free
1500b57cec5SDimitry Andric
__kmp_env_exists(char const * name)1510b57cec5SDimitry Andric int __kmp_env_exists(char const *name) {
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric #if KMP_OS_UNIX
1540b57cec5SDimitry Andric char const *value = getenv(name);
1550b57cec5SDimitry Andric return ((value == NULL) ? (0) : (1));
1560b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
1570b57cec5SDimitry Andric DWORD rc;
1580b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, NULL, 0);
1590b57cec5SDimitry Andric if (rc == 0) {
1600b57cec5SDimitry Andric DWORD error = GetLastError();
1610b57cec5SDimitry Andric if (error != ERROR_ENVVAR_NOT_FOUND) {
1620b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
1630b57cec5SDimitry Andric }
1640b57cec5SDimitry Andric return 0;
1650b57cec5SDimitry Andric }
1660b57cec5SDimitry Andric return 1;
1670b57cec5SDimitry Andric #else
1680b57cec5SDimitry Andric #error Unknown or unsupported OS.
1690b57cec5SDimitry Andric #endif
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric } // func __kmp_env_exists
1720b57cec5SDimitry Andric
__kmp_env_set(char const * name,char const * value,int overwrite)1730b57cec5SDimitry Andric void __kmp_env_set(char const *name, char const *value, int overwrite) {
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric #if KMP_OS_UNIX
1760b57cec5SDimitry Andric int rc = setenv(name, value, overwrite);
1770b57cec5SDimitry Andric if (rc != 0) {
1780b57cec5SDimitry Andric // Dead code. I tried to put too many variables into Linux* OS
1790b57cec5SDimitry Andric // environment on IA-32 architecture. When application consumes
1800b57cec5SDimitry Andric // more than ~2.5 GB of memory, entire system feels bad. Sometimes
1810b57cec5SDimitry Andric // application is killed (by OS?), sometimes system stops
1820b57cec5SDimitry Andric // responding... But this error message never appears. --ln
1830b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_HNT(NotEnoughMemory),
1840b57cec5SDimitry Andric __kmp_msg_null);
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
1870b57cec5SDimitry Andric BOOL rc;
1880b57cec5SDimitry Andric if (!overwrite) {
1890b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, NULL, 0);
1900b57cec5SDimitry Andric if (rc) {
1910b57cec5SDimitry Andric // Variable exists, do not overwrite.
1920b57cec5SDimitry Andric return;
1930b57cec5SDimitry Andric }
1940b57cec5SDimitry Andric DWORD error = GetLastError();
1950b57cec5SDimitry Andric if (error != ERROR_ENVVAR_NOT_FOUND) {
1960b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric rc = SetEnvironmentVariable(name, value);
2000b57cec5SDimitry Andric if (!rc) {
2010b57cec5SDimitry Andric DWORD error = GetLastError();
2020b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric #else
2050b57cec5SDimitry Andric #error Unknown or unsupported OS.
2060b57cec5SDimitry Andric #endif
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric } // func __kmp_env_set
2090b57cec5SDimitry Andric
__kmp_env_unset(char const * name)2100b57cec5SDimitry Andric void __kmp_env_unset(char const *name) {
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric #if KMP_OS_UNIX
2130b57cec5SDimitry Andric unsetenv(name);
2140b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
2150b57cec5SDimitry Andric BOOL rc = SetEnvironmentVariable(name, NULL);
2160b57cec5SDimitry Andric if (!rc) {
2170b57cec5SDimitry Andric DWORD error = GetLastError();
2180b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null);
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric #else
2210b57cec5SDimitry Andric #error Unknown or unsupported OS.
2220b57cec5SDimitry Andric #endif
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric } // func __kmp_env_unset
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric /* Intel OpenMP RTL string representation of environment: just a string of
2270b57cec5SDimitry Andric characters, variables are separated with vertical bars, e. g.:
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric "KMP_WARNINGS=0|KMP_AFFINITY=compact|"
2300b57cec5SDimitry Andric
2310b57cec5SDimitry Andric Empty variables are allowed and ignored:
2320b57cec5SDimitry Andric
2330b57cec5SDimitry Andric "||KMP_WARNINGS=1||"
2340b57cec5SDimitry Andric */
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric static void
___kmp_env_blk_parse_string(kmp_env_blk_t * block,char const * env)2370b57cec5SDimitry Andric ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill.
2380b57cec5SDimitry Andric char const *env // I: String to parse.
2390b57cec5SDimitry Andric ) {
2400b57cec5SDimitry Andric
2410b57cec5SDimitry Andric char const chr_delimiter = '|';
2420b57cec5SDimitry Andric char const str_delimiter[] = {chr_delimiter, 0};
2430b57cec5SDimitry Andric
2440b57cec5SDimitry Andric char *bulk = NULL;
2450b57cec5SDimitry Andric kmp_env_var_t *vars = NULL;
2460b57cec5SDimitry Andric int count = 0; // Number of used elements in vars array.
2470b57cec5SDimitry Andric int delimiters = 0; // Number of delimiters in input string.
2480b57cec5SDimitry Andric
2490b57cec5SDimitry Andric // Copy original string, we will modify the copy.
2500b57cec5SDimitry Andric bulk = __kmp_str_format("%s", env);
2510b57cec5SDimitry Andric
2520b57cec5SDimitry Andric // Loop thru all the vars in environment block. Count delimiters (maximum
2530b57cec5SDimitry Andric // number of variables is number of delimiters plus one).
2540b57cec5SDimitry Andric {
2550b57cec5SDimitry Andric char const *ptr = bulk;
2560b57cec5SDimitry Andric for (;;) {
2570b57cec5SDimitry Andric ptr = strchr(ptr, chr_delimiter);
2580b57cec5SDimitry Andric if (ptr == NULL) {
2590b57cec5SDimitry Andric break;
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric ++delimiters;
2620b57cec5SDimitry Andric ptr += 1;
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric // Allocate vars array.
2670b57cec5SDimitry Andric vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t));
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric // Loop thru all the variables.
2700b57cec5SDimitry Andric {
2710b57cec5SDimitry Andric char *var; // Pointer to variable (both name and value).
2720b57cec5SDimitry Andric char *name; // Pointer to name of variable.
2730b57cec5SDimitry Andric char *value; // Pointer to value.
2740b57cec5SDimitry Andric char *buf; // Buffer for __kmp_str_token() function.
2750b57cec5SDimitry Andric var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var.
2760b57cec5SDimitry Andric while (var != NULL) {
2770b57cec5SDimitry Andric // Save found variable in vars array.
2780b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value);
2790b57cec5SDimitry Andric KMP_DEBUG_ASSERT(count < delimiters + 1);
2800b57cec5SDimitry Andric vars[count].name = name;
2810b57cec5SDimitry Andric vars[count].value = value;
2820b57cec5SDimitry Andric ++count;
2830b57cec5SDimitry Andric // Get the next var.
2840b57cec5SDimitry Andric var = __kmp_str_token(NULL, str_delimiter, &buf);
2850b57cec5SDimitry Andric }
2860b57cec5SDimitry Andric }
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric // Fill out result.
2890b57cec5SDimitry Andric block->bulk = bulk;
2900b57cec5SDimitry Andric block->vars = vars;
2910b57cec5SDimitry Andric block->count = count;
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric
2940b57cec5SDimitry Andric /* Windows* OS (actually, DOS) environment block is a piece of memory with
2950b57cec5SDimitry Andric environment variables. Each variable is terminated with zero byte, entire
2960b57cec5SDimitry Andric block is terminated with one extra zero byte, so we have two zero bytes at
2970b57cec5SDimitry Andric the end of environment block, e. g.:
2980b57cec5SDimitry Andric
2990b57cec5SDimitry Andric "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00"
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric It is not clear how empty environment is represented. "\x00\x00"?
3020b57cec5SDimitry Andric */
3030b57cec5SDimitry Andric
3040b57cec5SDimitry Andric #if KMP_OS_WINDOWS
___kmp_env_blk_parse_windows(kmp_env_blk_t * block,char const * env)3050b57cec5SDimitry Andric static void ___kmp_env_blk_parse_windows(
3060b57cec5SDimitry Andric kmp_env_blk_t *block, // M: Env block to fill.
3070b57cec5SDimitry Andric char const *env // I: Pointer to Windows* OS (DOS) environment block.
3080b57cec5SDimitry Andric ) {
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric char *bulk = NULL;
3110b57cec5SDimitry Andric kmp_env_var_t *vars = NULL;
3120b57cec5SDimitry Andric int count = 0; // Number of used elements in vars array.
3130b57cec5SDimitry Andric int size = 0; // Size of bulk.
3140b57cec5SDimitry Andric
3150b57cec5SDimitry Andric char *name; // Pointer to name of variable.
3160b57cec5SDimitry Andric char *value; // Pointer to value.
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andric if (env != NULL) {
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric // Loop thru all the vars in environment block. Count variables, find size
3210b57cec5SDimitry Andric // of block.
3220b57cec5SDimitry Andric {
3230b57cec5SDimitry Andric char const *var; // Pointer to beginning of var.
3240b57cec5SDimitry Andric int len; // Length of variable.
3250b57cec5SDimitry Andric count = 0;
3260b57cec5SDimitry Andric var =
3270b57cec5SDimitry Andric env; // The first variable starts and beginning of environment block.
3280b57cec5SDimitry Andric len = KMP_STRLEN(var);
3290b57cec5SDimitry Andric while (len != 0) {
3300b57cec5SDimitry Andric ++count;
3310b57cec5SDimitry Andric size = size + len + 1;
3320b57cec5SDimitry Andric var = var + len +
3330b57cec5SDimitry Andric 1; // Move pointer to the beginning of the next variable.
3340b57cec5SDimitry Andric len = KMP_STRLEN(var);
3350b57cec5SDimitry Andric }
3360b57cec5SDimitry Andric size =
3370b57cec5SDimitry Andric size + 1; // Total size of env block, including terminating zero byte.
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric
3400b57cec5SDimitry Andric // Copy original block to bulk, we will modify bulk, not original block.
3410b57cec5SDimitry Andric bulk = (char *)allocate(size);
3420b57cec5SDimitry Andric KMP_MEMCPY_S(bulk, size, env, size);
3430b57cec5SDimitry Andric // Allocate vars array.
3440b57cec5SDimitry Andric vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
3450b57cec5SDimitry Andric
3460b57cec5SDimitry Andric // Loop thru all the vars, now in bulk.
3470b57cec5SDimitry Andric {
3480b57cec5SDimitry Andric char *var; // Pointer to beginning of var.
3490b57cec5SDimitry Andric int len; // Length of variable.
3500b57cec5SDimitry Andric count = 0;
3510b57cec5SDimitry Andric var = bulk;
3520b57cec5SDimitry Andric len = KMP_STRLEN(var);
3530b57cec5SDimitry Andric while (len != 0) {
3540b57cec5SDimitry Andric // Save variable in vars array.
3550b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value);
3560b57cec5SDimitry Andric vars[count].name = name;
3570b57cec5SDimitry Andric vars[count].value = value;
3580b57cec5SDimitry Andric ++count;
3590b57cec5SDimitry Andric // Get the next var.
3600b57cec5SDimitry Andric var = var + len + 1;
3610b57cec5SDimitry Andric len = KMP_STRLEN(var);
3620b57cec5SDimitry Andric }
3630b57cec5SDimitry Andric }
3640b57cec5SDimitry Andric }
3650b57cec5SDimitry Andric
3660b57cec5SDimitry Andric // Fill out result.
3670b57cec5SDimitry Andric block->bulk = bulk;
3680b57cec5SDimitry Andric block->vars = vars;
3690b57cec5SDimitry Andric block->count = count;
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric #endif
3720b57cec5SDimitry Andric
3730b57cec5SDimitry Andric /* Unix environment block is a array of pointers to variables, last pointer in
3740b57cec5SDimitry Andric array is NULL:
3750b57cec5SDimitry Andric
3760b57cec5SDimitry Andric { "HOME=/home/lev", "TERM=xterm", NULL }
3770b57cec5SDimitry Andric */
3780b57cec5SDimitry Andric
379fe6060f1SDimitry Andric #if KMP_OS_UNIX
3800b57cec5SDimitry Andric static void
___kmp_env_blk_parse_unix(kmp_env_blk_t * block,char ** env)3810b57cec5SDimitry Andric ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill.
3820b57cec5SDimitry Andric char **env // I: Unix environment to parse.
3830b57cec5SDimitry Andric ) {
3840b57cec5SDimitry Andric char *bulk = NULL;
3850b57cec5SDimitry Andric kmp_env_var_t *vars = NULL;
3860b57cec5SDimitry Andric int count = 0;
387e8d8bef9SDimitry Andric size_t size = 0; // Size of bulk.
3880b57cec5SDimitry Andric
3890b57cec5SDimitry Andric // Count number of variables and length of required bulk.
3900b57cec5SDimitry Andric {
3910b57cec5SDimitry Andric while (env[count] != NULL) {
3920b57cec5SDimitry Andric size += KMP_STRLEN(env[count]) + 1;
3930b57cec5SDimitry Andric ++count;
3940b57cec5SDimitry Andric }
3950b57cec5SDimitry Andric }
3960b57cec5SDimitry Andric
3970b57cec5SDimitry Andric // Allocate memory.
3980b57cec5SDimitry Andric bulk = (char *)allocate(size);
3990b57cec5SDimitry Andric vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t));
4000b57cec5SDimitry Andric
4010b57cec5SDimitry Andric // Loop thru all the vars.
4020b57cec5SDimitry Andric {
4030b57cec5SDimitry Andric char *var; // Pointer to beginning of var.
4040b57cec5SDimitry Andric char *name; // Pointer to name of variable.
4050b57cec5SDimitry Andric char *value; // Pointer to value.
406e8d8bef9SDimitry Andric size_t len; // Length of variable.
4070b57cec5SDimitry Andric int i;
4080b57cec5SDimitry Andric var = bulk;
4090b57cec5SDimitry Andric for (i = 0; i < count; ++i) {
410*5f757f3fSDimitry Andric KMP_ASSERT(var < bulk + size);
411*5f757f3fSDimitry Andric [[maybe_unused]] size_t ssize = size - (var - bulk);
4120b57cec5SDimitry Andric // Copy variable to bulk.
4130b57cec5SDimitry Andric len = KMP_STRLEN(env[i]);
414*5f757f3fSDimitry Andric KMP_MEMCPY_S(var, ssize, env[i], len + 1);
4150b57cec5SDimitry Andric // Save found variable in vars array.
4160b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value);
4170b57cec5SDimitry Andric vars[i].name = name;
4180b57cec5SDimitry Andric vars[i].value = value;
4190b57cec5SDimitry Andric // Move pointer.
4200b57cec5SDimitry Andric var += len + 1;
4210b57cec5SDimitry Andric }
4220b57cec5SDimitry Andric }
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric // Fill out result.
4250b57cec5SDimitry Andric block->bulk = bulk;
4260b57cec5SDimitry Andric block->vars = vars;
4270b57cec5SDimitry Andric block->count = count;
4280b57cec5SDimitry Andric }
429fe6060f1SDimitry Andric #endif
4300b57cec5SDimitry Andric
__kmp_env_blk_init(kmp_env_blk_t * block,char const * bulk)4310b57cec5SDimitry Andric void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize.
4320b57cec5SDimitry Andric char const *bulk // I: Initialization string, or NULL.
4330b57cec5SDimitry Andric ) {
4340b57cec5SDimitry Andric
4350b57cec5SDimitry Andric if (bulk != NULL) {
4360b57cec5SDimitry Andric ___kmp_env_blk_parse_string(block, bulk);
4370b57cec5SDimitry Andric } else {
4380b57cec5SDimitry Andric #if KMP_OS_UNIX
4390b57cec5SDimitry Andric ___kmp_env_blk_parse_unix(block, environ);
4400b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
4410b57cec5SDimitry Andric {
4420b57cec5SDimitry Andric char *mem = GetEnvironmentStrings();
4430b57cec5SDimitry Andric if (mem == NULL) {
4440b57cec5SDimitry Andric DWORD error = GetLastError();
4450b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error),
4460b57cec5SDimitry Andric __kmp_msg_null);
4470b57cec5SDimitry Andric }
4480b57cec5SDimitry Andric ___kmp_env_blk_parse_windows(block, mem);
4490b57cec5SDimitry Andric FreeEnvironmentStrings(mem);
4500b57cec5SDimitry Andric }
4510b57cec5SDimitry Andric #else
4520b57cec5SDimitry Andric #error Unknown or unsupported OS.
4530b57cec5SDimitry Andric #endif
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric
4560b57cec5SDimitry Andric } // __kmp_env_blk_init
4570b57cec5SDimitry Andric
___kmp_env_var_cmp(kmp_env_var_t const * lhs,kmp_env_var_t const * rhs)4580b57cec5SDimitry Andric static int ___kmp_env_var_cmp( // Comparison function for qsort().
4590b57cec5SDimitry Andric kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) {
4600b57cec5SDimitry Andric return strcmp(lhs->name, rhs->name);
4610b57cec5SDimitry Andric }
4620b57cec5SDimitry Andric
__kmp_env_blk_sort(kmp_env_blk_t * block)4630b57cec5SDimitry Andric void __kmp_env_blk_sort(
4640b57cec5SDimitry Andric kmp_env_blk_t *block // M: Block of environment variables to sort.
4650b57cec5SDimitry Andric ) {
4660b57cec5SDimitry Andric
4670b57cec5SDimitry Andric qsort(CCAST(kmp_env_var_t *, block->vars), block->count,
4680b57cec5SDimitry Andric sizeof(kmp_env_var_t),
4690b57cec5SDimitry Andric (int (*)(void const *, void const *)) & ___kmp_env_var_cmp);
4700b57cec5SDimitry Andric
4710b57cec5SDimitry Andric } // __kmp_env_block_sort
4720b57cec5SDimitry Andric
__kmp_env_blk_free(kmp_env_blk_t * block)4730b57cec5SDimitry Andric void __kmp_env_blk_free(
4740b57cec5SDimitry Andric kmp_env_blk_t *block // M: Block of environment variables to free.
4750b57cec5SDimitry Andric ) {
4760b57cec5SDimitry Andric
4770b57cec5SDimitry Andric KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars));
4780b57cec5SDimitry Andric __kmp_str_free(&(block->bulk));
4790b57cec5SDimitry Andric
4800b57cec5SDimitry Andric block->count = 0;
4810b57cec5SDimitry Andric block->vars = NULL;
4820b57cec5SDimitry Andric
4830b57cec5SDimitry Andric } // __kmp_env_blk_free
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andric char const * // R: Value of variable or NULL if variable does not exist.
__kmp_env_blk_var(kmp_env_blk_t * block,char const * name)486fe6060f1SDimitry Andric __kmp_env_blk_var(kmp_env_blk_t *block, // I: Block of environment variables.
4870b57cec5SDimitry Andric char const *name // I: Name of variable to find.
4880b57cec5SDimitry Andric ) {
4890b57cec5SDimitry Andric
4900b57cec5SDimitry Andric int i;
4910b57cec5SDimitry Andric for (i = 0; i < block->count; ++i) {
4920b57cec5SDimitry Andric if (strcmp(block->vars[i].name, name) == 0) {
4930b57cec5SDimitry Andric return block->vars[i].value;
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric }
4960b57cec5SDimitry Andric return NULL;
4970b57cec5SDimitry Andric
4980b57cec5SDimitry Andric } // __kmp_env_block_var
4990b57cec5SDimitry Andric
5000b57cec5SDimitry Andric // end of file //
501