Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337//// environment_initialization.cpp//// Copyright (c) Microsoft Corporation. All rights reserved.//// Defines functions for initializing and uninitializing the global environments// and for constructing and destroying environments. The logic for manipulating// the environment data structures is split across this file and the setenv.cpp// file.//#include <corecrt_internal_traits.h>#include <stdlib.h>#include <string.h>
// The global environment data. The initial environments store the pointer to// the environment that is passed to main or wmain. This is used only to// ensure that we do not modify that environment block after we pass it to// user code. The _environ_table and _wenviron_table hold the current CRT environment.// Their names cannot change; they are publicly documented.extern "C"{ char** __dcrt_initial_narrow_environment = nullptr; wchar_t** __dcrt_initial_wide_environment = nullptr;
__crt_state_management::dual_state_global<char**> _environ_table; __crt_state_management::dual_state_global<wchar_t**> _wenviron_table;
char*** __cdecl __p__environ() { return &_environ_table.value(); } wchar_t*** __cdecl __p__wenviron() { return &_wenviron_table.value(); }}
_Ret_opt_z_static char**& get_environment_nolock(char) throw() { return _environ_table.value(); }
_Ret_opt_z_static wchar_t**& get_environment_nolock(wchar_t) throw() { return _wenviron_table.value(); }
_Ret_opt_z_static char**& __cdecl get_initial_environment(char) throw() { return __dcrt_initial_narrow_environment; }
_Ret_opt_z_static wchar_t**& __cdecl get_initial_environment(wchar_t) throw() { return __dcrt_initial_wide_environment; }
static __crt_state_management::dual_state_global<char**>& get_dual_state_environment_nolock(char) throw() { return _environ_table; }static __crt_state_management::dual_state_global<wchar_t**>& get_dual_state_environment_nolock(wchar_t) throw() { return _wenviron_table; }
// Counts the number of environment variables in the provided 'environment_block',// excluding those that start with '=' (these are drive letter settings).template <typename Character>static size_t const count_variables_in_environment_block(Character* const environment_block) throw(){ typedef __crt_char_traits<Character> traits;
// Count the number of variables in the environment block, ignoring drive // letter settings, which begin with '=': size_t count = 0;
Character* it = environment_block; while (*it != '\0') { if (*it != '=') ++count;
// This advances the iterator to the next string: it += traits::tcslen(it) + 1; }
return count;}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Environment Create and Free (These do not modify any global data)////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// Frees the environment pointed-to by 'environment'. This function ensures that// each of the environment strings is freed and that the array itself is freed.// This function requires that 'environment' is either nullptr or that it points// to a valid environment (i.e., one composed of a sequence of zero or more non-// null pointers terminated by a null pointer).template <typename Character>static void free_environment(Character** const environment) throw(){ if (!environment) return;
for (Character** it = environment; *it; ++it) _free_crt(*it);
_free_crt(environment);}
// Creates a new environment, populating it with the strings from the provided// 'environment_block', which must be a double-null-terminated sequence of// environment variable strings of the form "name=value". Variables beginning// with '=' are ignored (these are drive letter settings). Returns the newly// created environment on succes; returns nullptr on failure.template <typename Character>static Character** const create_environment(Character* const environment_block) throw(){ typedef __crt_char_traits<Character> traits;
size_t const variable_count = count_variables_in_environment_block(environment_block);
__crt_unique_heap_ptr<Character*> environment(_calloc_crt_t(Character*, variable_count + 1)); if (!environment) return nullptr;
Character* source_it = environment_block; Character** result_it = environment.get();
while (*source_it != '\0') { size_t const required_count = traits::tcslen(source_it) + 1;
// Don't copy drive letter settings, which start with '=': if (*source_it != '=') { __crt_unique_heap_ptr<Character> variable(_calloc_crt_t(Character, required_count)); if (!variable) { free_environment(environment.detach()); return nullptr; }
_ERRCHECK(traits::tcscpy_s(variable.get(), required_count, source_it)); *result_it++ = variable.detach(); }
// This advances the iterator to the next string: source_it += required_count; }
// The sequence of pointers is already null-terminated; return it: return environment.detach();}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Environment Initialize and Uninitialize////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// In the initialize function below, we need to ensure that we've initialized// the mbc table before we start performing character transformations.static void pre_initialize(char) throw() { __acrt_initialize_multibyte(); }static void pre_initialize(wchar_t) throw() { /* no-op */ }
// Gets the current environment from the operating system and initializes the// CRT environment from that environment. Returns 0 on success; -1 on failure.// If this function returns successfully, the global environment pointer for// the requested environment will be non-null and valid.template <typename Character>static int __cdecl common_initialize_environment_nolock() throw(){ typedef __crt_char_traits<Character> traits;
// We only initialize the environment once. Once the environment has been // initialized, all updates and modifications go through the other functions // that manipulate the environment. if (get_environment_nolock(Character())) return 0;
pre_initialize(Character());
__crt_unique_heap_ptr<Character> const os_environment(traits::get_environment_from_os()); if (!os_environment) return -1;
__crt_unique_heap_ptr<Character*> crt_environment(create_environment(os_environment.get())); if (!crt_environment) return -1;
get_initial_environment(Character()) = crt_environment.get(); get_dual_state_environment_nolock(Character()).initialize(crt_environment.detach()); return 0;}
extern "C" int __cdecl _initialize_narrow_environment(){ return common_initialize_environment_nolock<char>();}
extern "C" int __cdecl _initialize_wide_environment(){ return common_initialize_environment_nolock<wchar_t>();}
// Frees the global wide and narrow environments and returns.template <typename Character>static void __cdecl uninitialize_environment_internal(Character**& environment) throw(){ if (environment == get_initial_environment(Character())) { return; }
free_environment(environment);}
extern "C" void __cdecl __dcrt_uninitialize_environments_nolock(){ _environ_table .uninitialize(uninitialize_environment_internal<char>); _wenviron_table.uninitialize(uninitialize_environment_internal<wchar_t>);
free_environment(__dcrt_initial_narrow_environment); free_environment(__dcrt_initial_wide_environment);}
//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+//// Environment Get-Or-Create////-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+// These functions help with synchronization between the narrow and wide// environments. If the requested environment has not yet been initialized but// the other environment has been initialized, the other environment is cloned// to create the requested environment. Note that if the other environment has// not yet been initialized, these functions do not do anything.
// Gets the other environment and copies each of the environment variables from// it into the requested environment. Returns 0 on success; -1 on failure.template <typename Character>static int __cdecl initialize_environment_by_cloning_nolock() throw(){ typedef __crt_char_traits<Character> traits; typedef typename traits::other_char_type other_char_type;
other_char_type** const other_environment = get_environment_nolock(other_char_type()); if (!other_environment) return -1;
for (other_char_type** it = other_environment; *it; ++it) { size_t const required_count = __crt_compute_required_transform_buffer_count(CP_ACP, *it); if (required_count == 0) return -1;
__crt_unique_heap_ptr<Character> buffer(_calloc_crt_t(Character, required_count)); if (!buffer) return -1;
size_t const actual_count = __crt_transform_string(CP_ACP, *it, buffer.get(), required_count); if (actual_count == 0) return -1;
// Ignore a failed attempt to set a variable; continue with the rest... traits::set_variable_in_environment_nolock(buffer.detach(), 0); }
return 0;}
// If the requested environment exists, this function returns it unmodified. If// the requested environment does not exist but the other environment does, the// other environment is cloned to create the requested environment, and the new// requested environment is returned. Otherwise, nullptr is returned.template <typename Character>_Deref_ret_opt_z_static Character** __cdecl common_get_or_create_environment_nolock() throw(){ typedef __crt_char_traits<Character> traits; typedef typename traits::other_char_type other_char_type;
// Check to see if the required environment already exists: Character** const existing_environment = get_environment_nolock(Character()); if (existing_environment) return existing_environment;
// Check to see if the other environment exists. We will only initialize // the environment here if the other environment was already initialized. other_char_type** const other_environment = get_environment_nolock(other_char_type()); if (!other_environment) return nullptr;
if (common_initialize_environment_nolock<Character>() != 0) { if (initialize_environment_by_cloning_nolock<Character>() != 0) { return nullptr; } }
return get_environment_nolock(Character());}
extern "C" char** __cdecl __dcrt_get_or_create_narrow_environment_nolock(){ return common_get_or_create_environment_nolock<char>();}
extern "C" wchar_t** __cdecl __dcrt_get_or_create_wide_environment_nolock(){ return common_get_or_create_environment_nolock<wchar_t>();}
template <typename Character>static Character** __cdecl common_get_initial_environment() throw(){ Character**& initial_environment = get_initial_environment(Character()); if (!initial_environment) { initial_environment = common_get_or_create_environment_nolock<Character>(); }
return initial_environment;}
extern "C" char** __cdecl _get_initial_narrow_environment(){ return common_get_initial_environment<char>();}
extern "C" wchar_t** __cdecl _get_initial_wide_environment(){ return common_get_initial_environment<wchar_t>();}