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