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 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 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 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