ReactOS 0.4.16-dev-927-g467dec4
setenv.cpp File Reference
#include <corecrt_internal.h>
#include <corecrt_internal_traits.h>
#include <limits.h>
#include <stdlib.h>
Include dependency graph for setenv.cpp:

Go to the source code of this file.

Functions

static char **&__cdecl get_environment (char) throw ()
 
static wchar_t **&__cdecl get_environment (wchar_t) throw ()
 
static wchar_t **&__cdecl get_other_environment (char) throw ()
 
static char **&__cdecl get_other_environment (wchar_t) throw ()
 
static char **&__cdecl get_initial_environment (char) throw ()
 
static wchar_t **&__cdecl get_initial_environment (wchar_t) throw ()
 
template<typename Character >
static Character **__cdecl copy_environment (Character **const old_environment) throw ()
 
template<typename Character >
static void __cdecl ensure_current_environment_is_not_initial_environment_nolock () throw ()
 
template<typename Character >
static ptrdiff_t __cdecl find_in_environment_nolock (Character const *const name, size_t const length) throw ()
 
template<typename Character >
static int __cdecl common_set_variable_in_environment_nolock (Character *const option, int const is_top_level_call) throw ()
 
int __cdecl __dcrt_set_variable_in_narrow_environment_nolock (char *const option, int const is_top_level_call)
 
int __cdecl __dcrt_set_variable_in_wide_environment_nolock (wchar_t *const option, int const is_top_level_call)
 

Function Documentation

◆ __dcrt_set_variable_in_narrow_environment_nolock()

int __cdecl __dcrt_set_variable_in_narrow_environment_nolock ( char *const  option,
int const  is_top_level_call 
)

Definition at line 359 of file setenv.cpp.

363{
364 return common_set_variable_in_environment_nolock(option, is_top_level_call);
365}
static int __cdecl common_set_variable_in_environment_nolock(Character *const option, int const is_top_level_call)
Definition: setenv.cpp:164
Definition: getopt.h:109

◆ __dcrt_set_variable_in_wide_environment_nolock()

int __cdecl __dcrt_set_variable_in_wide_environment_nolock ( wchar_t *const  option,
int const  is_top_level_call 
)

Definition at line 367 of file setenv.cpp.

371{
372 return common_set_variable_in_environment_nolock(option, is_top_level_call);
373}

◆ common_set_variable_in_environment_nolock()

template<typename Character >
static int __cdecl common_set_variable_in_environment_nolock ( Character *const  option,
int const  is_top_level_call 
)
throw (
)
static

Definition at line 164 of file setenv.cpp.

