- Sync with trunk r58248 to bring the latest changes from Amine (headers) and others...
[reactos.git] / base / shell / cmd / setlocal.c
1 /*
2 * SETLOCAL.C - setlocal and endlocal internal batch commands.
3 *
4 * History:
5 *
6 * 1 Feb 2008 (Christoph von Wittich)
7 * started.
8 */
9
10 #include "precomp.h"
11
12 typedef struct _SETLOCAL {
13 struct _SETLOCAL *Prev;
14 BOOL DelayedExpansion;
15 LPTSTR Environment;
16 } SETLOCAL;
17
18 /* Create a copy of the current environment */
19 LPTSTR
20 DuplicateEnvironment(VOID)
21 {
22 LPTSTR Environ = GetEnvironmentStrings();
23 LPTSTR End, EnvironCopy;
24 if (!Environ)
25 return NULL;
26 for (End = Environ; *End; End += _tcslen(End) + 1)
27 ;
28 EnvironCopy = cmd_alloc((End + 1 - Environ) * sizeof(TCHAR));
29 if (EnvironCopy)
30 memcpy(EnvironCopy, Environ, (End + 1 - Environ) * sizeof(TCHAR));
31 FreeEnvironmentStrings(Environ);
32 return EnvironCopy;
33 }
34
35 INT cmd_setlocal(LPTSTR param)
36 {
37 SETLOCAL *Saved;
38 LPTSTR *arg;
39 INT argc, i;
40
41 /* SETLOCAL only works inside a batch file */
42 if (!bc)
43 return 0;
44
45 Saved = cmd_alloc(sizeof(SETLOCAL));
46 if (!Saved)
47 {
48 error_out_of_memory();
49 return 1;
50 }
51 Saved->Prev = bc->setlocal;
52 Saved->DelayedExpansion = bDelayedExpansion;
53 Saved->Environment = DuplicateEnvironment();
54 if (!Saved->Environment)
55 {
56 error_out_of_memory();
57 cmd_free(Saved);
58 return 1;
59 }
60 bc->setlocal = Saved;
61
62 nErrorLevel = 0;
63
64 arg = splitspace(param, &argc);
65 for (i = 0; i < argc; i++)
66 {
67 if (!_tcsicmp(arg[i], _T("enableextensions")))
68 /* not implemented, ignore */;
69 else if (!_tcsicmp(arg[i], _T("disableextensions")))
70 /* not implemented, ignore */;
71 else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion")))
72 bDelayedExpansion = TRUE;
73 else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion")))
74 bDelayedExpansion = FALSE;
75 else
76 {
77 error_invalid_parameter_format(arg[i]);
78 break;
79 }
80 }
81 freep(arg);
82
83 return nErrorLevel;
84 }
85
86 /* endlocal doesn't take any params */
87 INT cmd_endlocal(LPTSTR param)
88 {
89 LPTSTR Environ, Name, Value;
90 SETLOCAL *Saved;
91
92 /* Pop a SETLOCAL struct off of this batch file's stack */
93 if (!bc || !(Saved = bc->setlocal))
94 return 0;
95 bc->setlocal = Saved->Prev;
96
97 bDelayedExpansion = Saved->DelayedExpansion;
98
99 /* First, clear out the environment. Since making any changes to the
100 * environment invalidates pointers obtained from GetEnvironmentStrings(),
101 * we must make a copy of it and get the variable names from that */
102 Environ = DuplicateEnvironment();
103 if (Environ)
104 {
105 for (Name = Environ; *Name; Name += _tcslen(Name) + 1)
106 {
107 if (!(Value = _tcschr(Name + 1, _T('='))))
108 continue;
109 *Value++ = _T('\0');
110 SetEnvironmentVariable(Name, NULL);
111 Name = Value;
112 }
113 cmd_free(Environ);
114 }
115
116 /* Now, restore variables from the copy saved by cmd_setlocal */
117 for (Name = Saved->Environment; *Name; Name += _tcslen(Name) + 1)
118 {
119 if (!(Value = _tcschr(Name + 1, _T('='))))
120 continue;
121 *Value++ = _T('\0');
122 SetEnvironmentVariable(Name, Value);
123 Name = Value;
124 }
125
126 cmd_free(Saved->Environment);
127 cmd_free(Saved);
128 return 0;
129 }