xref: /reactos/base/shell/cmd/setlocal.c (revision 279107d5)
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         WARN("Cannot allocate memory for Saved!\n");
53         error_out_of_memory();
54         return 1;
55     }
56     Saved->Prev = bc->setlocal;
57     Saved->EnableExtensions = bEnableExtensions;
58     Saved->DelayedExpansion = bDelayedExpansion;
59     Saved->Environment = DuplicateEnvironment();
60     if (!Saved->Environment)
61     {
62         error_out_of_memory();
63         cmd_free(Saved);
64         return 1;
65     }
66     bc->setlocal = Saved;
67 
68     nErrorLevel = 0;
69 
70     arg = splitspace(param, &argc);
71     for (i = 0; i < argc; i++)
72     {
73         if (!_tcsicmp(arg[i], _T("enableextensions")))
74             /* FIXME: not implemented! */
75             bEnableExtensions = TRUE;
76         else if (!_tcsicmp(arg[i], _T("disableextensions")))
77             /* FIXME: not implemented! */
78             bEnableExtensions = FALSE;
79         else if (!_tcsicmp(arg[i], _T("enabledelayedexpansion")))
80             bDelayedExpansion = TRUE;
81         else if (!_tcsicmp(arg[i], _T("disabledelayedexpansion")))
82             bDelayedExpansion = FALSE;
83         else
84         {
85             error_invalid_parameter_format(arg[i]);
86             break;
87         }
88     }
89     freep(arg);
90 
91     return nErrorLevel;
92 }
93 
94 /* endlocal doesn't take any params */
95 INT cmd_endlocal(LPTSTR param)
96 {
97     LPTSTR Environ, Name, Value;
98     SETLOCAL *Saved;
99 
100     /* Pop a SETLOCAL struct off of this batch file's stack */
101     if (!bc || !(Saved = bc->setlocal))
102         return 0;
103     bc->setlocal = Saved->Prev;
104 
105     bEnableExtensions = Saved->EnableExtensions;
106     bDelayedExpansion = Saved->DelayedExpansion;
107 
108     /* First, clear out the environment. Since making any changes to the
109      * environment invalidates pointers obtained from GetEnvironmentStrings(),
110      * we must make a copy of it and get the variable names from that */
111     Environ = DuplicateEnvironment();
112     if (Environ)
113     {
114         for (Name = Environ; *Name; Name += _tcslen(Name) + 1)
115         {
116             if (!(Value = _tcschr(Name + 1, _T('='))))
117                 continue;
118             *Value++ = _T('\0');
119             SetEnvironmentVariable(Name, NULL);
120             Name = Value;
121         }
122         cmd_free(Environ);
123     }
124 
125     /* Now, restore variables from the copy saved by cmd_setlocal */
126     for (Name = Saved->Environment; *Name; Name += _tcslen(Name) + 1)
127     {
128         if (!(Value = _tcschr(Name + 1, _T('='))))
129             continue;
130         *Value++ = _T('\0');
131         SetEnvironmentVariable(Name, Value);
132         Name = Value;
133     }
134 
135     cmd_free(Saved->Environment);
136     cmd_free(Saved);
137     return 0;
138 }
139