8948980633aff462e6c21d9d0effcef064c3b543
[reactos.git] / reactos / dll / win32 / kernel32 / client / environ.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/misc/env.c
5 * PURPOSE: Environment functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Emanuele Aliberti
8 * Thomas Weidenmueller
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES *******************************************************************/
14
15 #include <k32.h>
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* FUNCTIONS ******************************************************************/
21
22 /*
23 * @implemented
24 */
25 DWORD
26 WINAPI
27 GetEnvironmentVariableA(IN LPCSTR lpName,
28 IN LPSTR lpBuffer,
29 IN DWORD nSize)
30 {
31 ANSI_STRING VarName, VarValue;
32 UNICODE_STRING VarNameU, VarValueU;
33 PWSTR Buffer;
34 ULONG Result = 0;
35 USHORT UniSize;
36 NTSTATUS Status;
37
38 /* Initialize all the strings */
39 RtlInitAnsiString(&VarName, lpName);
40 RtlInitUnicodeString(&VarNameU, NULL);
41 RtlInitUnicodeString(&VarValueU, NULL);
42 Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
43 if (!NT_SUCCESS(Status)) goto Quickie;
44
45 /* Check if the size is too big to fit */
46 UniSize = UNICODE_STRING_MAX_CHARS - 2;
47 if (nSize <= UniSize)
48 {
49 /* It fits, but was there a string at all? */
50 if (nSize)
51 {
52 /* Keep the given size, minus a NULL-char */
53 UniSize = nSize - 1;
54 }
55 else
56 {
57 /* No size */
58 UniSize = 0;
59 }
60 }
61 else
62 {
63 /* String is too big, so we need to return a NULL char as well */
64 UniSize--;
65 }
66
67 /* Allocate the value string buffer */
68 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize * sizeof(WCHAR));
69 if (!Buffer)
70 {
71 Status = STATUS_NO_MEMORY;
72 goto Quickie;
73 }
74
75 /* And initialize its string */
76 RtlInitEmptyUnicodeString(&VarValueU, Buffer, UniSize * sizeof(WCHAR));
77
78 /* Acquire the PEB lock since we'll be querying variables now */
79 RtlAcquirePebLock();
80
81 /* Query the variable */
82 Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
83 if ((NT_SUCCESS(Status)) && !(nSize)) Status = STATUS_BUFFER_TOO_SMALL;
84
85 /* Check if we didn't have enough space */
86 if (!(NT_SUCCESS(Status)) && (Status == STATUS_BUFFER_TOO_SMALL))
87 {
88 /* Fixup the length that the API returned */
89 VarValueU.MaximumLength = VarValueU.Length + 2;
90
91 /* Free old Unicode buffer */
92 RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
93
94 /* Allocate new one */
95 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, VarValueU.MaximumLength);
96 if (Buffer)
97 {
98 /* Query the variable so we can know its size */
99 VarValueU.Buffer = Buffer;
100 Status = RtlQueryEnvironmentVariable_U(NULL, &VarNameU, &VarValueU);
101 if (NT_SUCCESS(Status))
102 {
103 /* Get the ASCII length of the variable */
104 Result = RtlUnicodeStringToAnsiSize(&VarValueU);
105 }
106 }
107 else
108 {
109 /* Set failure status */
110 Status = STATUS_NO_MEMORY;
111 }
112 }
113 else if (NT_SUCCESS(Status))
114 {
115 /* Check if the size is too big to fit */
116 UniSize = UNICODE_STRING_MAX_BYTES - 1;
117 if (nSize <= UniSize) UniSize = nSize;
118
119 /* Check the size */
120 Result = RtlUnicodeStringToAnsiSize(&VarValueU);
121 if (Result <= UniSize)
122 {
123 /* Convert the string */
124 RtlInitEmptyAnsiString(&VarValue, lpBuffer, UniSize);
125 Status = RtlUnicodeStringToAnsiString(&VarValue, &VarValueU, FALSE);
126 if (NT_SUCCESS(Status))
127 {
128 /* NULL-terminate and set the final length */
129 lpBuffer[VarValue.Length] = ANSI_NULL;
130 Result = VarValue.Length;
131 }
132 }
133 }
134
135 /* Release the lock */
136 RtlReleasePebLock();
137
138 Quickie:
139 /* Free the strings */
140 RtlFreeUnicodeString(&VarNameU);
141 if (VarValueU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
142
143 /* Check if we suceeded */
144 if (!NT_SUCCESS(Status))
145 {
146 /* We did not, clear the result and set the error code */
147 BaseSetLastNTError(Status);
148 Result = 0;
149 }
150
151 /* Return the result */
152 return Result;
153 }
154
155 /*
156 * @implemented
157 */
158 DWORD
159 WINAPI
160 GetEnvironmentVariableW(IN LPCWSTR lpName,
161 IN LPWSTR lpBuffer,
162 IN DWORD nSize)
163 {
164 UNICODE_STRING VarName, VarValue;
165 NTSTATUS Status;
166 USHORT UniSize;
167
168 if (nSize <= (UNICODE_STRING_MAX_CHARS - 1))
169 {
170 if (nSize)
171 {
172 UniSize = nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
173 }
174 else
175 {
176 UniSize = 0;
177 }
178 }
179 else
180 {
181 UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
182 }
183
184 Status = RtlInitUnicodeStringEx(&VarName, lpName);
185 if (!NT_SUCCESS(Status))
186 {
187 BaseSetLastNTError(Status);
188 return 0;
189 }
190
191 RtlInitEmptyUnicodeString(&VarValue, lpBuffer, UniSize);
192
193 Status = RtlQueryEnvironmentVariable_U(NULL, &VarName, &VarValue);
194 if (!NT_SUCCESS(Status))
195 {
196 if (Status == STATUS_BUFFER_TOO_SMALL)
197 {
198 return (VarValue.Length / sizeof(WCHAR)) + sizeof(ANSI_NULL);
199 }
200 BaseSetLastNTError (Status);
201 return 0;
202 }
203
204 lpBuffer[VarValue.Length / sizeof(WCHAR)] = UNICODE_NULL;
205
206 return (VarValue.Length / sizeof(WCHAR));
207 }
208
209 /*
210 * @implemented
211 */
212 BOOL
213 WINAPI
214 SetEnvironmentVariableA(IN LPCSTR lpName,
215 IN LPCSTR lpValue)
216 {
217 ANSI_STRING VarName, VarValue;
218 UNICODE_STRING VarNameU, VarValueU;
219 NTSTATUS Status;
220
221 RtlInitAnsiString(&VarName, (LPSTR)lpName);
222 Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
223 if (NT_SUCCESS(Status))
224 {
225 if (lpValue)
226 {
227 RtlInitAnsiString(&VarValue, (LPSTR)lpValue);
228 Status = RtlAnsiStringToUnicodeString(&VarValueU, &VarValue, TRUE);
229 if (NT_SUCCESS(Status))
230 {
231 Status = RtlSetEnvironmentVariable(NULL, &VarNameU, &VarValueU);
232 RtlFreeUnicodeString(&VarValueU);
233 }
234 }
235 else
236 {
237 Status = RtlSetEnvironmentVariable(NULL, &VarNameU, NULL);
238 }
239
240 RtlFreeUnicodeString(&VarNameU);
241
242 if (NT_SUCCESS(Status)) return TRUE;
243 }
244
245 BaseSetLastNTError(Status);
246 return FALSE;
247 }
248
249 /*
250 * @implemented
251 */
252 BOOL
253 WINAPI
254 SetEnvironmentVariableW(IN LPCWSTR lpName,
255 IN LPCWSTR lpValue)
256 {
257 UNICODE_STRING VarName, VarValue;
258 NTSTATUS Status;
259
260 Status = RtlInitUnicodeStringEx(&VarName, lpName);
261 if (NT_SUCCESS(Status))
262 {
263 if (lpValue)
264 {
265 Status = RtlInitUnicodeStringEx(&VarValue, lpValue);
266 if (NT_SUCCESS(Status))
267 {
268 Status = RtlSetEnvironmentVariable(NULL, &VarName, &VarValue);
269 }
270 }
271 else
272 {
273 Status = RtlSetEnvironmentVariable(NULL, &VarName, NULL);
274 }
275
276 if (NT_SUCCESS(Status)) return TRUE;
277 }
278
279 BaseSetLastNTError(Status);
280 return FALSE;
281 }
282
283 /*
284 * @implemented
285 */
286 LPSTR
287 WINAPI
288 GetEnvironmentStringsA(VOID)
289 {
290 ULONG Length, Size;
291 NTSTATUS Status;
292 PWCHAR Environment, p;
293 PCHAR Buffer = NULL;
294
295 RtlAcquirePebLock();
296 p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
297
298 do
299 {
300 p += wcslen(p) + 1;
301 } while (*p);
302
303 Length = p - Environment + 1;
304
305 Status = RtlUnicodeToMultiByteSize(&Size, Environment, Length * sizeof(WCHAR));
306 if (NT_SUCCESS(Status))
307 {
308 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
309 if (Buffer)
310 {
311 Status = RtlUnicodeToOemN(Buffer, Size, 0, Environment, Length * sizeof(WCHAR));
312 if (!NT_SUCCESS(Status))
313 {
314 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
315 Buffer = NULL;
316
317 BaseSetLastNTError(Status);
318 }
319 }
320 else
321 {
322 BaseSetLastNTError(STATUS_NO_MEMORY);
323 }
324 }
325 else
326 {
327 BaseSetLastNTError(Status);
328 }
329
330 RtlReleasePebLock();
331 return Buffer;
332 }
333
334 /*
335 * @implemented
336 */
337 LPWSTR
338 WINAPI
339 GetEnvironmentStringsW(VOID)
340 {
341 PWCHAR Environment, p;
342 ULONG Length;
343
344 RtlAcquirePebLock();
345
346 p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
347
348 do
349 {
350 p += wcslen(p) + 1;
351 } while (*p);
352
353 Length = p - Environment + 1;
354
355 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
356 if (p)
357 {
358 RtlCopyMemory(p, Environment, Length * sizeof(WCHAR));
359 }
360 else
361 {
362 BaseSetLastNTError(STATUS_NO_MEMORY);
363 }
364
365 RtlReleasePebLock();
366 return p;
367 }
368
369 /*
370 * @implemented
371 */
372 BOOL
373 WINAPI
374 FreeEnvironmentStringsA(IN LPSTR EnvironmentStrings)
375 {
376 return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
377 }
378
379 /*
380 * @implemented
381 */
382 BOOL
383 WINAPI
384 FreeEnvironmentStringsW(IN LPWSTR EnvironmentStrings)
385 {
386 return (BOOL)RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
387 }
388
389 /*
390 * @implemented
391 */
392 DWORD
393 WINAPI
394 ExpandEnvironmentStringsA(IN LPCSTR lpSrc,
395 IN LPSTR lpDst,
396 IN DWORD nSize)
397 {
398 ANSI_STRING Source, Dest;
399 UNICODE_STRING SourceU, DestU;
400 PWSTR Buffer;
401 ULONG Result = 0, Length;
402 USHORT UniSize;
403 NTSTATUS Status;
404
405 /* Check if the size is too big to fit */
406 UniSize = UNICODE_STRING_MAX_CHARS - 2;
407 if (nSize <= UniSize) UniSize = nSize;
408
409 /* Clear the input buffer */
410 if (lpDst) *lpDst = ANSI_NULL;
411
412 /* Initialize all the strings */
413 RtlInitAnsiString(&Source, lpSrc);
414 RtlInitUnicodeString(&SourceU, NULL);
415 RtlInitUnicodeString(&DestU, NULL);
416 Status = RtlAnsiStringToUnicodeString(&SourceU, &Source, TRUE);
417 if (!NT_SUCCESS(Status)) goto Quickie;
418
419 /* If the string fit in, make space for a NULL char */
420 if (UniSize)
421 {
422 UniSize--;
423 }
424 else
425 {
426 /* No input size, so no string size */
427 UniSize = 0;
428 }
429
430 /* Allocate the value string buffer */
431 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize * sizeof(WCHAR));
432 if (!Buffer)
433 {
434 Status = STATUS_NO_MEMORY;
435 goto Quickie;
436 }
437
438 /* And initialize its string */
439 RtlInitEmptyUnicodeString(&DestU, Buffer, UniSize * sizeof(WCHAR));
440
441 /* Query the variable */
442 Length = 0;
443 Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
444
445 /* Check if we didn't have enough space */
446 if (!(NT_SUCCESS(Status)) && (Status == STATUS_BUFFER_TOO_SMALL))
447 {
448 /* Fixup the length that the API returned */
449 DestU.MaximumLength = Length;
450
451 /* Free old Unicode buffer */
452 RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
453
454 /* Allocate new one */
455 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
456 if (Buffer)
457 {
458 /* Query the variable so we can know its size */
459 DestU.Buffer = Buffer;
460 Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
461 if (NT_SUCCESS(Status))
462 {
463 /* Get the ASCII length of the variable, add a byte for NULL */
464 Result = RtlUnicodeStringToAnsiSize(&DestU) + sizeof(ANSI_NULL);
465 }
466 }
467 else
468 {
469 /* Set failure status */
470 Status = STATUS_NO_MEMORY;
471 }
472 }
473 else if (NT_SUCCESS(Status))
474 {
475 /* Check if the size is too big to fit */
476 UniSize = UNICODE_STRING_MAX_BYTES - 1;
477 if (nSize <= UniSize) UniSize = nSize;
478
479 /* Check the size */
480 Result = RtlUnicodeStringToAnsiSize(&DestU);
481 if (Result <= UniSize)
482 {
483 /* Convert the string */
484 RtlInitEmptyAnsiString(&Dest, lpDst, UniSize);
485 Status = RtlUnicodeStringToAnsiString(&Dest, &DestU, FALSE);
486
487 /* Write a NULL-char in case of failure only */
488 if (!NT_SUCCESS(Status)) *lpDst = ANSI_NULL;
489 }
490 }
491 Quickie:
492 /* Free the strings */
493 RtlFreeUnicodeString(&SourceU);
494 if (DestU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
495
496 /* Check if we suceeded */
497 if (!NT_SUCCESS(Status))
498 {
499 /* We did not, clear the result and set the error code */
500 BaseSetLastNTError(Status);
501 Result = 0;
502 }
503
504 /* Return the result */
505 return Result;
506 }
507
508 /*
509 * @implemented
510 */
511 DWORD
512 WINAPI
513 ExpandEnvironmentStringsW(IN LPCWSTR lpSrc,
514 IN LPWSTR lpDst,
515 IN DWORD nSize)
516 {
517 UNICODE_STRING Source, Destination;
518 NTSTATUS Status;
519 USHORT UniSize;
520
521 UniSize = UNICODE_STRING_MAX_CHARS - 2;
522 if (nSize <= UniSize) UniSize = nSize;
523
524 RtlInitUnicodeString(&Source, (LPWSTR)lpSrc);
525 RtlInitEmptyUnicodeString(&Destination, lpDst, UniSize * sizeof(WCHAR));
526
527 Status = RtlExpandEnvironmentStrings_U(NULL,
528 &Source,
529 &Destination,
530 &nSize);
531 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
532 {
533 return nSize / sizeof(WCHAR);
534 }
535
536 BaseSetLastNTError(Status);
537 return 0;
538 }
539
540 /*
541 * @implemented
542 */
543 BOOL
544 WINAPI
545 SetEnvironmentStringsA(IN LPCH NewEnvironment)
546 {
547 STUB;
548 return FALSE;
549 }
550
551 /*
552 * @implemented
553 */
554 BOOL
555 WINAPI
556 SetEnvironmentStringsW(IN LPWCH NewEnvironment)
557 {
558 STUB;
559 return FALSE;
560 }
561
562 /* EOF */