xref: /freebsd/contrib/llvm-project/openmp/runtime/src/kmp_environment.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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