ReactOS 0.4.16-dev-835-gd769f56
environment_initialization.cpp
Go to the documentation of this file.
1//
2// environment_initialization.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines functions for initializing and uninitializing the global environments
7// and for constructing and destroying environments. The logic for manipulating
8// the environment data structures is split across this file and the setenv.cpp
9// file.
10//
12#include <stdlib.h>
13#include <string.h>
14
15
16
17// The global environment data. The initial environments store the pointer to
18// the environment that is passed to main or wmain. This is used only to
19// ensure that we do not modify that environment block after we pass it to
20// user code. The _environ_table and _wenviron_table hold the current CRT environment.
21// Their names cannot change; they are publicly documented.
22extern "C"
23{
26
27 __crt_state_management::dual_state_global<char**> _environ_table;
28 __crt_state_management::dual_state_global<wchar_t**> _wenviron_table;
29
30 char*** __cdecl __p__environ() { return &_environ_table.value(); }
31 wchar_t*** __cdecl __p__wenviron() { return &_wenviron_table.value(); }
32}
33
34
35
37static char**& get_environment_nolock(char) throw() { return _environ_table.value(); }
38
40static wchar_t**& get_environment_nolock(wchar_t) throw() { return _wenviron_table.value(); }
41
44
46static wchar_t**& __cdecl get_initial_environment(wchar_t) throw() { return __dcrt_initial_wide_environment; }
47
48static __crt_state_management::dual_state_global<char**>& get_dual_state_environment_nolock(char) throw() { return _environ_table; }
49static __crt_state_management::dual_state_global<wchar_t**>& get_dual_state_environment_nolock(wchar_t) throw() { return _wenviron_table; }
50
51
52
53// Counts the number of environment variables in the provided 'environment_block',
54// excluding those that start with '=' (these are drive letter settings).
55template <typename Character>
56static size_t const count_variables_in_environment_block(Character* const environment_block) throw()
57{
58 typedef __crt_char_traits<Character> traits;
59
60 // Count the number of variables in the environment block, ignoring drive
61 // letter settings, which begin with '=':
62 size_t count = 0;
63
64 Character* it = environment_block;
65 while (*it != '\0')
66 {
67 if (*it != '=')
68 ++count;
69
70 // This advances the iterator to the next string:
71 it += traits::tcslen(it) + 1;
72 }
73
74 return count;
75}
76
77
78
79//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
80//
81// Environment Create and Free (These do not modify any global data)
82//
83//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84// Frees the environment pointed-to by 'environment'. This function ensures that
85// each of the environment strings is freed and that the array itself is freed.
86// This function requires that 'environment' is either nullptr or that it points
87// to a valid environment (i.e., one composed of a sequence of zero or more non-
88// null pointers terminated by a null pointer).
89template <typename Character>
90static void free_environment(Character** const environment) throw()
91{
92 if (!environment)
93 return;
94
95 for (Character** it = environment; *it; ++it)
96 _free_crt(*it);
97
98 _free_crt(environment);
99}
100
101
102
103// Creates a new environment, populating it with the strings from the provided
104// 'environment_block', which must be a double-null-terminated sequence of
105// environment variable strings of the form "name=value". Variables beginning
106// with '=' are ignored (these are drive letter settings). Returns the newly
107// created environment on succes; returns nullptr on failure.
108template <typename Character>
109static Character** const create_environment(Character* const environment_block) throw()
110{
111 typedef __crt_char_traits<Character> traits;
112
113 size_t const variable_count = count_variables_in_environment_block(environment_block);
114
115 __crt_unique_heap_ptr<Character*> environment(_calloc_crt_t(Character*, variable_count + 1));
116 if (!environment)
117 return nullptr;
118
119 Character* source_it = environment_block;
120 Character** result_it = environment.get();
121
122 while (*source_it != '\0')
123 {
124 size_t const required_count = traits::tcslen(source_it) + 1;
125
126 // Don't copy drive letter settings, which start with '=':
127 if (*source_it != '=')
128 {
129 __crt_unique_heap_ptr<Character> variable(_calloc_crt_t(Character, required_count));
130 if (!variable)
131 {
132 free_environment(environment.detach());
133 return nullptr;
134 }
135
136 _ERRCHECK(traits::tcscpy_s(variable.get(), required_count, source_it));
137 *result_it++ = variable.detach();
138 }
139
140 // This advances the iterator to the next string:
141 source_it += required_count;
142 }
143
144 // The sequence of pointers is already null-terminated; return it:
145 return environment.detach();
146}
147
148
149
150//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151//
152// Environment Initialize and Uninitialize
153//
154//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155// In the initialize function below, we need to ensure that we've initialized
156// the mbc table before we start performing character transformations.
157static void pre_initialize(char) throw() { __acrt_initialize_multibyte(); }
158static void pre_initialize(wchar_t) throw() { /* no-op */ }
159
160
161
162// Gets the current environment from the operating system and initializes the
163// CRT environment from that environment. Returns 0 on success; -1 on failure.
164// If this function returns successfully, the global environment pointer for
165// the requested environment will be non-null and valid.
166template <typename Character>
168{
169 typedef __crt_char_traits<Character> traits;
170
171 // We only initialize the environment once. Once the environment has been
172 // initialized, all updates and modifications go through the other functions
173 // that manipulate the environment.
174 if (get_environment_nolock(Character()))
175 return 0;
176
177 pre_initialize(Character());
178
179 __crt_unique_heap_ptr<Character> const os_environment(traits::get_environment_from_os());
180 if (!os_environment)
181 return -1;
182
183 __crt_unique_heap_ptr<Character*> crt_environment(create_environment(os_environment.get()));
184 if (!crt_environment)
185 return -1;
186
187 get_initial_environment(Character()) = crt_environment.get();
188 get_dual_state_environment_nolock(Character()).initialize(crt_environment.detach());
189 return 0;
190}
191
193{
194 return common_initialize_environment_nolock<char>();
195}
196
198{
199 return common_initialize_environment_nolock<wchar_t>();
200}
201
202
203
204// Frees the global wide and narrow environments and returns.
205template <typename Character>
206static void __cdecl uninitialize_environment_internal(Character**& environment) throw()
207{
208 if (environment == get_initial_environment(Character()))
209 {
210 return;
211 }
212
213 free_environment(environment);
214}
215
217{
218 _environ_table .uninitialize(uninitialize_environment_internal<char>);
219 _wenviron_table.uninitialize(uninitialize_environment_internal<wchar_t>);
220
223}
224
225
226
227//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228//
229// Environment Get-Or-Create
230//
231//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
232// These functions help with synchronization between the narrow and wide
233// environments. If the requested environment has not yet been initialized but
234// the other environment has been initialized, the other environment is cloned
235// to create the requested environment. Note that if the other environment has
236// not yet been initialized, these functions do not do anything.
237
238// Gets the other environment and copies each of the environment variables from
239// it into the requested environment. Returns 0 on success; -1 on failure.
240template <typename Character>
242{
243 typedef __crt_char_traits<Character> traits;
244 typedef typename traits::other_char_type other_char_type;
245
246 other_char_type** const other_environment = get_environment_nolock(other_char_type());
247 if (!other_environment)
248 return -1;
249
250 for (other_char_type** it = other_environment; *it; ++it)
251 {
252 size_t const required_count = __crt_compute_required_transform_buffer_count(CP_ACP, *it);
253 if (required_count == 0)
254 return -1;
255
256 __crt_unique_heap_ptr<Character> buffer(_calloc_crt_t(Character, required_count));
257 if (!buffer)
258 return -1;
259
260 size_t const actual_count = __crt_transform_string(CP_ACP, *it, buffer.get(), required_count);
261 if (actual_count == 0)
262 return -1;
263
264 // Ignore a failed attempt to set a variable; continue with the rest...
265 traits::set_variable_in_environment_nolock(buffer.detach(), 0);
266 }
267
268 return 0;
269}
270
271
272
273// If the requested environment exists, this function returns it unmodified. If
274// the requested environment does not exist but the other environment does, the
275// other environment is cloned to create the requested environment, and the new
276// requested environment is returned. Otherwise, nullptr is returned.
277template <typename Character>
280{
281 typedef __crt_char_traits<Character> traits;
282 typedef typename traits::other_char_type other_char_type;
283
284 // Check to see if the required environment already exists:
285 Character** const existing_environment = get_environment_nolock(Character());
286 if (existing_environment)
287 return existing_environment;
288
289 // Check to see if the other environment exists. We will only initialize
290 // the environment here if the other environment was already initialized.
291 other_char_type** const other_environment = get_environment_nolock(other_char_type());
292 if (!other_environment)
293 return nullptr;
294
295 if (common_initialize_environment_nolock<Character>() != 0)
296 {
297 if (initialize_environment_by_cloning_nolock<Character>() != 0)
298 {
299 return nullptr;
300 }
301 }
302
303 return get_environment_nolock(Character());
304}
305
307{
308 return common_get_or_create_environment_nolock<char>();
309}
310
312{
313 return common_get_or_create_environment_nolock<wchar_t>();
314}
315
316template <typename Character>
318{
319 Character**& initial_environment = get_initial_environment(Character());
320 if (!initial_environment)
321 {
322 initial_environment = common_get_or_create_environment_nolock<Character>();
323 }
324
325 return initial_environment;
326}
327
329{
330 return common_get_initial_environment<char>();
331}
332
334{
335 return common_get_initial_environment<wchar_t>();
336}
#define __cdecl
Definition: accygwin.h:79
bool __cdecl __acrt_initialize_multibyte(void)
Definition: mbctype.cpp:894
#define _ERRCHECK(e)
size_t __crt_compute_required_transform_buffer_count(unsigned const code_page, _In_z_ char const *const string)
result_buffer_count char *const _In_ int const _In_ bool const _In_ unsigned const _In_ STRFLT const _In_ bool const _Inout_ __crt_cached_ptd_host &ptd throw()
Definition: cvt.cpp:119
#define CP_ACP
Definition: compat.h:109
char ***__cdecl __p__environ()
static int __cdecl common_initialize_environment_nolock()
char **__cdecl _get_initial_narrow_environment()
static _Ret_opt_z_ char **&__cdecl get_initial_environment(char)
__crt_state_management::dual_state_global< wchar_t ** > _wenviron_table
static Character **const create_environment(Character *const environment_block)
int __cdecl _initialize_wide_environment()
wchar_t **__cdecl __dcrt_get_or_create_wide_environment_nolock()
wchar_t **__cdecl _get_initial_wide_environment()
__crt_state_management::dual_state_global< char ** > _environ_table
static _Ret_opt_z_ char **& get_environment_nolock(char)
static size_t const count_variables_in_environment_block(Character *const environment_block)
static int __cdecl initialize_environment_by_cloning_nolock()
wchar_t ** __dcrt_initial_wide_environment
void __cdecl __dcrt_uninitialize_environments_nolock()
static void __cdecl uninitialize_environment_internal(Character **&environment)
static void free_environment(Character **const environment)
int __cdecl _initialize_narrow_environment()
static void pre_initialize(wchar_t)
static __crt_state_management::dual_state_global< char ** > & get_dual_state_environment_nolock(char)
static Character **__cdecl common_get_initial_environment()
static _Deref_ret_opt_z_ Character **__cdecl common_get_or_create_environment_nolock()
wchar_t ***__cdecl __p__wenviron()
char ** __dcrt_initial_narrow_environment
char **__cdecl __dcrt_get_or_create_narrow_environment_nolock()
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
GLenum GLenum variable
Definition: glext.h:9031
#define _free_crt
#define _Deref_ret_opt_z_
Definition: ms_sal.h:1207
#define _Ret_opt_z_
Definition: ms_sal.h:1220