Reactos
1//
2// getenv.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the getenv family of functions, which search the environment for a
7// variable and return its value.
8//
9#include <corecrt_internal_traits.h>
10#include <stdlib.h>
11#include <string.h>
12
13
14
15//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16//
17// getenv() and _wgetenv()
18//
19//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20// These functions search the environment for a variable with the given name.
21// If such a variable is found, a pointer to its value is returned. Otherwise,
22// nullptr is returned. Note that if the environment is access and manipulated
23// from multiple threads, this function cannot be safely used: the returned
24// pointer may not be valid when the function returns.
25template <typename Character>
26static Character* __cdecl common_getenv_nolock(Character const* const name) throw()
27{
28 typedef __crt_char_traits<Character> traits;
29
30 Character** const environment = traits::get_or_create_environment_nolock();
31 if (environment == nullptr || name == nullptr)
32 return nullptr;
33
34 size_t const name_length = traits::tcslen(name);
35
36 for (Character** current = environment; *current; ++current)
37 {
38 if (traits::tcslen(*current) <= name_length)
39 continue;
40
41 if (*(*current + name_length) != '=')
42 continue;
43
44 if (traits::tcsnicoll(*current, name, name_length) != 0)
45 continue;
46
47 // Internal consistency check: The environment string should never use
48 // a bigger buffer than _MAX_ENV. See also the SetEnvironmentVariable
49 // SDK function.
50 _ASSERTE(traits::tcsnlen(*current + name_length + 1, _MAX_ENV) < _MAX_ENV);
51
52 return *current + name_length + 1;
53 }
54
55 return nullptr;
56}
57
58
59
60template <typename Character>
61static Character* __cdecl common_getenv(Character const* const name) throw()
62{
63 typedef __crt_char_traits<Character> traits;
64
65 _VALIDATE_RETURN(name != nullptr, EINVAL, nullptr);
66 _VALIDATE_RETURN(traits::tcsnlen(name, _MAX_ENV) < _MAX_ENV, EINVAL, nullptr);
67
68 Character* result = 0;
69
70 __acrt_lock(__acrt_environment_lock);
71 __try
72 {
73 result = common_getenv_nolock(name);
74 }
75 __finally
76 {
77 __acrt_unlock(__acrt_environment_lock);
78 }
79 __endtry
80
81 return result;
82}
83
84extern "C" char* __cdecl getenv(char const* const name)
85{
86 return common_getenv(name);
87}
88
89extern "C" wchar_t* __cdecl _wgetenv(wchar_t const* const name)
90{
91 return common_getenv(name);
92}
93
94
95
96//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97//
98// getenv_s() and _wgetenv_s()
99//
100//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101// These functions search the environment for a variable with the given name.
102// If such a variable is found, its value is copied into the provided buffer.
103// The number of characters in the value (including the null terminator) is
104// stored in '*required_count'. Returns 0 on success; returns ERANGE if the
105// provided buffer is too small; otherwise returns an error code on failure.
106template <typename Character>
107_Success_(return == 0)
108static errno_t __cdecl common_getenv_s_nolock(
109 size_t* const required_count,
110 _Out_writes_z_(buffer_count) Character* const buffer,
111 size_t const buffer_count,
112 Character const* const name
113 ) throw()
114{
115 typedef __crt_char_traits<Character> traits;
116
117 _VALIDATE_RETURN_ERRCODE(required_count != nullptr, EINVAL);
118 *required_count = 0;
119
120 _VALIDATE_RETURN_ERRCODE(
121 (buffer != nullptr && buffer_count > 0) ||
122 (buffer == nullptr && buffer_count == 0), EINVAL);
123
124 if (buffer)
125 buffer[0] = '\0';
126
127 Character const* const value = common_getenv_nolock(name);
128 if (!value)
129 return 0;
130
131 *required_count = traits::tcslen(value) + 1;
132 if (buffer_count == 0)
133 return 0;
134
135 // The buffer is too small; we return an error code and the caller can have
136 // the opportunity to try again with a larger buffer:
137 if (*required_count > buffer_count)
138 return ERANGE;
139
140 _ERRCHECK(traits::tcscpy_s(buffer, buffer_count, value));
141 return 0;
142}
143
144template <typename Character>
145_Success_(return == 0)
146static errno_t __cdecl common_getenv_s(
147 size_t* const required_count,
148 _Out_writes_z_(buffer_count) Character* const buffer,
149 size_t const buffer_count,
150 Character const* const name
151 ) throw()
152{
153 errno_t status = 0;
154
155 __acrt_lock(__acrt_environment_lock);
156 __try
157 {
158 status = common_getenv_s_nolock(required_count, buffer, buffer_count, name);
159 }
160 __finally
161 {
162 __acrt_unlock(__acrt_environment_lock);
163 }
164 __endtry
165
166 return status;
167}
168
169extern "C" errno_t __cdecl getenv_s(
170 size_t* const required_count,
171 char* const buffer,
172 size_t const buffer_count,
173 char const* const name
174 )
175{
176 return common_getenv_s(required_count, buffer, buffer_count, name);
177}
178
179extern "C" errno_t __cdecl _wgetenv_s(
180 size_t* const required_count,
181 wchar_t* const buffer,
182 size_t const buffer_count,
183 wchar_t const* const name
184 )
185{
186 return common_getenv_s(required_count, buffer, buffer_count, name);
187}
188
189
190
191//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192//
193// _dupenv_s() and _wdupenv_s()
194//
195//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
196// These functions search the environment for a variable with the given name.
197// If a variable is found, a buffer is allocated using the public malloc to hold
198// the value of the variable. The value is copied into the buffer and the buffer
199// is returned to the caller via 'buffer_pointer' and 'buffer_count'. The caller
200// is responsible for freeing the buffer.
201//
202// Returns zero on success; returns an error code on failure. Note that if a
203// variable with the specified name is not found, that is still considered a
204// success; in this case, the 'value' is an empty string ('*buffer_count' will
205// be zero and '*buffer_pointer' will be nullptr).
206template <typename Character>
207static errno_t __cdecl common_dupenv_s_nolock(
208 _Outptr_result_buffer_maybenull_(*buffer_count) _Outptr_result_maybenull_z_ Character** const buffer_pointer,
209 _Out_opt_ size_t* const buffer_count,
210 Character const* const name,
211 int const block_use,
212 char const* const file_name,
213 int const line_number
214 ) throw()
215{
216 // These are referenced only in the Debug CRT build
217 UNREFERENCED_PARAMETER(block_use);
218 UNREFERENCED_PARAMETER(file_name);
219 UNREFERENCED_PARAMETER(line_number);
220
221 typedef __crt_char_traits<Character> traits;
222
223 _VALIDATE_RETURN_ERRCODE(buffer_pointer != nullptr, EINVAL);
224 *buffer_pointer = nullptr;
225
226 if (buffer_count != nullptr)
227 *buffer_count = 0;
228
229 _VALIDATE_RETURN_ERRCODE(name != nullptr, EINVAL);
230
231 Character const* const value = common_getenv_nolock(name);
232 if (value == nullptr)
233 return 0;
234
235 size_t const value_count = traits::tcslen(value) + 1;
236
237 *buffer_pointer = static_cast<Character*>(_calloc_dbg(
238 value_count,
239 sizeof(Character),
240 block_use,
241 file_name,
242 line_number));
243 _VALIDATE_RETURN_ERRCODE_NOEXC(*buffer_pointer != nullptr, ENOMEM);
244
245 _ERRCHECK(traits::tcscpy_s(*buffer_pointer, value_count, value));
246 if (buffer_count != nullptr)
247 *buffer_count = value_count;
248
249 return 0;
250}
251
252template <typename Character>
253_Success_(return != 0)
254static errno_t __cdecl common_dupenv_s(
255 _Outptr_result_buffer_maybenull_(*buffer_count) _Outptr_result_maybenull_z_ Character** const buffer_pointer,
256 _Out_opt_ size_t* const buffer_count,
257 Character const* const name,
258 int const block_use,
259 char const* const file_name,
260 int const line_number
261 ) throw()
262{
263 errno_t status = 0;
264
265 __acrt_lock(__acrt_environment_lock);
266 __try
267 {
268 status = common_dupenv_s_nolock(
269 buffer_pointer,
270 buffer_count,
271 name,
272 block_use,
273 file_name,
274 line_number);
275 }
276 __finally
277 {
278 __acrt_unlock(__acrt_environment_lock);
279 }
280 __endtry
281
282 return status;
283}
284
285extern "C" errno_t __cdecl _dupenv_s(
286 char** const buffer_pointer,
287 size_t* const buffer_count,
288 char const* const name
289 )
290{
291 return common_dupenv_s(buffer_pointer, buffer_count, name, _NORMAL_BLOCK, nullptr, 0);
292}
293
294extern "C" errno_t __cdecl _wdupenv_s(
295 wchar_t** const buffer_pointer,
296 size_t* const buffer_count,
297 wchar_t const* const name
298 )
299{
300 return common_dupenv_s(buffer_pointer, buffer_count, name, _NORMAL_BLOCK, nullptr, 0);
301}
302
303#ifdef _DEBUG
304
305#undef _dupenv_s_dbg
306#undef _wdupenv_s_dbg
307
308extern "C" errno_t __cdecl _dupenv_s_dbg(
309 char** const buffer_pointer,
310 size_t* const buffer_count,
311 char const* const name,
312 int const block_use,
313 char const* const file_name,
314 int const line_number
315 )
316{
317 return common_dupenv_s(buffer_pointer, buffer_count, name, block_use, file_name, line_number);
318}
319
320extern "C" errno_t __cdecl _wdupenv_s_dbg(
321 wchar_t** const buffer_pointer,
322 size_t* const buffer_count,
323 wchar_t const* const name,
324 int const block_use,
325 char const* const file_name,
326 int const line_number
327 )
328{
329 return common_dupenv_s(buffer_pointer, buffer_count, name, block_use, file_name, line_number);
330}
331
332#endif // _DEBUG