e7baeaa17d312214d742926c4437467011833ab1
[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: dll/win32/kernel32/client/environ.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 = (USHORT)(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 (Status == STATUS_BUFFER_TOO_SMALL)
87 {
88 /* Fixup the length that the API returned */
89 VarValueU.MaximumLength = VarValueU.Length + sizeof(UNICODE_NULL);
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 VarValueU.Buffer = NULL;
112 }
113 }
114 else if (NT_SUCCESS(Status))
115 {
116 /* Check if the size is too big to fit */
117 UniSize = UNICODE_STRING_MAX_BYTES - 1;
118 if (nSize <= UniSize) UniSize = (USHORT)nSize;
119
120 /* Check the size */
121 Result = RtlUnicodeStringToAnsiSize(&VarValueU);
122 if (Result <= UniSize)
123 {
124 /* Convert the string */
125 RtlInitEmptyAnsiString(&VarValue, lpBuffer, UniSize);
126 Status = RtlUnicodeStringToAnsiString(&VarValue, &VarValueU, FALSE);
127 if (NT_SUCCESS(Status))
128 {
129 /* NULL-terminate and set the final length */
130 lpBuffer[VarValue.Length] = ANSI_NULL;
131 Result = VarValue.Length;
132 }
133 }
134 }
135
136 /* Release the lock */
137 RtlReleasePebLock();
138
139 Quickie:
140 /* Free the strings */
141 RtlFreeUnicodeString(&VarNameU);
142 if (VarValueU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, VarValueU.Buffer);
143
144 /* Check if we suceeded */
145 if (!NT_SUCCESS(Status))
146 {
147 /* We did not, clear the result and set the error code */
148 BaseSetLastNTError(Status);
149 Result = 0;
150 }
151
152 /* Return the result */
153 return Result;
154 }
155
156 /*
157 * @implemented
158 */
159 DWORD
160 WINAPI
161 GetEnvironmentVariableW(IN LPCWSTR lpName,
162 IN LPWSTR lpBuffer,
163 IN DWORD nSize)
164 {
165 UNICODE_STRING VarName, VarValue;
166 NTSTATUS Status;
167 USHORT UniSize;
168
169 if (nSize <= (UNICODE_STRING_MAX_CHARS - 1))
170 {
171 if (nSize)
172 {
173 UniSize = (USHORT)nSize * sizeof(WCHAR) - sizeof(UNICODE_NULL);
174 }
175 else
176 {
177 UniSize = 0;
178 }
179 }
180 else
181 {
182 UniSize = UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL);
183 }
184
185 Status = RtlInitUnicodeStringEx(&VarName, lpName);
186 if (!NT_SUCCESS(Status))
187 {
188 BaseSetLastNTError(Status);
189 return 0;
190 }
191
192 RtlInitEmptyUnicodeString(&VarValue, lpBuffer, UniSize);
193
194 Status = RtlQueryEnvironmentVariable_U(NULL, &VarName, &VarValue);
195 if (!NT_SUCCESS(Status))
196 {
197 if (Status == STATUS_BUFFER_TOO_SMALL)
198 {
199 return (VarValue.Length / sizeof(WCHAR)) + sizeof(ANSI_NULL);
200 }
201 BaseSetLastNTError (Status);
202 return 0;
203 }
204
205 lpBuffer[VarValue.Length / sizeof(WCHAR)] = UNICODE_NULL;
206
207 return (VarValue.Length / sizeof(WCHAR));
208 }
209
210 /*
211 * @implemented
212 */
213 BOOL
214 WINAPI
215 SetEnvironmentVariableA(IN LPCSTR lpName,
216 IN LPCSTR lpValue)
217 {
218 ANSI_STRING VarName, VarValue;
219 UNICODE_STRING VarNameU, VarValueU;
220 NTSTATUS Status;
221
222 RtlInitAnsiString(&VarName, (LPSTR)lpName);
223 Status = RtlAnsiStringToUnicodeString(&VarNameU, &VarName, TRUE);
224 if (NT_SUCCESS(Status))
225 {
226 if (lpValue)
227 {
228 RtlInitAnsiString(&VarValue, (LPSTR)lpValue);
229 Status = RtlAnsiStringToUnicodeString(&VarValueU, &VarValue, TRUE);
230 if (NT_SUCCESS(Status))
231 {
232 Status = RtlSetEnvironmentVariable(NULL, &VarNameU, &VarValueU);
233 RtlFreeUnicodeString(&VarValueU);
234 }
235 }
236 else
237 {
238 Status = RtlSetEnvironmentVariable(NULL, &VarNameU, NULL);
239 }
240
241 RtlFreeUnicodeString(&VarNameU);
242
243 if (NT_SUCCESS(Status)) return TRUE;
244 }
245
246 BaseSetLastNTError(Status);
247 return FALSE;
248 }
249
250 /*
251 * @implemented
252 */
253 BOOL
254 WINAPI
255 SetEnvironmentVariableW(IN LPCWSTR lpName,
256 IN LPCWSTR lpValue)
257 {
258 UNICODE_STRING VarName, VarValue;
259 NTSTATUS Status;
260
261 Status = RtlInitUnicodeStringEx(&VarName, lpName);
262 if (NT_SUCCESS(Status))
263 {
264 if (lpValue)
265 {
266 Status = RtlInitUnicodeStringEx(&VarValue, lpValue);
267 if (NT_SUCCESS(Status))
268 {
269 Status = RtlSetEnvironmentVariable(NULL, &VarName, &VarValue);
270 }
271 }
272 else
273 {
274 Status = RtlSetEnvironmentVariable(NULL, &VarName, NULL);
275 }
276
277 if (NT_SUCCESS(Status)) return TRUE;
278 }
279
280 BaseSetLastNTError(Status);
281 return FALSE;
282 }
283
284 /*
285 * @implemented
286 */
287 LPSTR
288 WINAPI
289 GetEnvironmentStringsA(VOID)
290 {
291 ULONG Length, Size;
292 NTSTATUS Status;
293 PWCHAR Environment, p;
294 PCHAR Buffer = NULL;
295
296 RtlAcquirePebLock();
297 p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
298
299 do
300 {
301 p += wcslen(p) + 1;
302 } while (*p);
303
304 Length = p - Environment + 1;
305
306 Status = RtlUnicodeToMultiByteSize(&Size, Environment, Length * sizeof(WCHAR));
307 if (NT_SUCCESS(Status))
308 {
309 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
310 if (Buffer)
311 {
312 Status = RtlUnicodeToOemN(Buffer, Size, 0, Environment, Length * sizeof(WCHAR));
313 if (!NT_SUCCESS(Status))
314 {
315 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
316 Buffer = NULL;
317
318 BaseSetLastNTError(Status);
319 }
320 }
321 else
322 {
323 BaseSetLastNTError(STATUS_NO_MEMORY);
324 }
325 }
326 else
327 {
328 BaseSetLastNTError(Status);
329 }
330
331 RtlReleasePebLock();
332 return Buffer;
333 }
334
335 /*
336 * @implemented
337 */
338 LPWSTR
339 WINAPI
340 GetEnvironmentStringsW(VOID)
341 {
342 PWCHAR Environment, p;
343 ULONG Length;
344
345 RtlAcquirePebLock();
346
347 p = Environment = NtCurrentPeb()->ProcessParameters->Environment;
348
349 do
350 {
351 p += wcslen(p) + 1;
352 } while (*p);
353
354 Length = p - Environment + 1;
355
356 p = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length * sizeof(WCHAR));
357 if (p)
358 {
359 RtlCopyMemory(p, Environment, Length * sizeof(WCHAR));
360 }
361 else
362 {
363 BaseSetLastNTError(STATUS_NO_MEMORY);
364 }
365
366 RtlReleasePebLock();
367 return p;
368 }
369
370 /*
371 * @implemented
372 */
373 BOOL
374 WINAPI
375 FreeEnvironmentStringsA(IN LPSTR EnvironmentStrings)
376 {
377 return RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
378 }
379
380 /*
381 * @implemented
382 */
383 BOOL
384 WINAPI
385 FreeEnvironmentStringsW(IN LPWSTR EnvironmentStrings)
386 {
387 return RtlFreeHeap(RtlGetProcessHeap(), 0, EnvironmentStrings);
388 }
389
390 /*
391 * @implemented
392 */
393 DWORD
394 WINAPI
395 ExpandEnvironmentStringsA(IN LPCSTR lpSrc,
396 IN LPSTR lpDst,
397 IN DWORD nSize)
398 {
399 ANSI_STRING Source, Dest;
400 UNICODE_STRING SourceU, DestU;
401 PWSTR Buffer;
402 ULONG Result = 0, Length;
403 USHORT UniSize;
404 NTSTATUS Status;
405
406 /* Check if the size is too big to fit */
407 UniSize = UNICODE_STRING_MAX_CHARS - 2;
408 if (nSize <= UniSize) UniSize = (USHORT)nSize;
409
410 /* Clear the input buffer */
411 if (lpDst) *lpDst = ANSI_NULL;
412
413 /* Initialize all the strings */
414 RtlInitAnsiString(&Source, lpSrc);
415 RtlInitUnicodeString(&SourceU, NULL);
416 RtlInitUnicodeString(&DestU, NULL);
417 Status = RtlAnsiStringToUnicodeString(&SourceU, &Source, TRUE);
418 if (!NT_SUCCESS(Status)) goto Quickie;
419
420 /* If the string fit in, make space for a NULL char */
421 if (UniSize)
422 {
423 UniSize--;
424 }
425 else
426 {
427 /* No input size, so no string size */
428 UniSize = 0;
429 }
430
431 /* Allocate the value string buffer */
432 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, UniSize * sizeof(WCHAR));
433 if (!Buffer)
434 {
435 Status = STATUS_NO_MEMORY;
436 goto Quickie;
437 }
438
439 /* And initialize its string */
440 RtlInitEmptyUnicodeString(&DestU, Buffer, UniSize * sizeof(WCHAR));
441
442 /* Query the variable */
443 Length = 0;
444 Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
445
446 /* Check if we didn't have enough space */
447 if (Status == STATUS_BUFFER_TOO_SMALL)
448 {
449 /* Fixup the length that the API returned */
450 DestU.MaximumLength = (SHORT)Length;
451
452 /* Free old Unicode buffer */
453 RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
454
455 /* Allocate new one */
456 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, Length);
457 if (Buffer)
458 {
459 /* Query the variable so we can know its size */
460 DestU.Buffer = Buffer;
461 Status = RtlExpandEnvironmentStrings_U(NULL, &SourceU, &DestU, &Length);
462 if (NT_SUCCESS(Status))
463 {
464 /* Get the ASCII length of the variable, add a byte for NULL */
465 Result = RtlUnicodeStringToAnsiSize(&DestU) + sizeof(ANSI_NULL);
466 }
467 }
468 else
469 {
470 /* Set failure status */
471 Status = STATUS_NO_MEMORY;
472 DestU.Buffer = NULL;
473 }
474 }
475 else if (NT_SUCCESS(Status))
476 {
477 /* Check if the size is too big to fit */
478 UniSize = UNICODE_STRING_MAX_BYTES - 1;
479 if (nSize <= UniSize) UniSize = (USHORT)nSize;
480
481 /* Check the size */
482 Result = RtlUnicodeStringToAnsiSize(&DestU);
483 if (Result <= UniSize)
484 {
485 /* Convert the string */
486 RtlInitEmptyAnsiString(&Dest, lpDst, UniSize);
487 Status = RtlUnicodeStringToAnsiString(&Dest, &DestU, FALSE);
488
489 /* Write a NULL-char in case of failure only */
490 if (!NT_SUCCESS(Status)) *lpDst = ANSI_NULL;
491 }
492 }
493 Quickie:
494 /* Free the strings */
495 RtlFreeUnicodeString(&SourceU);
496 if (DestU.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, DestU.Buffer);
497
498 /* Check if we suceeded */
499 if (!NT_SUCCESS(Status))
500 {
501 /* We did not, clear the result and set the error code */
502 BaseSetLastNTError(Status);
503 Result = 0;
504 }
505
506 /* Return the result */
507 return Result;
508 }
509
510 /*
511 * @implemented
512 */
513 DWORD
514 WINAPI
515 ExpandEnvironmentStringsW(IN LPCWSTR lpSrc,
516 IN LPWSTR lpDst,
517 IN DWORD nSize)
518 {
519 UNICODE_STRING Source, Destination;
520 NTSTATUS Status;
521 USHORT UniSize;
522
523 UniSize = min(nSize, UNICODE_STRING_MAX_CHARS - 2);
524
525 RtlInitUnicodeString(&Source, (LPWSTR)lpSrc);
526 RtlInitEmptyUnicodeString(&Destination, lpDst, UniSize * sizeof(WCHAR));
527
528 Status = RtlExpandEnvironmentStrings_U(NULL,
529 &Source,
530 &Destination,
531 &nSize);
532 if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
533 {
534 return nSize / sizeof(WCHAR);
535 }
536
537 BaseSetLastNTError(Status);
538 return 0;
539 }
540
541 /*
542 * @implemented
543 */
544 BOOL
545 WINAPI
546 SetEnvironmentStringsA(IN LPCH NewEnvironment)
547 {
548 STUB;
549 return FALSE;
550 }
551
552 /*
553 * @implemented
554 */
555 BOOL
556 WINAPI
557 SetEnvironmentStringsW(IN LPWCH NewEnvironment)
558 {
559 STUB;
560 return FALSE;
561 }
562
563 /* EOF */