1*0b57cec5SDimitry Andric /* 2*0b57cec5SDimitry Andric * kmp_environment.cpp -- Handle environment variables OS-independently. 3*0b57cec5SDimitry Andric */ 4*0b57cec5SDimitry Andric 5*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 8*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 9*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the 14*0b57cec5SDimitry Andric act of loading a DLL on Windows* OS makes any user-set environment variables 15*0b57cec5SDimitry Andric (i.e. with putenv()) unavailable. getenv() apparently gets a clean copy of 16*0b57cec5SDimitry Andric the env variables as they existed at the start of the run. JH 12/23/2002 17*0b57cec5SDimitry Andric 18*0b57cec5SDimitry Andric On Windows* OS, there are two environments (at least, see below): 19*0b57cec5SDimitry Andric 20*0b57cec5SDimitry Andric 1. Environment maintained by Windows* OS on IA-32 architecture. Accessible 21*0b57cec5SDimitry Andric through GetEnvironmentVariable(), SetEnvironmentVariable(), and 22*0b57cec5SDimitry Andric GetEnvironmentStrings(). 23*0b57cec5SDimitry Andric 24*0b57cec5SDimitry Andric 2. Environment maintained by C RTL. Accessible through getenv(), putenv(). 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric putenv() function updates both C and Windows* OS on IA-32 architecture. 27*0b57cec5SDimitry Andric getenv() function search for variables in C RTL environment only. 28*0b57cec5SDimitry Andric Windows* OS on IA-32 architecture functions work *only* with Windows* OS on 29*0b57cec5SDimitry Andric IA-32 architecture. 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric Windows* OS on IA-32 architecture maintained by OS, so there is always only 32*0b57cec5SDimitry Andric one Windows* OS on IA-32 architecture per process. Changes in Windows* OS on 33*0b57cec5SDimitry Andric IA-32 architecture are process-visible. 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric C environment maintained by C RTL. Multiple copies of C RTL may be present 36*0b57cec5SDimitry Andric in the process, and each C RTL maintains its own environment. :-( 37*0b57cec5SDimitry Andric 38*0b57cec5SDimitry Andric Thus, proper way to work with environment on Windows* OS is: 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric 1. Set variables with putenv() function -- both C and Windows* OS on IA-32 41*0b57cec5SDimitry Andric architecture are being updated. Windows* OS on IA-32 architecture may be 42*0b57cec5SDimitry Andric considered primary target, while updating C RTL environment is free bonus. 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric 2. Get variables with GetEnvironmentVariable() -- getenv() does not 45*0b57cec5SDimitry Andric search Windows* OS on IA-32 architecture, and can not see variables 46*0b57cec5SDimitry Andric set with SetEnvironmentVariable(). 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric 2007-04-05 -- lev 49*0b57cec5SDimitry Andric */ 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric #include "kmp_environment.h" 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric #include "kmp.h" // 54*0b57cec5SDimitry Andric #include "kmp_i18n.h" 55*0b57cec5SDimitry Andric #include "kmp_os.h" // KMP_OS_*. 56*0b57cec5SDimitry Andric #include "kmp_str.h" // __kmp_str_*(). 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric #if KMP_OS_UNIX 59*0b57cec5SDimitry Andric #include <stdlib.h> // getenv, setenv, unsetenv. 60*0b57cec5SDimitry Andric #include <string.h> // strlen, strcpy. 61*0b57cec5SDimitry Andric #if KMP_OS_DARWIN 62*0b57cec5SDimitry Andric #include <crt_externs.h> 63*0b57cec5SDimitry Andric #define environ (*_NSGetEnviron()) 64*0b57cec5SDimitry Andric #else 65*0b57cec5SDimitry Andric extern char **environ; 66*0b57cec5SDimitry Andric #endif 67*0b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 68*0b57cec5SDimitry Andric #include <windows.h> // GetEnvironmentVariable, SetEnvironmentVariable, 69*0b57cec5SDimitry Andric // GetLastError. 70*0b57cec5SDimitry Andric #else 71*0b57cec5SDimitry Andric #error Unknown or unsupported OS. 72*0b57cec5SDimitry Andric #endif 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric // TODO: Eliminate direct memory allocations, use string operations instead. 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric static inline void *allocate(size_t size) { 77*0b57cec5SDimitry Andric void *ptr = KMP_INTERNAL_MALLOC(size); 78*0b57cec5SDimitry Andric if (ptr == NULL) { 79*0b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed); 80*0b57cec5SDimitry Andric } 81*0b57cec5SDimitry Andric return ptr; 82*0b57cec5SDimitry Andric } // allocate 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric char *__kmp_env_get(char const *name) { 85*0b57cec5SDimitry Andric 86*0b57cec5SDimitry Andric char *result = NULL; 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric #if KMP_OS_UNIX 89*0b57cec5SDimitry Andric char const *value = getenv(name); 90*0b57cec5SDimitry Andric if (value != NULL) { 91*0b57cec5SDimitry Andric size_t len = KMP_STRLEN(value) + 1; 92*0b57cec5SDimitry Andric result = (char *)KMP_INTERNAL_MALLOC(len); 93*0b57cec5SDimitry Andric if (result == NULL) { 94*0b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed); 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric KMP_STRNCPY_S(result, len, value, len); 97*0b57cec5SDimitry Andric } 98*0b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 99*0b57cec5SDimitry Andric /* We use GetEnvironmentVariable for Windows* OS instead of getenv because the 100*0b57cec5SDimitry Andric act of loading a DLL on Windows* OS makes any user-set environment 101*0b57cec5SDimitry Andric variables (i.e. with putenv()) unavailable. getenv() apparently gets a 102*0b57cec5SDimitry Andric clean copy of the env variables as they existed at the start of the run. 103*0b57cec5SDimitry Andric JH 12/23/2002 */ 104*0b57cec5SDimitry Andric DWORD rc; 105*0b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, NULL, 0); 106*0b57cec5SDimitry Andric if (!rc) { 107*0b57cec5SDimitry Andric DWORD error = GetLastError(); 108*0b57cec5SDimitry Andric if (error != ERROR_ENVVAR_NOT_FOUND) { 109*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 110*0b57cec5SDimitry Andric } 111*0b57cec5SDimitry Andric // Variable is not found, it's ok, just continue. 112*0b57cec5SDimitry Andric } else { 113*0b57cec5SDimitry Andric DWORD len = rc; 114*0b57cec5SDimitry Andric result = (char *)KMP_INTERNAL_MALLOC(len); 115*0b57cec5SDimitry Andric if (result == NULL) { 116*0b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed); 117*0b57cec5SDimitry Andric } 118*0b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, result, len); 119*0b57cec5SDimitry Andric if (!rc) { 120*0b57cec5SDimitry Andric // GetEnvironmentVariable() may return 0 if variable is empty. 121*0b57cec5SDimitry Andric // In such a case GetLastError() returns ERROR_SUCCESS. 122*0b57cec5SDimitry Andric DWORD error = GetLastError(); 123*0b57cec5SDimitry Andric if (error != ERROR_SUCCESS) { 124*0b57cec5SDimitry Andric // Unexpected error. The variable should be in the environment, 125*0b57cec5SDimitry Andric // and buffer should be large enough. 126*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), 127*0b57cec5SDimitry Andric __kmp_msg_null); 128*0b57cec5SDimitry Andric KMP_INTERNAL_FREE((void *)result); 129*0b57cec5SDimitry Andric result = NULL; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric #else 134*0b57cec5SDimitry Andric #error Unknown or unsupported OS. 135*0b57cec5SDimitry Andric #endif 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric return result; 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric } // func __kmp_env_get 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric // TODO: Find and replace all regular free() with __kmp_env_free(). 142*0b57cec5SDimitry Andric 143*0b57cec5SDimitry Andric void __kmp_env_free(char const **value) { 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric KMP_DEBUG_ASSERT(value != NULL); 146*0b57cec5SDimitry Andric KMP_INTERNAL_FREE(CCAST(char *, *value)); 147*0b57cec5SDimitry Andric *value = NULL; 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric } // func __kmp_env_free 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric int __kmp_env_exists(char const *name) { 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric #if KMP_OS_UNIX 154*0b57cec5SDimitry Andric char const *value = getenv(name); 155*0b57cec5SDimitry Andric return ((value == NULL) ? (0) : (1)); 156*0b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 157*0b57cec5SDimitry Andric DWORD rc; 158*0b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, NULL, 0); 159*0b57cec5SDimitry Andric if (rc == 0) { 160*0b57cec5SDimitry Andric DWORD error = GetLastError(); 161*0b57cec5SDimitry Andric if (error != ERROR_ENVVAR_NOT_FOUND) { 162*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 163*0b57cec5SDimitry Andric } 164*0b57cec5SDimitry Andric return 0; 165*0b57cec5SDimitry Andric } 166*0b57cec5SDimitry Andric return 1; 167*0b57cec5SDimitry Andric #else 168*0b57cec5SDimitry Andric #error Unknown or unsupported OS. 169*0b57cec5SDimitry Andric #endif 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric } // func __kmp_env_exists 172*0b57cec5SDimitry Andric 173*0b57cec5SDimitry Andric void __kmp_env_set(char const *name, char const *value, int overwrite) { 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric #if KMP_OS_UNIX 176*0b57cec5SDimitry Andric int rc = setenv(name, value, overwrite); 177*0b57cec5SDimitry Andric if (rc != 0) { 178*0b57cec5SDimitry Andric // Dead code. I tried to put too many variables into Linux* OS 179*0b57cec5SDimitry Andric // environment on IA-32 architecture. When application consumes 180*0b57cec5SDimitry Andric // more than ~2.5 GB of memory, entire system feels bad. Sometimes 181*0b57cec5SDimitry Andric // application is killed (by OS?), sometimes system stops 182*0b57cec5SDimitry Andric // responding... But this error message never appears. --ln 183*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_HNT(NotEnoughMemory), 184*0b57cec5SDimitry Andric __kmp_msg_null); 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 187*0b57cec5SDimitry Andric BOOL rc; 188*0b57cec5SDimitry Andric if (!overwrite) { 189*0b57cec5SDimitry Andric rc = GetEnvironmentVariable(name, NULL, 0); 190*0b57cec5SDimitry Andric if (rc) { 191*0b57cec5SDimitry Andric // Variable exists, do not overwrite. 192*0b57cec5SDimitry Andric return; 193*0b57cec5SDimitry Andric } 194*0b57cec5SDimitry Andric DWORD error = GetLastError(); 195*0b57cec5SDimitry Andric if (error != ERROR_ENVVAR_NOT_FOUND) { 196*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric } 199*0b57cec5SDimitry Andric rc = SetEnvironmentVariable(name, value); 200*0b57cec5SDimitry Andric if (!rc) { 201*0b57cec5SDimitry Andric DWORD error = GetLastError(); 202*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 203*0b57cec5SDimitry Andric } 204*0b57cec5SDimitry Andric #else 205*0b57cec5SDimitry Andric #error Unknown or unsupported OS. 206*0b57cec5SDimitry Andric #endif 207*0b57cec5SDimitry Andric 208*0b57cec5SDimitry Andric } // func __kmp_env_set 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric void __kmp_env_unset(char const *name) { 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric #if KMP_OS_UNIX 213*0b57cec5SDimitry Andric unsetenv(name); 214*0b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 215*0b57cec5SDimitry Andric BOOL rc = SetEnvironmentVariable(name, NULL); 216*0b57cec5SDimitry Andric if (!rc) { 217*0b57cec5SDimitry Andric DWORD error = GetLastError(); 218*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantSetEnvVar, name), KMP_ERR(error), __kmp_msg_null); 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric #else 221*0b57cec5SDimitry Andric #error Unknown or unsupported OS. 222*0b57cec5SDimitry Andric #endif 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric } // func __kmp_env_unset 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric /* Intel OpenMP RTL string representation of environment: just a string of 227*0b57cec5SDimitry Andric characters, variables are separated with vertical bars, e. g.: 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric "KMP_WARNINGS=0|KMP_AFFINITY=compact|" 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric Empty variables are allowed and ignored: 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric "||KMP_WARNINGS=1||" 234*0b57cec5SDimitry Andric */ 235*0b57cec5SDimitry Andric 236*0b57cec5SDimitry Andric static void 237*0b57cec5SDimitry Andric ___kmp_env_blk_parse_string(kmp_env_blk_t *block, // M: Env block to fill. 238*0b57cec5SDimitry Andric char const *env // I: String to parse. 239*0b57cec5SDimitry Andric ) { 240*0b57cec5SDimitry Andric 241*0b57cec5SDimitry Andric char const chr_delimiter = '|'; 242*0b57cec5SDimitry Andric char const str_delimiter[] = {chr_delimiter, 0}; 243*0b57cec5SDimitry Andric 244*0b57cec5SDimitry Andric char *bulk = NULL; 245*0b57cec5SDimitry Andric kmp_env_var_t *vars = NULL; 246*0b57cec5SDimitry Andric int count = 0; // Number of used elements in vars array. 247*0b57cec5SDimitry Andric int delimiters = 0; // Number of delimiters in input string. 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric // Copy original string, we will modify the copy. 250*0b57cec5SDimitry Andric bulk = __kmp_str_format("%s", env); 251*0b57cec5SDimitry Andric 252*0b57cec5SDimitry Andric // Loop thru all the vars in environment block. Count delimiters (maximum 253*0b57cec5SDimitry Andric // number of variables is number of delimiters plus one). 254*0b57cec5SDimitry Andric { 255*0b57cec5SDimitry Andric char const *ptr = bulk; 256*0b57cec5SDimitry Andric for (;;) { 257*0b57cec5SDimitry Andric ptr = strchr(ptr, chr_delimiter); 258*0b57cec5SDimitry Andric if (ptr == NULL) { 259*0b57cec5SDimitry Andric break; 260*0b57cec5SDimitry Andric } 261*0b57cec5SDimitry Andric ++delimiters; 262*0b57cec5SDimitry Andric ptr += 1; 263*0b57cec5SDimitry Andric } 264*0b57cec5SDimitry Andric } 265*0b57cec5SDimitry Andric 266*0b57cec5SDimitry Andric // Allocate vars array. 267*0b57cec5SDimitry Andric vars = (kmp_env_var_t *)allocate((delimiters + 1) * sizeof(kmp_env_var_t)); 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric // Loop thru all the variables. 270*0b57cec5SDimitry Andric { 271*0b57cec5SDimitry Andric char *var; // Pointer to variable (both name and value). 272*0b57cec5SDimitry Andric char *name; // Pointer to name of variable. 273*0b57cec5SDimitry Andric char *value; // Pointer to value. 274*0b57cec5SDimitry Andric char *buf; // Buffer for __kmp_str_token() function. 275*0b57cec5SDimitry Andric var = __kmp_str_token(bulk, str_delimiter, &buf); // Get the first var. 276*0b57cec5SDimitry Andric while (var != NULL) { 277*0b57cec5SDimitry Andric // Save found variable in vars array. 278*0b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value); 279*0b57cec5SDimitry Andric KMP_DEBUG_ASSERT(count < delimiters + 1); 280*0b57cec5SDimitry Andric vars[count].name = name; 281*0b57cec5SDimitry Andric vars[count].value = value; 282*0b57cec5SDimitry Andric ++count; 283*0b57cec5SDimitry Andric // Get the next var. 284*0b57cec5SDimitry Andric var = __kmp_str_token(NULL, str_delimiter, &buf); 285*0b57cec5SDimitry Andric } 286*0b57cec5SDimitry Andric } 287*0b57cec5SDimitry Andric 288*0b57cec5SDimitry Andric // Fill out result. 289*0b57cec5SDimitry Andric block->bulk = bulk; 290*0b57cec5SDimitry Andric block->vars = vars; 291*0b57cec5SDimitry Andric block->count = count; 292*0b57cec5SDimitry Andric } 293*0b57cec5SDimitry Andric 294*0b57cec5SDimitry Andric /* Windows* OS (actually, DOS) environment block is a piece of memory with 295*0b57cec5SDimitry Andric environment variables. Each variable is terminated with zero byte, entire 296*0b57cec5SDimitry Andric block is terminated with one extra zero byte, so we have two zero bytes at 297*0b57cec5SDimitry Andric the end of environment block, e. g.: 298*0b57cec5SDimitry Andric 299*0b57cec5SDimitry Andric "HOME=C:\\users\\lev\x00OS=Windows_NT\x00\x00" 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric It is not clear how empty environment is represented. "\x00\x00"? 302*0b57cec5SDimitry Andric */ 303*0b57cec5SDimitry Andric 304*0b57cec5SDimitry Andric #if KMP_OS_WINDOWS 305*0b57cec5SDimitry Andric static void ___kmp_env_blk_parse_windows( 306*0b57cec5SDimitry Andric kmp_env_blk_t *block, // M: Env block to fill. 307*0b57cec5SDimitry Andric char const *env // I: Pointer to Windows* OS (DOS) environment block. 308*0b57cec5SDimitry Andric ) { 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric char *bulk = NULL; 311*0b57cec5SDimitry Andric kmp_env_var_t *vars = NULL; 312*0b57cec5SDimitry Andric int count = 0; // Number of used elements in vars array. 313*0b57cec5SDimitry Andric int size = 0; // Size of bulk. 314*0b57cec5SDimitry Andric 315*0b57cec5SDimitry Andric char *name; // Pointer to name of variable. 316*0b57cec5SDimitry Andric char *value; // Pointer to value. 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric if (env != NULL) { 319*0b57cec5SDimitry Andric 320*0b57cec5SDimitry Andric // Loop thru all the vars in environment block. Count variables, find size 321*0b57cec5SDimitry Andric // of block. 322*0b57cec5SDimitry Andric { 323*0b57cec5SDimitry Andric char const *var; // Pointer to beginning of var. 324*0b57cec5SDimitry Andric int len; // Length of variable. 325*0b57cec5SDimitry Andric count = 0; 326*0b57cec5SDimitry Andric var = 327*0b57cec5SDimitry Andric env; // The first variable starts and beginning of environment block. 328*0b57cec5SDimitry Andric len = KMP_STRLEN(var); 329*0b57cec5SDimitry Andric while (len != 0) { 330*0b57cec5SDimitry Andric ++count; 331*0b57cec5SDimitry Andric size = size + len + 1; 332*0b57cec5SDimitry Andric var = var + len + 333*0b57cec5SDimitry Andric 1; // Move pointer to the beginning of the next variable. 334*0b57cec5SDimitry Andric len = KMP_STRLEN(var); 335*0b57cec5SDimitry Andric } 336*0b57cec5SDimitry Andric size = 337*0b57cec5SDimitry Andric size + 1; // Total size of env block, including terminating zero byte. 338*0b57cec5SDimitry Andric } 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric // Copy original block to bulk, we will modify bulk, not original block. 341*0b57cec5SDimitry Andric bulk = (char *)allocate(size); 342*0b57cec5SDimitry Andric KMP_MEMCPY_S(bulk, size, env, size); 343*0b57cec5SDimitry Andric // Allocate vars array. 344*0b57cec5SDimitry Andric vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric // Loop thru all the vars, now in bulk. 347*0b57cec5SDimitry Andric { 348*0b57cec5SDimitry Andric char *var; // Pointer to beginning of var. 349*0b57cec5SDimitry Andric int len; // Length of variable. 350*0b57cec5SDimitry Andric count = 0; 351*0b57cec5SDimitry Andric var = bulk; 352*0b57cec5SDimitry Andric len = KMP_STRLEN(var); 353*0b57cec5SDimitry Andric while (len != 0) { 354*0b57cec5SDimitry Andric // Save variable in vars array. 355*0b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value); 356*0b57cec5SDimitry Andric vars[count].name = name; 357*0b57cec5SDimitry Andric vars[count].value = value; 358*0b57cec5SDimitry Andric ++count; 359*0b57cec5SDimitry Andric // Get the next var. 360*0b57cec5SDimitry Andric var = var + len + 1; 361*0b57cec5SDimitry Andric len = KMP_STRLEN(var); 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric } 364*0b57cec5SDimitry Andric } 365*0b57cec5SDimitry Andric 366*0b57cec5SDimitry Andric // Fill out result. 367*0b57cec5SDimitry Andric block->bulk = bulk; 368*0b57cec5SDimitry Andric block->vars = vars; 369*0b57cec5SDimitry Andric block->count = count; 370*0b57cec5SDimitry Andric } 371*0b57cec5SDimitry Andric #endif 372*0b57cec5SDimitry Andric 373*0b57cec5SDimitry Andric /* Unix environment block is a array of pointers to variables, last pointer in 374*0b57cec5SDimitry Andric array is NULL: 375*0b57cec5SDimitry Andric 376*0b57cec5SDimitry Andric { "HOME=/home/lev", "TERM=xterm", NULL } 377*0b57cec5SDimitry Andric */ 378*0b57cec5SDimitry Andric 379*0b57cec5SDimitry Andric static void 380*0b57cec5SDimitry Andric ___kmp_env_blk_parse_unix(kmp_env_blk_t *block, // M: Env block to fill. 381*0b57cec5SDimitry Andric char **env // I: Unix environment to parse. 382*0b57cec5SDimitry Andric ) { 383*0b57cec5SDimitry Andric 384*0b57cec5SDimitry Andric char *bulk = NULL; 385*0b57cec5SDimitry Andric kmp_env_var_t *vars = NULL; 386*0b57cec5SDimitry Andric int count = 0; 387*0b57cec5SDimitry Andric int size = 0; // Size of bulk. 388*0b57cec5SDimitry Andric 389*0b57cec5SDimitry Andric // Count number of variables and length of required bulk. 390*0b57cec5SDimitry Andric { 391*0b57cec5SDimitry Andric count = 0; 392*0b57cec5SDimitry Andric size = 0; 393*0b57cec5SDimitry Andric while (env[count] != NULL) { 394*0b57cec5SDimitry Andric size += KMP_STRLEN(env[count]) + 1; 395*0b57cec5SDimitry Andric ++count; 396*0b57cec5SDimitry Andric } 397*0b57cec5SDimitry Andric } 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric // Allocate memory. 400*0b57cec5SDimitry Andric bulk = (char *)allocate(size); 401*0b57cec5SDimitry Andric vars = (kmp_env_var_t *)allocate(count * sizeof(kmp_env_var_t)); 402*0b57cec5SDimitry Andric 403*0b57cec5SDimitry Andric // Loop thru all the vars. 404*0b57cec5SDimitry Andric { 405*0b57cec5SDimitry Andric char *var; // Pointer to beginning of var. 406*0b57cec5SDimitry Andric char *name; // Pointer to name of variable. 407*0b57cec5SDimitry Andric char *value; // Pointer to value. 408*0b57cec5SDimitry Andric int len; // Length of variable. 409*0b57cec5SDimitry Andric int i; 410*0b57cec5SDimitry Andric var = bulk; 411*0b57cec5SDimitry Andric for (i = 0; i < count; ++i) { 412*0b57cec5SDimitry Andric // Copy variable to bulk. 413*0b57cec5SDimitry Andric len = KMP_STRLEN(env[i]); 414*0b57cec5SDimitry Andric KMP_MEMCPY_S(var, size, env[i], len + 1); 415*0b57cec5SDimitry Andric // Save found variable in vars array. 416*0b57cec5SDimitry Andric __kmp_str_split(var, '=', &name, &value); 417*0b57cec5SDimitry Andric vars[i].name = name; 418*0b57cec5SDimitry Andric vars[i].value = value; 419*0b57cec5SDimitry Andric // Move pointer. 420*0b57cec5SDimitry Andric var += len + 1; 421*0b57cec5SDimitry Andric } 422*0b57cec5SDimitry Andric } 423*0b57cec5SDimitry Andric 424*0b57cec5SDimitry Andric // Fill out result. 425*0b57cec5SDimitry Andric block->bulk = bulk; 426*0b57cec5SDimitry Andric block->vars = vars; 427*0b57cec5SDimitry Andric block->count = count; 428*0b57cec5SDimitry Andric } 429*0b57cec5SDimitry Andric 430*0b57cec5SDimitry Andric void __kmp_env_blk_init(kmp_env_blk_t *block, // M: Block to initialize. 431*0b57cec5SDimitry Andric char const *bulk // I: Initialization string, or NULL. 432*0b57cec5SDimitry Andric ) { 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric if (bulk != NULL) { 435*0b57cec5SDimitry Andric ___kmp_env_blk_parse_string(block, bulk); 436*0b57cec5SDimitry Andric } else { 437*0b57cec5SDimitry Andric #if KMP_OS_UNIX 438*0b57cec5SDimitry Andric ___kmp_env_blk_parse_unix(block, environ); 439*0b57cec5SDimitry Andric #elif KMP_OS_WINDOWS 440*0b57cec5SDimitry Andric { 441*0b57cec5SDimitry Andric char *mem = GetEnvironmentStrings(); 442*0b57cec5SDimitry Andric if (mem == NULL) { 443*0b57cec5SDimitry Andric DWORD error = GetLastError(); 444*0b57cec5SDimitry Andric __kmp_fatal(KMP_MSG(CantGetEnvironment), KMP_ERR(error), 445*0b57cec5SDimitry Andric __kmp_msg_null); 446*0b57cec5SDimitry Andric } 447*0b57cec5SDimitry Andric ___kmp_env_blk_parse_windows(block, mem); 448*0b57cec5SDimitry Andric FreeEnvironmentStrings(mem); 449*0b57cec5SDimitry Andric } 450*0b57cec5SDimitry Andric #else 451*0b57cec5SDimitry Andric #error Unknown or unsupported OS. 452*0b57cec5SDimitry Andric #endif 453*0b57cec5SDimitry Andric } 454*0b57cec5SDimitry Andric 455*0b57cec5SDimitry Andric } // __kmp_env_blk_init 456*0b57cec5SDimitry Andric 457*0b57cec5SDimitry Andric static int ___kmp_env_var_cmp( // Comparison function for qsort(). 458*0b57cec5SDimitry Andric kmp_env_var_t const *lhs, kmp_env_var_t const *rhs) { 459*0b57cec5SDimitry Andric return strcmp(lhs->name, rhs->name); 460*0b57cec5SDimitry Andric } 461*0b57cec5SDimitry Andric 462*0b57cec5SDimitry Andric void __kmp_env_blk_sort( 463*0b57cec5SDimitry Andric kmp_env_blk_t *block // M: Block of environment variables to sort. 464*0b57cec5SDimitry Andric ) { 465*0b57cec5SDimitry Andric 466*0b57cec5SDimitry Andric qsort(CCAST(kmp_env_var_t *, block->vars), block->count, 467*0b57cec5SDimitry Andric sizeof(kmp_env_var_t), 468*0b57cec5SDimitry Andric (int (*)(void const *, void const *)) & ___kmp_env_var_cmp); 469*0b57cec5SDimitry Andric 470*0b57cec5SDimitry Andric } // __kmp_env_block_sort 471*0b57cec5SDimitry Andric 472*0b57cec5SDimitry Andric void __kmp_env_blk_free( 473*0b57cec5SDimitry Andric kmp_env_blk_t *block // M: Block of environment variables to free. 474*0b57cec5SDimitry Andric ) { 475*0b57cec5SDimitry Andric 476*0b57cec5SDimitry Andric KMP_INTERNAL_FREE(CCAST(kmp_env_var_t *, block->vars)); 477*0b57cec5SDimitry Andric __kmp_str_free(&(block->bulk)); 478*0b57cec5SDimitry Andric 479*0b57cec5SDimitry Andric block->count = 0; 480*0b57cec5SDimitry Andric block->vars = NULL; 481*0b57cec5SDimitry Andric 482*0b57cec5SDimitry Andric } // __kmp_env_blk_free 483*0b57cec5SDimitry Andric 484*0b57cec5SDimitry Andric char const * // R: Value of variable or NULL if variable does not exist. 485*0b57cec5SDimitry Andric __kmp_env_blk_var( 486*0b57cec5SDimitry Andric kmp_env_blk_t *block, // I: Block of environment variables. 487*0b57cec5SDimitry Andric char const *name // I: Name of variable to find. 488*0b57cec5SDimitry Andric ) { 489*0b57cec5SDimitry Andric 490*0b57cec5SDimitry Andric int i; 491*0b57cec5SDimitry Andric for (i = 0; i < block->count; ++i) { 492*0b57cec5SDimitry Andric if (strcmp(block->vars[i].name, name) == 0) { 493*0b57cec5SDimitry Andric return block->vars[i].value; 494*0b57cec5SDimitry Andric } 495*0b57cec5SDimitry Andric } 496*0b57cec5SDimitry Andric return NULL; 497*0b57cec5SDimitry Andric 498*0b57cec5SDimitry Andric } // __kmp_env_block_var 499*0b57cec5SDimitry Andric 500*0b57cec5SDimitry Andric // end of file // 501