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