168{
169 typedef __crt_char_traits<Character> traits;
170
171 // Check that the option string is valid first. Find the '=' and verify
172 // that '=' is not the first character in the string:
173 _VALIDATE_RETURN_NOEXC(option != nullptr, EINVAL, -1);
174 __crt_unique_heap_ptr<Character> owned_option(option);
175
176 Character* const equal_sign = traits::tcschr(option, '=');
177 _VALIDATE_RETURN_NOEXC(equal_sign != nullptr && equal_sign != option, EINVAL, -1);
178
179 // Internal consistency check: The environment string should never use
180 // buffers larger than _MAX_ENV. See also the SetEnvironmentVariable SDK
181 // function.
182 _ASSERTE(equal_sign - option < _MAX_ENV);
183 _ASSERTE(traits::tcsnlen(equal_sign + 1, _MAX_ENV) < _MAX_ENV);
184
185 // If the character following '=' is the terminator, we are removing the
186 // environment variable. Otherwise, we are adding or updating the variable:
187 bool const is_removal = *(equal_sign + 1) == '\0';
188
189 // At program startup, the initial environment (__dcrt_initial_narrow_environment), which is passed
190 // to main(), is backed by the same environment arrays as the global
191 // environment used by getenv, setenv, et al. We cannot modify thie initial
192 // environment, so we make a copy of it the first time we need to make any
193 // modifications to the global environment:
194 ensure_current_environment_is_not_initial_environment_nolock<Character>();
195
196 // If the required environment does not exist, see if the other environment
197 // exists; if it does, convert it to create the required environment. These
198 // functions will reenter this function once for each environment variable;
199 // we use the top-level call flag to stop recursion.
200 if (!get_environment(Character()))
201 {
202 if (is_top_level_call && get_other_environment(Character()))
203 {
204 _VALIDATE_RETURN_NOEXC(traits::get_or_create_environment_nolock() != nullptr, EINVAL, -1);
205
206 // The call to get_or_create_environment() may have initialized the
207 // current environment to the same environment that is the initial
208 // environment. Re-check and make a new copy of the environment to
209 // modify if necessary.
210 ensure_current_environment_is_not_initial_environment_nolock<Character>();
211 }
212 else
213 {
214 // If the environment doesn't exist and the requested operation is a
215 // removal, there is nothing to do (there is nothing to remove):
216 if (is_removal)
217 {
218 return 0;
219 }
220
221 // Create a new environment for each environment that does not exist.
222 // Just start each off as an empty environment:
223 if (!_environ_table.value())
224 {
225 _environ_table.value() = _calloc_crt_t(char*, 1).detach();
226 }
227
228 if (!_environ_table.value())
229 {
230 return -1;
231 }
232
233 if (!_wenviron_table.value())
234 {
235 _wenviron_table.value() = _calloc_crt_t(wchar_t*, 1).detach();
236 }
237
238 if (!_wenviron_table.value())
239 {
240 return -1;
241 }
242 }
243 }
244
245 // At this point, either [1] only one environment exists, or [2] both of the
246 // environments exist and are in-sync. The only way they can get out of sync
247 // is if there are conversion problems. For example, if the user sets two
248 // Unicode environment variables, FOO1 and FOO2, and the conversion of these
249 // to multibyte yields FOO? and FOO?, then these environment blocks will
250 // differ.
251 Character** const environment = get_environment(Character());
252 if (!environment)
253 {
254 _ASSERTE(("CRT logic error in setenv", 0));
255 return -1;
256 }
257
258 // Try to find the option in the environment...
259 ptrdiff_t const option_index = find_in_environment_nolock(option, equal_sign - option);
260
261 // ... if the string is already in the environment, we free up the original
262 // string, then install the new string or shrink the environment:
263 if (option_index >= 0 && environment[0])
264 {
265 _free_crt(environment[option_index]);
266
267 // If this is a removal, shrink the environment:
268 if (is_removal)
269 {
270 // Shift all of the entries down by one element:
271 size_t i = static_cast<size_t>(option_index);
272 for (; environment[i]; ++i)
273 {
274 environment[i] = environment[i + 1];
275 }
276
277 // Shrink the environment memory block. At this point, i is the
278 // number of elements remaining in the environment. This realloc
279 // should never fail, since we are shrinking the block, but it is
280 // best to be careful. If it does fail, it doesn't matter.
281 Character** new_environment = _recalloc_crt_t(Character*, environment, i).detach();
282 if (new_environment)
283 {
284 get_environment(Character()) = new_environment;
285 }
286 }
287 // If this is a replacement, replace the variable:
288 else
289 {
290 environment[option_index] = owned_option.detach();
291 }
292 }
293 // Otherwise, the string is not in the environment:
294 else
295 {
296 // If this is a removal, it is a no-op: the variable does not exist.
297 if (is_removal)
298 {
299 return 0;
300 }
301 // Otherwise, we need to append the string to the environment table, and
302 // we must grow the table to do this:
303 else
304 {
305 size_t const environment_count = static_cast<size_t>(-option_index);
306 if (environment_count + 2 < environment_count)
307 {
308 return -1;
309 }
310
311 if (environment_count + 2 >= SIZE_MAX / sizeof(Character*))
312 {
313 return -1;
314 }
315
316 Character** const new_environment = _recalloc_crt_t(Character*, environment, environment_count + 2).detach();
317 if (!new_environment)
318 {
319 return -1;
320 }
321
322 new_environment[environment_count] = owned_option.detach();
323 new_environment[environment_count + 1] = nullptr;
324
325 get_environment(Character()) = new_environment;
326 }
327 }
328
329 // Update the operating system environment. Do not give an error if this
330 // fails since the failure will not affect the user code unless it is making
331 // direct calls to the operating system. We only need to do this for one of
332 // the environments; the operating system synchronizes with the other
333 // environment automatically.
334 if (is_top_level_call)
335 {
336 size_t const count = traits::tcslen(option) + 2;
337 __crt_unique_heap_ptr<Character> const buffer(_calloc_crt_t(Character, count));
338 if (!buffer)
339 {
340 return 0;
341 }
342
343 Character* const name = buffer.get();
344 _ERRCHECK(traits::tcscpy_s(name, count, option));
345
346 Character* const value = name + (equal_sign - option) + 1;
347 *(value - 1) = '\0'; // Overwrite the '=' with a null terminator
348
349 if (traits::set_environment_variable(name, is_removal ? nullptr : value) == 0)
350 {
351 errno = EILSEQ;
352 return -1;
353 }
354 }
355
356 return 0;
357}
#define EINVAL
Definition: acclib.h:90
#define _ERRCHECK(e)
#define _ASSERTE(expr)
Definition: crtdbg.h:114
__kernel_ptrdiff_t ptrdiff_t
Definition: linux.h:247
__crt_state_management::dual_state_global< wchar_t ** > _wenviron_table
__crt_state_management::dual_state_global< char ** > _environ_table
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLuint buffer
Definition: glext.h:5915
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define _MAX_ENV
Definition: stdlib.h:118
#define _free_crt
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
#define errno
Definition: errno.h:18
#define EILSEQ
Definition: errno.h:109
#define SIZE_MAX
Definition: compat.h:66
static wchar_t **&__cdecl get_other_environment(char)
Definition: setenv.cpp:20
static ptrdiff_t __cdecl find_in_environment_nolock(Character const *const name, size_t const length)
Definition: setenv.cpp:96
static char **&__cdecl get_environment(char)
Definition: setenv.cpp:17
Definition: name.c:39
Definition: pdh_main.c:96

