update for HEAD-2003091401
[reactos.git] / lib / 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 <kernel32/kernel32.h>
16
17
18 /* FUNCTIONS ******************************************************************/
19
20 /*
21  * @implemented
22  */
23 DWORD
24 STDCALL
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 = nSize;
47         VarValue.Buffer = lpBuffer;
48
49         /* initialize unicode variable value string and allocate buffer */
50         VarValueU.Length = 0;
51         VarValueU.MaximumLength = nSize * sizeof(WCHAR);
52         VarValueU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
53                                             0,
54                                             VarValueU.MaximumLength);
55
56         /* get unicode environment variable */
57         Status = RtlQueryEnvironmentVariable_U (NULL,
58                                                 &VarNameU,
59                                                 &VarValueU);
60         if (!NT_SUCCESS(Status))
61         {
62                 /* free unicode buffer */
63                 RtlFreeHeap (RtlGetProcessHeap (),
64                              0,
65                              VarValueU.Buffer);
66
67                 /* free unicode variable name string */
68                 RtlFreeUnicodeString (&VarNameU);
69
70                 SetLastErrorByStatus (Status);
71                 if (Status == STATUS_BUFFER_TOO_SMALL)
72                 {
73                         return VarValueU.Length / sizeof(WCHAR) + 1;
74                 }
75                 else
76                 {
77                         return 0;
78                 }
79         }
80
81         /* convert unicode value string to ansi */
82         RtlUnicodeStringToAnsiString (&VarValue,
83                                       &VarValueU,
84                                       FALSE);
85
86         /* free unicode buffer */
87         RtlFreeHeap (RtlGetProcessHeap (),
88                      0,
89                      VarValueU.Buffer);
90
91         /* free unicode variable name string */
92         RtlFreeUnicodeString (&VarNameU);
93
94         return (VarValueU.Length / sizeof(WCHAR));
95 }
96
97
98 /*
99  * @implemented
100  */
101 DWORD
102 STDCALL
103 GetEnvironmentVariableW (
104         LPCWSTR lpName,
105         LPWSTR  lpBuffer,
106         DWORD   nSize
107         )
108 {
109         UNICODE_STRING VarName;
110         UNICODE_STRING VarValue;
111         NTSTATUS Status;
112
113         RtlInitUnicodeString (&VarName,
114                               lpName);
115
116         VarValue.Length = 0;
117         VarValue.MaximumLength = nSize * sizeof(WCHAR);
118         VarValue.Buffer = lpBuffer;
119
120         Status = RtlQueryEnvironmentVariable_U (NULL,
121                                                 &VarName,
122                                                 &VarValue);
123         if (!NT_SUCCESS(Status))
124         {
125                 SetLastErrorByStatus (Status);
126                 if (Status == STATUS_BUFFER_TOO_SMALL)
127                 {
128                         return (VarValue.Length / sizeof(WCHAR)) + 1;
129                 }
130                 else
131                 {
132                         return 0;
133                 }
134         }
135
136         return (VarValue.Length / sizeof(WCHAR));
137 }
138
139
140 /*
141  * @implemented
142  */
143 WINBOOL
144 STDCALL
145 SetEnvironmentVariableA (
146         LPCSTR  lpName,
147         LPCSTR  lpValue
148         )
149 {
150         ANSI_STRING VarName;
151         ANSI_STRING VarValue;
152         UNICODE_STRING VarNameU;
153         UNICODE_STRING VarValueU;
154         NTSTATUS Status;
155
156         DPRINT("SetEnvironmentVariableA(Name '%s', Value '%s')\n", lpName, lpValue);
157
158         RtlInitAnsiString (&VarName,
159                            (LPSTR)lpName);
160         RtlAnsiStringToUnicodeString (&VarNameU,
161                                       &VarName,
162                                       TRUE);
163
164         RtlInitAnsiString (&VarValue,
165                            (LPSTR)lpValue);
166         RtlAnsiStringToUnicodeString (&VarValueU,
167                                       &VarValue,
168                                       TRUE);
169
170         Status = RtlSetEnvironmentVariable (NULL,
171                                             &VarNameU,
172                                             &VarValueU);
173
174         RtlFreeUnicodeString (&VarNameU);
175         RtlFreeUnicodeString (&VarValueU);
176
177         if (!NT_SUCCESS(Status))
178         {
179                 SetLastErrorByStatus (Status);
180                 return FALSE;
181         }
182
183         return TRUE;
184 }
185
186
187 /*
188  * @implemented
189  */
190 WINBOOL
191 STDCALL
192 SetEnvironmentVariableW (
193         LPCWSTR lpName,
194         LPCWSTR lpValue
195         )
196 {
197         UNICODE_STRING VarName;
198         UNICODE_STRING VarValue;
199         NTSTATUS Status;
200
201         DPRINT("SetEnvironmentVariableW(Name '%S', Value '%S')\n", lpName, lpValue);
202
203         RtlInitUnicodeString (&VarName,
204                               lpName);
205
206         RtlInitUnicodeString (&VarValue,
207                               lpValue);
208
209         Status = RtlSetEnvironmentVariable (NULL,
210                                             &VarName,
211                                             &VarValue);
212         if (!NT_SUCCESS(Status))
213         {
214                 SetLastErrorByStatus (Status);
215                 return FALSE;
216         }
217
218         return TRUE;
219 }
220
221
222 /*
223  * @implemented
224  */
225 DWORD
226 STDCALL
227 GetVersion(VOID)
228 {
229  PPEB pPeb = NtCurrentPeb();
230  DWORD nVersion;
231
232  nVersion = MAKEWORD(pPeb->OSMajorVersion, pPeb->OSMinorVersion);
233
234  /* behave consistently when posing as another operating system */
235  /* build number */
236  if(pPeb->OSPlatformId != VER_PLATFORM_WIN32_WINDOWS)
237   nVersion |= ((DWORD)(pPeb->OSBuildNumber)) << 16;
238  
239  /* non-NT platform flag */
240  if(pPeb->OSPlatformId != VER_PLATFORM_WIN32_NT)
241   nVersion |= 0x80000000;
242
243  return nVersion;
244 }
245
246
247 /*
248  * @implemented
249  */
250 WINBOOL
251 STDCALL
252 GetVersionExW(
253     LPOSVERSIONINFOW lpVersionInformation
254     )
255 {
256  PPEB pPeb = NtCurrentPeb();
257
258  /* TODO: move this into RtlGetVersion */
259  switch(lpVersionInformation->dwOSVersionInfoSize)
260  {
261   case sizeof(OSVERSIONINFOEXW):
262   {
263    LPOSVERSIONINFOEXW lpVersionInformationEx =
264     (LPOSVERSIONINFOEXW)lpVersionInformation;
265
266    lpVersionInformationEx->wServicePackMajor = pPeb->SPMajorVersion;
267    lpVersionInformationEx->wServicePackMinor = pPeb->SPMinorVersion;
268    /* TODO: read from the KUSER_SHARED_DATA */
269    lpVersionInformationEx->wSuiteMask = 0;
270    /* TODO: call RtlGetNtProductType */
271    lpVersionInformationEx->wProductType = 0;
272    /* ??? */
273    lpVersionInformationEx->wReserved = 0;
274    /* fall through */
275   }
276
277   case sizeof(OSVERSIONINFOW):
278   {
279    lpVersionInformation->dwMajorVersion = pPeb->OSMajorVersion;
280    lpVersionInformation->dwMinorVersion = pPeb->OSMinorVersion;
281    lpVersionInformation->dwBuildNumber = pPeb->OSBuildNumber;
282    lpVersionInformation->dwPlatformId = pPeb->OSPlatformId;
283
284    /* version string is "ReactOS x.y.z" */
285    wcsncpy
286    (
287     lpVersionInformation->szCSDVersion,
288     L"ReactOS " KERNEL_VERSION_STR,
289     sizeof(lpVersionInformation->szCSDVersion) / sizeof(WCHAR)
290    );
291
292    /* null-terminate, just in case */
293    lpVersionInformation->szCSDVersion
294    [
295     sizeof(lpVersionInformation->szCSDVersion) / sizeof(WCHAR) - 1
296    ] = 0;
297
298    break;
299   }
300
301   default:
302   {
303    /* unknown version information revision */
304    SetLastError(ERROR_INSUFFICIENT_BUFFER);
305    return FALSE;
306   }
307  }
308  
309  return TRUE;
310 }
311
312
313 /*
314  * @implemented
315  */
316 WINBOOL
317 STDCALL
318 GetVersionExA(
319     LPOSVERSIONINFOA lpVersionInformation
320     )
321 {
322  NTSTATUS nErrCode;
323  OSVERSIONINFOEXW oviVerInfo;
324  LPOSVERSIONINFOEXA lpVersionInformationEx;
325
326  /* UNICODE_STRING descriptor of the Unicode version string */
327  UNICODE_STRING wstrVerStr =
328  {
329   /*
330    gives extra work to RtlUnicodeStringToAnsiString, but spares us an
331    RtlInitUnicodeString round
332   */
333   0,
334   sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion),
335   oviVerInfo.szCSDVersion
336  };
337
338  /* ANSI_STRING descriptor of the ANSI version string buffer */
339  ANSI_STRING strVerStr =
340  {
341   0,
342   sizeof(((LPOSVERSIONINFOA)NULL)->szCSDVersion),
343   lpVersionInformation->szCSDVersion
344  };
345
346  switch(lpVersionInformation->dwOSVersionInfoSize)
347  {
348   case sizeof(OSVERSIONINFOEXA):
349   {
350    oviVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
351    break;
352   }
353
354   case sizeof(OSVERSIONINFOA):
355   {
356    oviVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
357    break;
358   }
359
360   default:
361   {
362    /* unknown version information revision */
363    SetLastError(ERROR_INSUFFICIENT_BUFFER);
364    return FALSE;
365   }
366  }
367
368  if(!GetVersionExW((LPOSVERSIONINFOW)&oviVerInfo))
369   return FALSE;
370
371  /* null-terminate, just in case */
372  oviVerInfo.szCSDVersion
373  [
374   sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion) /
375   sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion[0]) -
376   1
377  ] = 0;
378  wstrVerStr.Length = wcslen(wstrVerStr.Buffer) * sizeof(WCHAR);
379
380  /* convert the version string */
381  nErrCode = RtlUnicodeStringToAnsiString(&strVerStr, &wstrVerStr, FALSE);
382  
383  if(!NT_SUCCESS(nErrCode))
384  {
385   /* failure */
386   SetLastErrorByStatus(nErrCode);
387   return FALSE;
388  }
389
390  /* copy the fields */
391  lpVersionInformation->dwMajorVersion = oviVerInfo.dwMajorVersion;
392  lpVersionInformation->dwMinorVersion = oviVerInfo.dwMinorVersion;
393  lpVersionInformation->dwBuildNumber = oviVerInfo.dwBuildNumber;
394  lpVersionInformation->dwPlatformId = oviVerInfo.dwPlatformId;
395  
396  if(lpVersionInformation->dwOSVersionInfoSize < sizeof(OSVERSIONINFOEXA))
397   /* success */
398   return TRUE;
399
400  /* copy the extended fields */
401  lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
402  lpVersionInformationEx->wServicePackMajor = oviVerInfo.wServicePackMajor;
403  lpVersionInformationEx->wServicePackMinor = oviVerInfo.wServicePackMinor;
404  lpVersionInformationEx->wSuiteMask = oviVerInfo.wSuiteMask;
405  lpVersionInformationEx->wProductType = oviVerInfo.wProductType;
406  lpVersionInformationEx->wReserved = oviVerInfo.wReserved;
407
408  /* success */
409  return TRUE;
410 }
411
412
413 /*
414  * @implemented
415  */
416 LPSTR
417 STDCALL
418 GetEnvironmentStringsA (
419         VOID
420         )
421 {
422         UNICODE_STRING UnicodeString;
423         ANSI_STRING AnsiString;
424         PWCHAR EnvU;
425         PWCHAR PtrU;
426         ULONG  Length;
427         PCHAR EnvPtr = NULL;
428
429         EnvU = (PWCHAR)(NtCurrentPeb ()->ProcessParameters->Environment);
430
431         if (EnvU == NULL)
432                 return NULL;
433
434         if (*EnvU == 0)
435                 return NULL;
436
437         /* get environment size */
438         PtrU = EnvU;
439         while (*PtrU)
440         {
441                 while (*PtrU)
442                         PtrU++;
443                 PtrU++;
444         }
445         Length = (ULONG)(PtrU - EnvU);
446         DPRINT("Length %lu\n", Length);
447
448         /* allocate environment buffer */
449         EnvPtr = RtlAllocateHeap (RtlGetProcessHeap (),
450                                   0,
451                                   Length + 1);
452         DPRINT("EnvPtr %p\n", EnvPtr);
453
454         /* convert unicode environment to ansi */
455         UnicodeString.MaximumLength = Length * sizeof(WCHAR) + sizeof(WCHAR);
456         UnicodeString.Buffer = EnvU;
457
458         AnsiString.MaximumLength = Length + 1;
459         AnsiString.Length = 0;
460         AnsiString.Buffer = EnvPtr;
461
462         DPRINT ("UnicodeString.Buffer \'%S\'\n", UnicodeString.Buffer);
463
464         while (*(UnicodeString.Buffer))
465         {
466                 UnicodeString.Length = wcslen (UnicodeString.Buffer) * sizeof(WCHAR);
467                 UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
468                 if (UnicodeString.Length > 0)
469                 {
470                         AnsiString.Length = 0;
471                         AnsiString.MaximumLength = Length + 1 - (AnsiString.Buffer - EnvPtr);
472
473                         RtlUnicodeStringToAnsiString (&AnsiString,
474                                                       &UnicodeString,
475                                                       FALSE);
476
477                         AnsiString.Buffer += (AnsiString.Length + 1);
478                         UnicodeString.Buffer += ((UnicodeString.Length / sizeof(WCHAR)) + 1);
479                 }
480         }
481         *(AnsiString.Buffer) = 0;
482
483         return EnvPtr;
484 }
485
486
487 /*
488  * @implemented
489  */
490 LPWSTR
491 STDCALL
492 GetEnvironmentStringsW (
493         VOID
494         )
495 {
496         return (LPWSTR)(NtCurrentPeb ()->ProcessParameters->Environment);
497 }
498
499
500 /*
501  * @implemented
502  */
503 WINBOOL
504 STDCALL
505 FreeEnvironmentStringsA (
506         LPSTR   EnvironmentStrings
507         )
508 {
509         if (EnvironmentStrings == NULL)
510                 return FALSE;
511
512         RtlFreeHeap (RtlGetProcessHeap (),
513                      0,
514                      EnvironmentStrings);
515
516         return TRUE;
517 }
518
519
520 /*
521  * @implemented
522  */
523 WINBOOL
524 STDCALL
525 FreeEnvironmentStringsW (
526         LPWSTR  EnvironmentStrings
527         )
528 {
529  (void)EnvironmentStrings;
530  return TRUE;
531 }
532
533
534 /*
535  * @implemented
536  */
537 DWORD
538 STDCALL
539 ExpandEnvironmentStringsA (
540         LPCSTR  lpSrc,
541         LPSTR   lpDst,
542         DWORD   nSize
543         )
544 {
545         ANSI_STRING Source;
546         ANSI_STRING Destination;
547         UNICODE_STRING SourceU;
548         UNICODE_STRING DestinationU;
549         NTSTATUS Status;
550         ULONG Length = 0;
551
552         RtlInitAnsiString (&Source,
553                            (LPSTR)lpSrc);
554         RtlAnsiStringToUnicodeString (&SourceU,
555                                       &Source,
556                                       TRUE);
557
558         Destination.Length = 0;
559         Destination.MaximumLength = nSize;
560         Destination.Buffer = lpDst,
561
562         DestinationU.Length = 0;
563         DestinationU.MaximumLength = nSize * sizeof(WCHAR);
564         DestinationU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
565                                                0,
566                                                DestinationU.MaximumLength);
567
568         Status = RtlExpandEnvironmentStrings_U (NULL,
569                                                 &SourceU,
570                                                 &DestinationU,
571                                                 &Length);
572
573         RtlFreeUnicodeString (&SourceU);
574
575         if (!NT_SUCCESS(Status))
576         {
577                 RtlFreeHeap (RtlGetProcessHeap (),
578                              0,
579                              DestinationU.Buffer);
580                 SetLastErrorByStatus (Status);
581                 return 0;
582         }
583
584         RtlUnicodeStringToAnsiString (&Destination,
585                                       &DestinationU,
586                                       FALSE);
587
588         RtlFreeHeap (RtlGetProcessHeap (),
589                      0,
590                      DestinationU.Buffer);
591
592         return (Length / sizeof(WCHAR));
593 }
594
595
596 /*
597  * @implemented
598  */
599 DWORD
600 STDCALL
601 ExpandEnvironmentStringsW (
602         LPCWSTR lpSrc,
603         LPWSTR  lpDst,
604         DWORD   nSize
605         )
606 {
607         UNICODE_STRING Source;
608         UNICODE_STRING Destination;
609         NTSTATUS Status;
610         ULONG Length = 0;
611
612         RtlInitUnicodeString (&Source,
613                               (LPWSTR)lpSrc);
614
615         Destination.Length = 0;
616         Destination.MaximumLength = nSize * sizeof(WCHAR);
617         Destination.Buffer = lpDst;
618
619         Status = RtlExpandEnvironmentStrings_U (NULL,
620                                                 &Source,
621                                                 &Destination,
622                                                 &Length);
623         if (!NT_SUCCESS(Status))
624         {
625                 SetLastErrorByStatus (Status);
626                 return 0;
627         }
628
629         return (Length / sizeof(WCHAR));
630 }
631
632 /* EOF */