strip whitespace from end of lines
[reactos.git] / reactos / lib / rtl / env.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/rtl/env.c
6 * PURPOSE: Environment functions
7 * PROGRAMMER: Eric Kohl
8 * UPDATE HISTORY:
9 * Created 30/09/98
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include "rtl.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 PPEB STDCALL RtlpCurrentPeb(VOID);
20 /* FUNCTIONS *****************************************************************/
21
22 /*
23 * @implemented
24 */
25 NTSTATUS STDCALL
26 RtlCreateEnvironment(BOOLEAN Inherit,
27 PWSTR *Environment)
28 {
29 MEMORY_BASIC_INFORMATION MemInfo;
30 PVOID EnvPtr = NULL;
31 NTSTATUS Status = STATUS_SUCCESS;
32 ULONG RegionSize = PAGE_SIZE;
33
34 if (Inherit == TRUE)
35 {
36 RtlAcquirePebLock();
37
38 if (NtCurrentPeb()->ProcessParameters->Environment != NULL)
39 {
40 Status = NtQueryVirtualMemory(NtCurrentProcess(),
41 NtCurrentPeb()->ProcessParameters->Environment,
42 MemoryBasicInformation,
43 &MemInfo,
44 sizeof(MEMORY_BASIC_INFORMATION),
45 NULL);
46 if (!NT_SUCCESS(Status))
47 {
48 RtlReleasePebLock();
49 *Environment = NULL;
50 return(Status);
51 }
52
53 RegionSize = MemInfo.RegionSize;
54 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
55 &EnvPtr,
56 0,
57 &RegionSize,
58 MEM_RESERVE | MEM_COMMIT,
59 PAGE_READWRITE);
60 if (!NT_SUCCESS(Status))
61 {
62 RtlReleasePebLock();
63 *Environment = NULL;
64 return(Status);
65 }
66
67 memmove(EnvPtr,
68 NtCurrentPeb ()->ProcessParameters->Environment,
69 MemInfo.RegionSize);
70
71 *Environment = EnvPtr;
72 }
73
74 RtlReleasePebLock ();
75 }
76 else
77 {
78 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
79 &EnvPtr,
80 0,
81 &RegionSize,
82 MEM_RESERVE | MEM_COMMIT,
83 PAGE_READWRITE);
84 if (NT_SUCCESS(Status))
85 {
86 memset(EnvPtr,
87 0,
88 RegionSize);
89 *Environment = EnvPtr;
90 }
91 }
92
93 return(Status);
94 }
95
96
97 /*
98 * @implemented
99 */
100 VOID STDCALL
101 RtlDestroyEnvironment(PWSTR Environment)
102 {
103 ULONG Size = 0;
104
105 NtFreeVirtualMemory(NtCurrentProcess(),
106 (PVOID)&Environment,
107 &Size,
108 MEM_RELEASE);
109 }
110
111
112 /*
113 * @implemented
114 */
115 NTSTATUS STDCALL
116 RtlExpandEnvironmentStrings_U(PWSTR Environment,
117 PUNICODE_STRING Source,
118 PUNICODE_STRING Destination,
119 PULONG Length)
120 {
121 UNICODE_STRING Variable;
122 UNICODE_STRING Value;
123 NTSTATUS ReturnStatus = STATUS_SUCCESS;
124 NTSTATUS Status;
125 PWSTR SourceBuffer;
126 PWSTR DestBuffer;
127 PWSTR CopyBuffer;
128 PWSTR VariableEnd;
129 ULONG SourceLength;
130 ULONG DestMax;
131 ULONG CopyLength;
132 ULONG Tail;
133 ULONG TotalLength = 1; /* for terminating NULL */
134
135 DPRINT("RtlExpandEnvironmentStrings_U %p %wZ %p %p\n",
136 Environment, Source, Destination, Length);
137
138 SourceLength = Source->Length / sizeof(WCHAR);
139 SourceBuffer = Source->Buffer;
140 DestMax = Destination->MaximumLength / sizeof(WCHAR);
141 DestBuffer = Destination->Buffer;
142
143 while (SourceLength)
144 {
145 if (*SourceBuffer != L'%')
146 {
147 CopyBuffer = SourceBuffer;
148 CopyLength = 0;
149 while (SourceLength != 0 && *SourceBuffer != L'%')
150 {
151 SourceBuffer++;
152 CopyLength++;
153 SourceLength--;
154 }
155 }
156 else
157 {
158 /* Process environment variable. */
159
160 VariableEnd = SourceBuffer + 1;
161 Tail = SourceLength - 1;
162 while (*VariableEnd != L'%' && Tail != 0)
163 {
164 VariableEnd++;
165 Tail--;
166 }
167
168 if (Tail != 0)
169 {
170 Variable.MaximumLength =
171 Variable.Length = (VariableEnd - (SourceBuffer + 1)) * sizeof(WCHAR);
172 Variable.Buffer = SourceBuffer + 1;
173
174 Value.Length = 0;
175 Value.MaximumLength = DestMax * sizeof(WCHAR);
176 Value.Buffer = DestBuffer;
177
178 Status = RtlQueryEnvironmentVariable_U(Environment, &Variable,
179 &Value);
180 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
181 {
182 SourceBuffer = VariableEnd + 1;
183 SourceLength = Tail - 1;
184 TotalLength += Value.Length / sizeof(WCHAR);
185 if (Status != STATUS_BUFFER_TOO_SMALL)
186 {
187 DestBuffer += Value.Length / sizeof(WCHAR);
188 DestMax -= Value.Length / sizeof(WCHAR);
189 }
190 else
191 {
192 DestMax = 0;
193 ReturnStatus = STATUS_BUFFER_TOO_SMALL;
194 }
195 continue;
196 }
197 else
198 {
199 /* Variable not found. */
200 CopyBuffer = SourceBuffer;
201 CopyLength = SourceLength - Tail + 1;
202 SourceLength -= CopyLength;
203 SourceBuffer += CopyLength;
204 }
205 }
206 else
207 {
208 /* Unfinished variable name. */
209 CopyBuffer = SourceBuffer;
210 CopyLength = SourceLength;
211 SourceLength = 0;
212 }
213 }
214
215 TotalLength += CopyLength;
216 if (DestMax)
217 {
218 if (DestMax < CopyLength)
219 {
220 CopyLength = DestMax;
221 ReturnStatus = STATUS_BUFFER_TOO_SMALL;
222 }
223 RtlCopyMemory(DestBuffer, CopyBuffer, CopyLength * sizeof(WCHAR));
224 DestMax -= CopyLength;
225 DestBuffer += CopyLength;
226 }
227 }
228
229 /* NULL-terminate the buffer. */
230 if (DestMax)
231 *DestBuffer = 0;
232 else
233 ReturnStatus = STATUS_BUFFER_TOO_SMALL;
234
235 Destination->Length = (DestBuffer - Destination->Buffer) * sizeof(WCHAR);
236 if (Length != NULL)
237 *Length = TotalLength * sizeof(WCHAR);
238
239 DPRINT("Destination %wZ\n", Destination);
240
241 return ReturnStatus;
242 }
243
244
245 /*
246 * @implemented
247 */
248 VOID STDCALL
249 RtlSetCurrentEnvironment(PWSTR NewEnvironment,
250 PWSTR *OldEnvironment)
251 {
252 PVOID EnvPtr;
253
254 DPRINT("NewEnvironment %x OldEnvironment %x\n",
255 NewEnvironment, OldEnvironment);
256
257 RtlAcquirePebLock();
258
259 EnvPtr = NtCurrentPeb()->ProcessParameters->Environment;
260 NtCurrentPeb()->ProcessParameters->Environment = NewEnvironment;
261
262 if (OldEnvironment != NULL)
263 *OldEnvironment = EnvPtr;
264
265 RtlReleasePebLock();
266 }
267
268
269 /*
270 * @implemented
271 */
272 NTSTATUS STDCALL
273 RtlSetEnvironmentVariable(PWSTR *Environment,
274 PUNICODE_STRING Name,
275 PUNICODE_STRING Value)
276 {
277 MEMORY_BASIC_INFORMATION mbi;
278 UNICODE_STRING var;
279 int hole_len, new_len, env_len = 0;
280 WCHAR *new_env = 0, *env_end = 0, *wcs, *env, *val = 0, *tail = 0, *hole = 0;
281 PWSTR head = NULL;
282 ULONG size = 0, new_size;
283 LONG f = 1;
284 NTSTATUS Status = STATUS_SUCCESS;
285
286 DPRINT("RtlSetEnvironmentVariable(Environment %p Name %wZ Value %wZ)\n",
287 Environment, Name, Value);
288
289 /* Variable names can't contain a '=' except as a first character. */
290 for (wcs = Name->Buffer + 1;
291 wcs < Name->Buffer + (Name->Length / sizeof(WCHAR));
292 wcs++)
293 {
294 if (*wcs == L'=')
295 return STATUS_INVALID_PARAMETER;
296 }
297
298 if (Environment)
299 {
300 env = *Environment;
301 }
302 else
303 {
304 RtlAcquirePebLock();
305 env = NtCurrentPeb()->ProcessParameters->Environment;
306 }
307
308 if (env)
309 {
310 /* get environment length */
311 wcs = env_end = env;
312 do
313 {
314 env_end += wcslen(env_end) + 1;
315 }
316 while (*env_end);
317 env_end++;
318 env_len = env_end - env;
319 DPRINT("environment length %ld characters\n", env_len);
320
321 /* find where to insert */
322 while (*wcs)
323 {
324 var.Buffer = wcs++;
325 wcs = wcschr(wcs, L'=');
326 if (wcs == NULL)
327 {
328 wcs = var.Buffer + wcslen(var.Buffer);
329 }
330 if (*wcs)
331 {
332 var.Length = (wcs - var.Buffer) * sizeof(WCHAR);
333 var.MaximumLength = var.Length;
334 val = ++wcs;
335 wcs += wcslen(wcs);
336 f = RtlCompareUnicodeString(&var, Name, TRUE);
337 if (f >= 0)
338 {
339 if (f) /* Insert before found */
340 {
341 hole = tail = var.Buffer;
342 }
343 else /* Exact match */
344 {
345 head = var.Buffer;
346 tail = ++wcs;
347 hole = val;
348 }
349 goto found;
350 }
351 }
352 wcs++;
353 }
354 hole = tail = wcs; /* Append to environment */
355 }
356
357 found:
358 if (Value != NULL && Value->Length > 0)
359 {
360 hole_len = tail - hole;
361 /* calculate new environment size */
362 new_size = Value->Length + sizeof(WCHAR);
363 /* adding new variable */
364 if (f)
365 new_size += Name->Length + sizeof(WCHAR);
366 new_len = new_size / sizeof(WCHAR);
367 if (hole_len < new_len)
368 {
369 /* enlarge environment size */
370 /* check the size of available memory */
371 new_size += (env_len - hole_len) * sizeof(WCHAR);
372 new_size = ROUNDUP(new_size, PAGE_SIZE);
373 mbi.RegionSize = 0;
374 DPRINT("new_size %lu\n", new_size);
375
376 if (env)
377 {
378 Status = NtQueryVirtualMemory(NtCurrentProcess(),
379 env,
380 MemoryBasicInformation,
381 &mbi,
382 sizeof(MEMORY_BASIC_INFORMATION),
383 NULL);
384 if (!NT_SUCCESS(Status))
385 {
386 if (Environment == NULL)
387 {
388 RtlReleasePebLock();
389 }
390 return(Status);
391 }
392 }
393
394 if (new_size > mbi.RegionSize)
395 {
396 /* reallocate memory area */
397 Status = NtAllocateVirtualMemory(NtCurrentProcess(),
398 (PVOID)&new_env,
399 0,
400 &new_size,
401 MEM_RESERVE | MEM_COMMIT,
402 PAGE_READWRITE);
403 if (!NT_SUCCESS(Status))
404 {
405 if (Environment == NULL)
406 {
407 RtlReleasePebLock();
408 }
409 return(Status);
410 }
411
412 if (env)
413 {
414 memmove(new_env,
415 env,
416 (hole - env) * sizeof(WCHAR));
417 hole = new_env + (hole - env);
418 }
419 else
420 {
421 /* absolutely new environment */
422 tail = hole = new_env;
423 *hole = 0;
424 env_end = hole + 1;
425 }
426 }
427 }
428
429 /* move tail */
430 memmove (hole + new_len, tail, (env_end - tail) * sizeof(WCHAR));
431
432 if (new_env)
433 {
434 /* we reallocated environment, let's free the old one */
435 if (Environment)
436 *Environment = new_env;
437 else
438 NtCurrentPeb()->ProcessParameters->Environment = new_env;
439
440 if (env)
441 {
442 size = 0;
443 NtFreeVirtualMemory(NtCurrentProcess(),
444 (PVOID)&env,
445 &size,
446 MEM_RELEASE);
447 }
448 }
449
450 /* and now copy given stuff */
451 if (f)
452 {
453 /* copy variable name and '=' character */
454 memmove(hole,
455 Name->Buffer,
456 Name->Length);
457 hole += Name->Length / sizeof(WCHAR);
458 *hole++ = L'=';
459 }
460
461 /* copy value */
462 memmove(hole,
463 Value->Buffer,
464 Value->Length);
465 hole += Value->Length / sizeof(WCHAR);
466 *hole = 0;
467 }
468 else
469 {
470 /* remove the environment variable */
471 if (f == 0)
472 {
473 memmove(head,
474 tail,
475 (env_end - tail) * sizeof(WCHAR));
476 }
477 else
478 {
479 Status = STATUS_VARIABLE_NOT_FOUND;
480 }
481 }
482
483 if (Environment == NULL)
484 {
485 RtlReleasePebLock();
486 }
487
488 return(Status);
489 }
490
491
492 /*
493 * @implemented
494 */
495 NTSTATUS STDCALL
496 RtlQueryEnvironmentVariable_U(PWSTR Environment,
497 PUNICODE_STRING Name,
498 PUNICODE_STRING Value)
499 {
500 NTSTATUS Status;
501 PWSTR wcs;
502 UNICODE_STRING var;
503 PWSTR val;
504 BOOLEAN SysEnvUsed = FALSE;
505
506 DPRINT("RtlQueryEnvironmentVariable_U Environment %p Variable %wZ Value %p\n",
507 Environment, Name, Value);
508
509 if (Environment == NULL)
510 {
511 PPEB Peb = RtlpCurrentPeb();
512 if (Peb) {
513 Environment = Peb->ProcessParameters->Environment;
514 SysEnvUsed = TRUE;
515 }
516 }
517
518 if (Environment == NULL)
519 return(STATUS_VARIABLE_NOT_FOUND);
520
521 Value->Length = 0;
522 if (SysEnvUsed == TRUE)
523 RtlAcquirePebLock();
524
525 wcs = Environment;
526 while (*wcs)
527 {
528 var.Buffer = wcs++;
529 wcs = wcschr(wcs, L'=');
530 if (wcs == NULL)
531 {
532 wcs = var.Buffer + wcslen(var.Buffer);
533 }
534 if (*wcs)
535 {
536 var.Length = var.MaximumLength = (wcs - var.Buffer) * sizeof(WCHAR);
537 val = ++wcs;
538 wcs += wcslen(wcs);
539
540 if (RtlEqualUnicodeString(&var, Name, TRUE))
541 {
542 Value->Length = (wcs - val) * sizeof(WCHAR);
543 if (Value->Length <= Value->MaximumLength)
544 {
545 memcpy(Value->Buffer, val,
546 min(Value->Length + sizeof(WCHAR), Value->MaximumLength));
547 DPRINT("Value %S\n", val);
548 DPRINT("Return STATUS_SUCCESS\n");
549 Status = STATUS_SUCCESS;
550 }
551 else
552 {
553 DPRINT("Return STATUS_BUFFER_TOO_SMALL\n");
554 Status = STATUS_BUFFER_TOO_SMALL;
555 }
556
557 if (SysEnvUsed == TRUE)
558 RtlReleasePebLock();
559
560 return(Status);
561 }
562 }
563 wcs++;
564 }
565
566 if (SysEnvUsed == TRUE)
567 RtlReleasePebLock();
568
569 DPRINT("Return STATUS_VARIABLE_NOT_FOUND\n");
570 return(STATUS_VARIABLE_NOT_FOUND);
571 }
572
573 /* EOF */