Referenced by __dcrt_set_variable_in_narrow_environment_nolock(), and __dcrt_set_variable_in_wide_environment_nolock().

◆ copy_environment()

template<typename Character >
static Character **__cdecl copy_environment ( Character **const  old_environment)
throw (
)
static

Definition at line 32 of file setenv.cpp.

33{
34 typedef __crt_char_traits<Character> traits;
35
36 if (!old_environment)
37 {
38 return nullptr;
39 }
40
41 // Count the number of environment variables:
42 size_t entry_count = 0;
43 for (Character** it = old_environment; *it; ++it)
44 {
45 ++entry_count;
46 }
47
48 // We need one pointer for each string, plus one null pointer at the end:
49 __crt_unique_heap_ptr<Character*> new_environment(_calloc_crt_t(Character*, entry_count + 1));
50 if (!new_environment)
51 {
52 abort();
53 }
54
55 Character** old_it = old_environment;
56 Character** new_it = new_environment.get();
57 for (; *old_it; ++old_it, ++new_it)
58 {
59 size_t const required_count = traits::tcslen(*old_it) + 1;
60 *new_it = _calloc_crt_t(Character, required_count).detach();
61 if (!*new_it)
62 {
63 abort();
64 }
65
66 _ERRCHECK(traits::tcscpy_s(*new_it, required_count, *old_it));
67 }
68
69 return new_environment.detach();
70}
#define abort()
Definition: i386-dis.c:34

Referenced by ensure_current_environment_is_not_initial_environment_nolock().

◆ ensure_current_environment_is_not_initial_environment_nolock()

template<typename Character >
static void __cdecl ensure_current_environment_is_not_initial_environment_nolock ( )
throw (
)
static

Definition at line 79 of file setenv.cpp.

80{
81 if (get_environment(Character()) == get_initial_environment(Character()))
82 {
83 get_environment(Character()) = copy_environment(get_environment(Character()));
84 }
85}
static char **&__cdecl get_initial_environment(char)
Definition: setenv.cpp:23
static Character **__cdecl copy_environment(Character **const old_environment)
Definition: setenv.cpp:32

◆ find_in_environment_nolock()

template<typename Character >
static ptrdiff_t __cdecl find_in_environment_nolock ( Character const *const  name,
size_t const  length 
)
throw (
)
static

Definition at line 96 of file setenv.cpp.

100{
101 typedef __crt_char_traits<Character> traits;
102
103 Character** const environment = get_environment(Character());
104
105 Character** it = nullptr;
106 for (it = environment; *it; ++it)
107 {
108 // See if the first 'length' characters match:
109 if (traits::tcsnicoll(name, *it, length) != 0)
110 {
111 continue;
112 }
113
114 // Ensure that the next character of the environment is an '=' or '\0':
115 if ((*it)[length] != '=' && (*it)[length] != '\0')
116 {
117 continue;
118 }
119
120 // Otherwise, this entry matched; return its index in the environment:
121 return static_cast<ptrdiff_t>(it - environment);
122 }
123
124 // No entry matched; return the total number of strings, multiplied by -1:
125 return -static_cast<ptrdiff_t>(it - environment);
126}
GLuint GLsizei GLsizei * length
Definition: glext.h:6040

Referenced by common_set_variable_in_environment_nolock().

◆ get_environment() [1/2]

static char **&__cdecl get_environment ( char  )
throw (
)
static

◆ get_environment() [2/2]

static wchar_t **&__cdecl get_environment ( wchar_t  )
throw (
)
static

Definition at line 18 of file setenv.cpp.

18{ return _wenviron_table.value(); }

◆ get_initial_environment() [1/2]

static char **&__cdecl get_initial_environment ( char  )
throw (
)
static

Definition at line 23 of file setenv.cpp.

char ** __dcrt_initial_narrow_environment

Referenced by ensure_current_environment_is_not_initial_environment_nolock().

◆ get_initial_environment() [2/2]

static wchar_t **&__cdecl get_initial_environment ( wchar_t  )
throw (
)
static

Definition at line 24 of file setenv.cpp.

wchar_t ** __dcrt_initial_wide_environment

◆ get_other_environment() [1/2]

static wchar_t **&__cdecl get_other_environment ( char  )
throw (
)
static

Definition at line 20 of file setenv.cpp.

20{ return _wenviron_table.value(); }

Referenced by common_set_variable_in_environment_nolock().

◆ get_other_environment() [2/2]

static char **&__cdecl get_other_environment ( wchar_t  )
throw (
)
static

Definition at line 21 of file setenv.cpp.

21{ return _environ_table.value(); }