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