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