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 #include <direct.h> // For _getdrive().
13
14 typedef struct _SETLOCAL
15 {
16 struct _SETLOCAL *Prev;
17 LPTSTR Environment;
18 INT CurDrive;
19 BOOL EnableExtensions;
20 BOOL DelayedExpansion;
21 } SETLOCAL, *PSETLOCAL;
22
23 /* Create a copy of the current environment */
24 LPTSTR
DuplicateEnvironment(VOID)25 DuplicateEnvironment(VOID)
26 {
27 LPTSTR Environ = GetEnvironmentStrings();
28 LPTSTR End, EnvironCopy;
29
30 if (!Environ) return NULL;
31
32 for (End = Environ; *End; End += _tcslen(End) + 1) ;
33 EnvironCopy = cmd_alloc((End + 1 - Environ) * sizeof(TCHAR));
34
35 if (EnvironCopy)
36 memcpy(EnvironCopy, Environ, (End + 1 - Environ) * sizeof(TCHAR));
37
38 FreeEnvironmentStrings(Environ);
39 return EnvironCopy;
40 }
41
cmd_setlocal(LPTSTR param)42 INT cmd_setlocal(LPTSTR param)
43 {
44 PSETLOCAL Saved;
45 LPTSTR* arg;
46 INT argc, i;
47
48 if (!_tcscmp(param, _T("/?")))
49 {
50 // FIXME
51 ConOutPuts(_T("SETLOCAL help not implemented yet!\n"));
52 return 0;
53 }
54
55 /* SETLOCAL only works inside a batch context */
56 if (!bc)
57 return 0;
58
59 Saved = cmd_alloc(sizeof(SETLOCAL));
60 if (!Saved)
61 {
62 WARN("Cannot allocate memory for Saved!\n");
63 error_out_of_memory();
64 return 1;
65 }
66
67 Saved->Environment = DuplicateEnvironment();
68 if (!Saved->Environment)
69 {
70 error_out_of_memory();
71 cmd_free(Saved);
72 return 1;
73 }
74 /*
75 * Save the current drive; the duplicated environment
76 * contains the corresponding current directory.
77 */
78 Saved->CurDrive = _getdrive();
79
80 Saved->EnableExtensions = bEnableExtensions;
81 Saved->DelayedExpansion = bDelayedExpansion;
82
83 Saved->Prev = bc->setlocal;
84 bc->setlocal = Saved;
85
86 nErrorLevel = 0;
87
88 arg = splitspace(param, &argc);
89 for (i = 0; i < argc; i++)
90 {
91 if (!_tcsicmp(arg[i], _T("ENABLEEXTENSIONS")))
92 bEnableExtensions = TRUE;
93 else if (!_tcsicmp(arg[i], _T("DISABLEEXTENSIONS")))
94 bEnableExtensions = FALSE;
95 else if (!_tcsicmp(arg[i], _T("ENABLEDELAYEDEXPANSION")))
96 bDelayedExpansion = TRUE;
97 else if (!_tcsicmp(arg[i], _T("DISABLEDELAYEDEXPANSION")))
98 bDelayedExpansion = FALSE;
99 else
100 {
101 error_invalid_parameter_format(arg[i]);
102 break;
103 }
104 }
105 freep(arg);
106
107 return nErrorLevel;
108 }
109
cmd_endlocal(LPTSTR param)110 INT cmd_endlocal(LPTSTR param)
111 {
112 LPTSTR Environ, Name, Value;
113 PSETLOCAL Saved;
114 TCHAR drvEnvVar[] = _T("=?:");
115 TCHAR szCurrent[MAX_PATH];
116
117 if (!_tcscmp(param, _T("/?")))
118 {
119 // FIXME
120 ConOutPuts(_T("ENDLOCAL help not implemented yet!\n"));
121 return 0;
122 }
123
124 /* Pop a SETLOCAL struct off of this batch context's stack */
125 if (!bc || !(Saved = bc->setlocal))
126 return 0;
127 bc->setlocal = Saved->Prev;
128
129 bEnableExtensions = Saved->EnableExtensions;
130 bDelayedExpansion = Saved->DelayedExpansion;
131
132 /* First, clear out the environment. Since making any changes to the
133 * environment invalidates pointers obtained from GetEnvironmentStrings(),
134 * we must make a copy of it and get the variable names from that. */
135 Environ = DuplicateEnvironment();
136 if (Environ)
137 {
138 for (Name = Environ; *Name; Name += _tcslen(Name) + 1)
139 {
140 if (!(Value = _tcschr(Name + 1, _T('='))))
141 continue;
142 *Value++ = _T('\0');
143 SetEnvironmentVariable(Name, NULL);
144 Name = Value;
145 }
146 cmd_free(Environ);
147 }
148
149 /* Now, restore variables from the copy saved by cmd_setlocal() */
150 for (Name = Saved->Environment; *Name; Name += _tcslen(Name) + 1)
151 {
152 if (!(Value = _tcschr(Name + 1, _T('='))))
153 continue;
154 *Value++ = _T('\0');
155 SetEnvironmentVariable(Name, Value);
156 Name = Value;
157 }
158
159 /* Restore the current drive and its current directory from the environment */
160 drvEnvVar[1] = _T('A') + Saved->CurDrive - 1;
161 if (!GetEnvironmentVariable(drvEnvVar, szCurrent, ARRAYSIZE(szCurrent)))
162 {
163 _stprintf(szCurrent, _T("%C:\\"), _T('A') + Saved->CurDrive - 1);
164 }
165 _tchdir(szCurrent); // SetRootPath(NULL, szCurrent);
166
167 cmd_free(Saved->Environment);
168 cmd_free(Saved);
169 return 0;
170 }
171