- RtlSetEnvironmentVariable: Removing a variable that didn't exist in the first place...
[reactos.git] / reactos / dll / win32 / kernel32 / misc / env.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/misc/env.c
6 * PURPOSE: Environment functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 #include <k32.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 /* FUNCTIONS ******************************************************************/
19
20 /*
21 * @implemented
22 */
23 DWORD
24 WINAPI
25 GetEnvironmentVariableA (
26 LPCSTR lpName,
27 LPSTR lpBuffer,
28 DWORD nSize
29 )
30 {
31 ANSI_STRING VarName;
32 ANSI_STRING VarValue;
33 UNICODE_STRING VarNameU;
34 UNICODE_STRING VarValueU;
35 NTSTATUS Status;
36
37 /* initialize unicode variable name string */
38 RtlInitAnsiString (&VarName,
39 (LPSTR)lpName);
40 RtlAnsiStringToUnicodeString (&VarNameU,
41 &VarName,
42 TRUE);
43
44 /* initialize ansi variable value string */
45 VarValue.Length = 0;
46 VarValue.MaximumLength = (USHORT)nSize;
47 VarValue.Buffer = lpBuffer;
48
49 /* initialize unicode variable value string and allocate buffer */
50 VarValueU.Length = 0;
51 if (nSize != 0)
52 {
53 VarValueU.MaximumLength = (USHORT)(nSize - 1) * sizeof(WCHAR);
54 VarValueU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
55 0,
56 nSize * sizeof(WCHAR));
57 if (VarValueU.Buffer != NULL)
58 {
59 /* NULL-terminate the buffer in any case! RtlQueryEnvironmentVariable_U
60 only terminates it if MaximumLength < Length! */
61 VarValueU.Buffer[nSize - 1] = L'\0';
62 }
63 }
64 else
65 {
66 VarValueU.MaximumLength = 0;
67 VarValueU.Buffer = NULL;
68 }
69
70 if (VarValueU.Buffer != NULL || nSize == 0)
71 {
72 /* get unicode environment variable */
73 Status = RtlQueryEnvironmentVariable_U (NULL,
74 &VarNameU,
75 &VarValueU);
76 if (!NT_SUCCESS(Status))
77 {
78 /* free unicode buffer */
79 RtlFreeHeap (RtlGetProcessHeap (),
80 0,
81 VarValueU.Buffer);
82
83 /* free unicode variable name string */
84 RtlFreeUnicodeString (&VarNameU);
85
86 SetLastErrorByStatus (Status);
87 if (Status == STATUS_BUFFER_TOO_SMALL)
88 {
89 return (VarValueU.Length / sizeof(WCHAR)) + 1;
90 }
91 else
92 {
93 return 0;
94 }
95 }
96
97 /* convert unicode value string to ansi */
98 RtlUnicodeStringToAnsiString (&VarValue,
99 &VarValueU,
100 FALSE);
101
102 if (VarValueU.Buffer != NULL)
103 {
104 /* free unicode buffer */
105 RtlFreeHeap (RtlGetProcessHeap (),
106 0,
107 VarValueU.Buffer);
108 }
109
110 /* free unicode variable name string */
111 RtlFreeUnicodeString (&VarNameU);
112
113 return (VarValueU.Length / sizeof(WCHAR));
114 }
115 else
116 {
117 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
118 return 0;
119 }
120 }
121
122
123 /*
124 * @implemented
125 */
126 DWORD
127 WINAPI
128 GetEnvironmentVariableW (
129 LPCWSTR lpName,
130 LPWSTR lpBuffer,
131 DWORD nSize
132 )
133 {
134 UNICODE_STRING VarName;
135 UNICODE_STRING VarValue;
136 NTSTATUS Status;
137
138 RtlInitUnicodeString (&VarName,
139 lpName);
140
141 VarValue.Length = 0;
142 VarValue.MaximumLength = (USHORT) (nSize ? nSize - 1 : 0) * sizeof(WCHAR);
143 VarValue.Buffer = lpBuffer;
144
145 Status = RtlQueryEnvironmentVariable_U (NULL,
146 &VarName,
147 &VarValue);
148 if (!NT_SUCCESS(Status))
149 {
150 if (Status == STATUS_BUFFER_TOO_SMALL)
151 {
152 return (VarValue.Length / sizeof(WCHAR)) + 1;
153 }
154 else
155 {
156 SetLastErrorByStatus (Status);
157 return 0;
158 }
159 }
160
161 if (nSize != 0)
162 {
163 /* make sure the string is NULL-terminated! RtlQueryEnvironmentVariable_U
164 only terminates it if MaximumLength < Length */
165 lpBuffer[VarValue.Length / sizeof(WCHAR)] = L'\0';
166 }
167
168 return (VarValue.Length / sizeof(WCHAR));
169 }
170
171
172 /*
173 * @implemented
174 */
175 BOOL
176 WINAPI
177 SetEnvironmentVariableA (
178 LPCSTR lpName,
179 LPCSTR lpValue
180 )
181 {
182 ANSI_STRING VarName;
183 ANSI_STRING VarValue;
184 UNICODE_STRING VarNameU;
185 UNICODE_STRING VarValueU;
186 NTSTATUS Status;
187
188 DPRINT("SetEnvironmentVariableA(Name '%s', Value '%s')\n", lpName, lpValue);
189
190 RtlInitAnsiString (&VarName,
191 (LPSTR)lpName);
192 RtlAnsiStringToUnicodeString (&VarNameU,
193 &VarName,
194 TRUE);
195
196 if (lpValue)
197 {
198 RtlInitAnsiString (&VarValue,
199 (LPSTR)lpValue);
200 RtlAnsiStringToUnicodeString (&VarValueU,
201 &VarValue,
202 TRUE);
203
204 Status = RtlSetEnvironmentVariable (NULL,
205 &VarNameU,
206 &VarValueU);
207
208 RtlFreeUnicodeString (&VarValueU);
209 }
210 else
211 {
212 Status = RtlSetEnvironmentVariable (NULL,
213 &VarNameU,
214 NULL);
215 }
216 RtlFreeUnicodeString (&VarNameU);
217
218 if (!NT_SUCCESS(Status))
219 {
220 SetLastErrorByStatus (Status);
221 return FALSE;
222 }
223
224 return TRUE;
225 }
226
227
228 /*
229 * @implemented
230 */
231 BOOL
232 WINAPI
233 SetEnvironmentVariableW (
234 LPCWSTR lpName,
235 LPCWSTR lpValue
236 )
237 {
238 UNICODE_STRING VarName;
239 UNICODE_STRING VarValue;
240 NTSTATUS Status;
241
242 DPRINT("SetEnvironmentVariableW(Name '%S', Value '%S')\n", lpName, lpValue);
243
244 RtlInitUnicodeString (&VarName,
245 lpName);
246
247 RtlInitUnicodeString (&VarValue,
248 lpValue);
249
250 Status = RtlSetEnvironmentVariable (NULL,
251 &VarName,
252 &VarValue);
253
254 if (!NT_SUCCESS(Status))
255 {
256 SetLastErrorByStatus (Status);
257 return FALSE;
258 }
259
260 return TRUE;
261 }
262
263
264 /*
265 * @implemented
266 */
267 LPSTR
268 WINAPI
269 GetEnvironmentStringsA (
270 VOID
271 )
272 {
273 UNICODE_STRING UnicodeString;
274 ANSI_STRING AnsiString;
275 PWCHAR EnvU;
276 PWCHAR PtrU;
277 ULONG Length;
278 PCHAR EnvPtr = NULL;
279
280 EnvU = (PWCHAR)(NtCurrentPeb ()->ProcessParameters->Environment);
281
282 if (EnvU == NULL)
283 return NULL;
284
285 if (*EnvU == 0)
286 return NULL;
287
288 /* get environment size */
289 PtrU = EnvU;
290 while (*PtrU)
291 {
292 while (*PtrU)
293 PtrU++;
294 PtrU++;
295 }
296 Length = (ULONG)(PtrU - EnvU);
297 DPRINT("Length %lu\n", Length);
298
299 /* allocate environment buffer */
300 EnvPtr = RtlAllocateHeap (RtlGetProcessHeap (),
301 0,
302 Length + 1);
303 if (EnvPtr == NULL)
304 {
305 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
306 return NULL;
307 }
308 DPRINT("EnvPtr %p\n", EnvPtr);
309
310 /* convert unicode environment to ansi */
311 UnicodeString.MaximumLength = (USHORT)Length * sizeof(WCHAR) + sizeof(WCHAR);
312 UnicodeString.Buffer = EnvU;
313
314 AnsiString.MaximumLength = (USHORT)Length + 1;
315 AnsiString.Length = 0;
316 AnsiString.Buffer = EnvPtr;
317
318 DPRINT ("UnicodeString.Buffer \'%S\'\n", UnicodeString.Buffer);
319
320 while (*(UnicodeString.Buffer))
321 {
322 UnicodeString.Length = wcslen (UnicodeString.Buffer) * sizeof(WCHAR);
323 UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
324 if (UnicodeString.Length > 0)
325 {
326 AnsiString.Length = 0;
327 AnsiString.MaximumLength = (USHORT)Length + 1 - (AnsiString.Buffer - EnvPtr);
328
329 RtlUnicodeStringToAnsiString (&AnsiString,
330 &UnicodeString,
331 FALSE);
332
333 AnsiString.Buffer += (AnsiString.Length + 1);
334 UnicodeString.Buffer += ((UnicodeString.Length / sizeof(WCHAR)) + 1);
335 }
336 }
337 *(AnsiString.Buffer) = 0;
338
339 return EnvPtr;
340 }
341
342
343 /*
344 * @implemented
345 */
346 LPWSTR
347 WINAPI
348 GetEnvironmentStringsW (
349 VOID
350 )
351 {
352 return (LPWSTR)(NtCurrentPeb ()->ProcessParameters->Environment);
353 }
354
355
356 /*
357 * @implemented
358 */
359 BOOL
360 WINAPI
361 FreeEnvironmentStringsA (
362 LPSTR EnvironmentStrings
363 )
364 {
365 if (EnvironmentStrings == NULL)
366 return FALSE;
367
368 RtlFreeHeap (RtlGetProcessHeap (),
369 0,
370 EnvironmentStrings);
371
372 return TRUE;
373 }
374
375
376 /*
377 * @implemented
378 */
379 BOOL
380 WINAPI
381 FreeEnvironmentStringsW (
382 LPWSTR EnvironmentStrings
383 )
384 {
385 (void)EnvironmentStrings;
386 return TRUE;
387 }
388
389
390 /*
391 * @implemented
392 */
393 DWORD
394 WINAPI
395 ExpandEnvironmentStringsA (
396 LPCSTR lpSrc,
397 LPSTR lpDst,
398 DWORD nSize
399 )
400 {
401 ANSI_STRING Source;
402 ANSI_STRING Destination;
403 UNICODE_STRING SourceU;
404 UNICODE_STRING DestinationU;
405 NTSTATUS Status;
406 ULONG Length = 0;
407
408 RtlInitAnsiString (&Source,
409 (LPSTR)lpSrc);
410 Status = RtlAnsiStringToUnicodeString (&SourceU,
411 &Source,
412 TRUE);
413 if (!NT_SUCCESS(Status))
414 {
415 SetLastErrorByStatus (Status);
416 return 0;
417 }
418
419 /* make sure we don't overflow the maximum ANSI_STRING size */
420 if (nSize > 0x7fff)
421 nSize = 0x7fff;
422
423 Destination.Length = 0;
424 Destination.MaximumLength = (USHORT)nSize;
425 Destination.Buffer = lpDst;
426
427 DestinationU.Length = 0;
428 DestinationU.MaximumLength = (USHORT)nSize * sizeof(WCHAR);
429 DestinationU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
430 0,
431 DestinationU.MaximumLength);
432 if (DestinationU.Buffer == NULL)
433 {
434 RtlFreeUnicodeString(&SourceU);
435 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
436 return 0;
437 }
438
439 Status = RtlExpandEnvironmentStrings_U (NULL,
440 &SourceU,
441 &DestinationU,
442 &Length);
443
444 RtlFreeUnicodeString (&SourceU);
445
446 if (!NT_SUCCESS(Status))
447 {
448 SetLastErrorByStatus (Status);
449 if (Status != STATUS_BUFFER_TOO_SMALL)
450 {
451 RtlFreeHeap (RtlGetProcessHeap (),
452 0,
453 DestinationU.Buffer);
454 return 0;
455 }
456 }
457
458 RtlUnicodeStringToAnsiString (&Destination,
459 &DestinationU,
460 FALSE);
461
462 RtlFreeHeap (RtlGetProcessHeap (),
463 0,
464 DestinationU.Buffer);
465
466 return (Length / sizeof(WCHAR));
467 }
468
469
470 /*
471 * @implemented
472 */
473 DWORD
474 WINAPI
475 ExpandEnvironmentStringsW (
476 LPCWSTR lpSrc,
477 LPWSTR lpDst,
478 DWORD nSize
479 )
480 {
481 UNICODE_STRING Source;
482 UNICODE_STRING Destination;
483 NTSTATUS Status;
484 ULONG Length = 0;
485
486 RtlInitUnicodeString (&Source,
487 (LPWSTR)lpSrc);
488
489 /* make sure we don't overflow the maximum UNICODE_STRING size */
490 if (nSize > 0x7fff)
491 nSize = 0x7fff;
492
493 Destination.Length = 0;
494 Destination.MaximumLength = (USHORT)nSize * sizeof(WCHAR);
495 Destination.Buffer = lpDst;
496
497 Status = RtlExpandEnvironmentStrings_U (NULL,
498 &Source,
499 &Destination,
500 &Length);
501 if (!NT_SUCCESS(Status))
502 {
503 SetLastErrorByStatus (Status);
504 if (Status != STATUS_BUFFER_TOO_SMALL)
505 return 0;
506 }
507
508 return (Length / sizeof(WCHAR));
509 }
510
511 /* EOF */