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 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 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 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 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 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 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 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 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 379*fe6060f1SDimitry Andric #if KMP_OS_UNIX 3800b57cec5SDimitry Andric static void 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) { 4100b57cec5SDimitry Andric // Copy variable to bulk. 4110b57cec5SDimitry Andric len = KMP_STRLEN(env[i]); 4120b57cec5SDimitry Andric KMP_MEMCPY_S(var, size, env[i], len + 1); 4130b57cec5SDimitry Andric // Save found variable in vars array. 4140b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value); 4150b57cec5SDimitry Andric vars[i].name = name; 4160b57cec5SDimitry Andric vars[i].value = value; 4170b57cec5SDimitry Andric // Move pointer. 4180b57cec5SDimitry Andric var += len + 1; 4190b57cec5SDimitry Andric } 4200b57cec5SDimitry Andric } 4210b57cec5SDimitry Andric 4220b57cec5SDimitry Andric // Fill out result. 4230b57cec5SDimitry Andric block->bulk = bulk; 4240b57cec5SDimitry Andric block->vars = vars; 4250b57cec5SDimitry Andric block->count = count; 4260b57cec5SDimitry Andric } 427*fe6060f1SDimitry Andric #endif 4280b57cec5SDimitry Andric 4290b57cec5SDimitry Andric void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize. 4300b57cec5SDimitry Andric char const *bulk // I: Initialization string, or NULL. 4310b57cec5SDimitry Andric ) { 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric if (bulk != NULL) { 4340b57cec5SDimitry Andric ___kmp_env_blk_parse_string(block, bulk); 4350b57cec5SDimitry Andric } else { 4360b57cec5SDimitry Andric #if KMP_OS_UNIX 4370b57cec5SDimitry Andric ___kmp_env_blk_parse_unix(block, environ); 4380b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 4390b57cec5SDimitry Andric { 4400b57cec5SDimitry Andric char *mem = GetEnvironmentStrings(); 4410b57cec5SDimitry Andric if (mem == NULL) { 4420b57cec5SDimitry Andric DWORD error = GetLastError(); 4430b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error), 4440b57cec5SDimitry Andric __kmp_msg_null); 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric ___kmp_env_blk_parse_windows(block, mem); 4470b57cec5SDimitry Andric FreeEnvironmentStrings(mem); 4480b57cec5SDimitry Andric } 4490b57cec5SDimitry Andric #else 4500b57cec5SDimitry Andric #error Unknown or unsupported OS. 4510b57cec5SDimitry Andric #endif 4520b57cec5SDimitry Andric } 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric } // __kmp_env_blk_init 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric static int ___kmp_env_var_cmp( // Comparison function for qsort(). 4570b57cec5SDimitry Andric kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) { 4580b57cec5SDimitry Andric return strcmp(lhs->name, rhs->name); 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric void __kmp_env_blk_sort( 4620b57cec5SDimitry Andric kmp_env_blk_t *block // M: Block of environment variables to sort. 4630b57cec5SDimitry Andric ) { 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric qsort(CCAST(kmp_env_var_t *, block->vars), block->count, 4660b57cec5SDimitry Andric sizeof(kmp_env_var_t), 4670b57cec5SDimitry Andric (int (*)(void const *, void const *)) & ___kmp_env_var_cmp); 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric } // __kmp_env_block_sort 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric void __kmp_env_blk_free( 4720b57cec5SDimitry Andric kmp_env_blk_t *block // M: Block of environment variables to free. 4730b57cec5SDimitry Andric ) { 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars)); 4760b57cec5SDimitry Andric __kmp_str_free(&(block->bulk)); 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric block->count = 0; 4790b57cec5SDimitry Andric block->vars = NULL; 4800b57cec5SDimitry Andric 4810b57cec5SDimitry Andric } // __kmp_env_blk_free 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric char const * // R: Value of variable or NULL if variable does not exist. 484*fe6060f1SDimitry Andric __kmp_env_blk_var(kmp_env_blk_t *block, // I: Block of environment variables. 4850b57cec5SDimitry Andric char const *name // I: Name of variable to find. 4860b57cec5SDimitry Andric ) { 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric int i; 4890b57cec5SDimitry Andric for (i = 0; i < block->count; ++i) { 4900b57cec5SDimitry Andric if (strcmp(block->vars[i].name, name) == 0) { 4910b57cec5SDimitry Andric return block->vars[i].value; 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric return NULL; 4950b57cec5SDimitry Andric 4960b57cec5SDimitry Andric } // __kmp_env_block_var 4970b57cec5SDimitry Andric 4980b57cec5SDimitry Andric // end of file // 499