0e32c9ef19b0925235ffacbcf2eecb830a1f1b67
[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    sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion) *
313    sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion[0]) -
314    1,
315    sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion) *
316    sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion[0]),
317   oviVerInfo.szCSDVersion
318  };
319
320  /* ANSI_STRING descriptor of the ANSI version string buffer */
321  ANSI_STRING strVerStr =
322  {
323   0,
324    sizeof(((LPOSVERSIONINFOA)NULL)->szCSDVersion) *
325    sizeof(((LPOSVERSIONINFOA)NULL)->szCSDVersion[0]) -
326    1,
327   lpVersionInformation->szCSDVersion
328  };
329
330  switch(lpVersionInformation->dwOSVersionInfoSize)
331  {
332   case sizeof(OSVERSIONINFOEXA):
333   {
334    oviVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
335    break;
336   }
337
338   case sizeof(OSVERSIONINFOA):
339   {
340    oviVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
341    break;
342   }
343
344   default:
345   {
346    /* unknown version information revision */
347    SetLastError(ERROR_INSUFFICIENT_BUFFER);
348    return FALSE;
349   }
350  }
351
352  if(!GetVersionExW((LPOSVERSIONINFOW)&oviVerInfo))
353   return FALSE;
354
355  /* null-terminate, just in case */
356  oviVerInfo.szCSDVersion
357  [
358   sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion) *
359   sizeof(((LPOSVERSIONINFOW)NULL)->szCSDVersion[0]) -
360   1
361  ] = 0;
362
363  /* convert the version string */
364  nErrCode = RtlUnicodeStringToAnsiString(&strVerStr, &wstrVerStr, FALSE);
365  
366  if(!NT_SUCCESS(nErrCode))
367  {
368   /* failure */
369   SetLastErrorByStatus(nErrCode);
370   return FALSE;
371  }
372
373  /* copy the fields */
374  lpVersionInformation->dwMajorVersion = oviVerInfo.dwMajorVersion;
375  lpVersionInformation->dwMinorVersion = oviVerInfo.dwMinorVersion;
376  lpVersionInformation->dwBuildNumber = oviVerInfo.dwBuildNumber;
377  lpVersionInformation->dwPlatformId = oviVerInfo.dwPlatformId;
378  
379  if(lpVersionInformation->dwOSVersionInfoSize < sizeof(OSVERSIONINFOEXA))
380   /* success */
381   return TRUE;
382
383  /* copy the extended fields */
384  lpVersionInformationEx = (LPOSVERSIONINFOEXA)lpVersionInformation;
385  lpVersionInformationEx->wServicePackMajor = oviVerInfo.wServicePackMajor;
386  lpVersionInformationEx->wServicePackMinor = oviVerInfo.wServicePackMinor;
387  lpVersionInformationEx->wSuiteMask = oviVerInfo.wSuiteMask;
388  lpVersionInformationEx->wProductType = oviVerInfo.wProductType;
389  lpVersionInformationEx->wReserved = oviVerInfo.wReserved;
390
391  /* success */
392  return TRUE;
393 }
394
395
396 LPSTR
397 STDCALL
398 GetEnvironmentStringsA (
399         VOID
400         )
401 {
402         UNICODE_STRING UnicodeString;
403         ANSI_STRING AnsiString;
404         PWCHAR EnvU;
405         PWCHAR PtrU;
406         ULONG  Length;
407         PCHAR EnvPtr = NULL;
408
409         EnvU = (PWCHAR)(NtCurrentPeb ()->ProcessParameters->Environment);
410
411         if (EnvU == NULL)
412                 return NULL;
413
414         if (*EnvU == 0)
415                 return NULL;
416
417         /* get environment size */
418         PtrU = EnvU;
419         while (*PtrU)
420         {
421                 while (*PtrU)
422                         PtrU++;
423                 PtrU++;
424         }
425         Length = (ULONG)(PtrU - EnvU);
426         DPRINT("Length %lu\n", Length);
427
428         /* allocate environment buffer */
429         EnvPtr = RtlAllocateHeap (RtlGetProcessHeap (),
430                                   0,
431                                   Length + 1);
432         DPRINT("EnvPtr %p\n", EnvPtr);
433
434         /* convert unicode environment to ansi */
435         UnicodeString.MaximumLength = Length * sizeof(WCHAR) + sizeof(WCHAR);
436         UnicodeString.Buffer = EnvU;
437
438         AnsiString.MaximumLength = Length + 1;
439         AnsiString.Length = 0;
440         AnsiString.Buffer = EnvPtr;
441
442         DPRINT ("UnicodeString.Buffer \'%S\'\n", UnicodeString.Buffer);
443
444         while (*(UnicodeString.Buffer))
445         {
446                 UnicodeString.Length = wcslen (UnicodeString.Buffer) * sizeof(WCHAR);
447                 UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
448                 if (UnicodeString.Length > 0)
449                 {
450                         AnsiString.Length = 0;
451                         AnsiString.MaximumLength = Length + 1 - (AnsiString.Buffer - EnvPtr);
452
453                         RtlUnicodeStringToAnsiString (&AnsiString,
454                                                       &UnicodeString,
455                                                       FALSE);
456
457                         AnsiString.Buffer += (AnsiString.Length + 1);
458                         UnicodeString.Buffer += ((UnicodeString.Length / sizeof(WCHAR)) + 1);
459                 }
460         }
461         *(AnsiString.Buffer) = 0;
462
463         return EnvPtr;
464 }
465
466
467 LPWSTR
468 STDCALL
469 GetEnvironmentStringsW (
470         VOID
471         )
472 {
473         return (LPWSTR)(NtCurrentPeb ()->ProcessParameters->Environment);
474 }
475
476
477 WINBOOL
478 STDCALL
479 FreeEnvironmentStringsA (
480         LPSTR   EnvironmentStrings
481         )
482 {
483         if (EnvironmentStrings == NULL)
484                 return FALSE;
485
486         RtlFreeHeap (RtlGetProcessHeap (),
487                      0,
488                      EnvironmentStrings);
489
490         return TRUE;
491 }
492
493
494 WINBOOL
495 STDCALL
496 FreeEnvironmentStringsW (
497         LPWSTR  EnvironmentStrings
498         )
499 {
500  (void)EnvironmentStrings;
501  return TRUE;
502 }
503
504
505 DWORD
506 STDCALL
507 ExpandEnvironmentStringsA (
508         LPCSTR  lpSrc,
509         LPSTR   lpDst,
510         DWORD   nSize
511         )
512 {
513         ANSI_STRING Source;
514         ANSI_STRING Destination;
515         UNICODE_STRING SourceU;
516         UNICODE_STRING DestinationU;
517         NTSTATUS Status;
518         ULONG Length = 0;
519
520         RtlInitAnsiString (&Source,
521                            (LPSTR)lpSrc);
522         RtlAnsiStringToUnicodeString (&SourceU,
523                                       &Source,
524                                       TRUE);
525
526         Destination.Length = 0;
527         Destination.MaximumLength = nSize;
528         Destination.Buffer = lpDst,
529
530         DestinationU.Length = 0;
531         DestinationU.MaximumLength = nSize * sizeof(WCHAR);
532         DestinationU.Buffer = RtlAllocateHeap (RtlGetProcessHeap (),
533                                                0,
534                                                DestinationU.MaximumLength);
535
536         Status = RtlExpandEnvironmentStrings_U (NULL,
537                                                 &SourceU,
538                                                 &DestinationU,
539                                                 &Length);
540
541         RtlFreeUnicodeString (&SourceU);
542
543         if (!NT_SUCCESS(Status))
544         {
545                 RtlFreeHeap (RtlGetProcessHeap (),
546                              0,
547                              DestinationU.Buffer);
548                 SetLastErrorByStatus (Status);
549                 return 0;
550         }
551
552         RtlUnicodeStringToAnsiString (&Destination,
553                                       &DestinationU,
554                                       FALSE);
555
556         RtlFreeHeap (RtlGetProcessHeap (),
557                      0,
558                      DestinationU.Buffer);
559
560         return (Length / sizeof(WCHAR));
561 }
562
563
564 DWORD
565 STDCALL
566 ExpandEnvironmentStringsW (
567         LPCWSTR lpSrc,
568         LPWSTR  lpDst,
569         DWORD   nSize
570         )
571 {
572         UNICODE_STRING Source;
573         UNICODE_STRING Destination;
574         NTSTATUS Status;
575         ULONG Length = 0;
576
577         RtlInitUnicodeString (&Source,
578                               (LPWSTR)lpSrc);
579
580         Destination.Length = 0;
581         Destination.MaximumLength = nSize * sizeof(WCHAR);
582         Destination.Buffer = lpDst;
583
584         Status = RtlExpandEnvironmentStrings_U (NULL,
585                                                 &Source,
586                                                 &Destination,
587                                                 &Length);
588         if (!NT_SUCCESS(Status))
589         {
590                 SetLastErrorByStatus (Status);
591                 return 0;
592         }
593
594         return (Length / sizeof(WCHAR));
595 }
596
597 /* EOF */