cmd: Fix setlocal/endlocal implementation.
This commit is contained in:
parent
9dde62cb96
commit
c55cd87632
|
@ -22,6 +22,8 @@
|
|||
#include "wcmd.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
extern struct env_stack *saved_environment;
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(cmd);
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -93,6 +95,13 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA
|
|||
}
|
||||
CloseHandle (h);
|
||||
|
||||
/*
|
||||
* If there are outstanding setlocal's to the current context, unwind them.
|
||||
*/
|
||||
while (saved_environment && saved_environment->batchhandle == context->h) {
|
||||
WCMD_endlocal();
|
||||
}
|
||||
|
||||
/*
|
||||
* If invoked by a CALL, we return to the context of our caller. Otherwise return
|
||||
* to the caller's caller.
|
||||
|
|
|
@ -103,7 +103,7 @@ static const WCHAR parmY[] = {'/','Y','\0'};
|
|||
static const WCHAR parmNoY[] = {'/','-','Y','\0'};
|
||||
|
||||
static HINSTANCE hinst;
|
||||
static struct env_stack *saved_environment;
|
||||
struct env_stack *saved_environment;
|
||||
static BOOL verify_mode = FALSE;
|
||||
|
||||
/**************************************************************************
|
||||
|
@ -2087,6 +2087,9 @@ void WCMD_setlocal (const WCHAR *s) {
|
|||
struct env_stack *env_copy;
|
||||
WCHAR cwd[MAX_PATH];
|
||||
|
||||
/* setlocal does nothing outside of batch programs */
|
||||
if (!context) return;
|
||||
|
||||
/* DISABLEEXTENSIONS ignored */
|
||||
|
||||
env_copy = LocalAlloc (LMEM_FIXED, sizeof (struct env_stack));
|
||||
|
@ -2097,10 +2100,10 @@ void WCMD_setlocal (const WCHAR *s) {
|
|||
}
|
||||
|
||||
env = GetEnvironmentStringsW ();
|
||||
|
||||
env_copy->strings = WCMD_dupenv (env);
|
||||
if (env_copy->strings)
|
||||
{
|
||||
env_copy->batchhandle = context->h;
|
||||
env_copy->next = saved_environment;
|
||||
saved_environment = env_copy;
|
||||
|
||||
|
@ -2127,7 +2130,12 @@ void WCMD_endlocal (void) {
|
|||
struct env_stack *temp;
|
||||
int len, n;
|
||||
|
||||
if (!saved_environment)
|
||||
/* setlocal does nothing outside of batch programs */
|
||||
if (!context) return;
|
||||
|
||||
/* setlocal needs a saved environment from within the same context (batch
|
||||
program) as it was saved in */
|
||||
if (!saved_environment || saved_environment->batchhandle != context->h)
|
||||
return;
|
||||
|
||||
/* pop the old environment from the stack */
|
||||
|
|
|
@ -1659,27 +1659,163 @@ cmd /e:oN /C tmp.cmd
|
|||
|
||||
rem FIXME: creating file before setting envvar value to prevent parsing-time evaluation (due to EnableDelayedExpansion not being implemented/available yet)
|
||||
echo --- setlocal with corresponding endlocal
|
||||
rem %CD% does not tork on NT4 so use the following workaround
|
||||
for /d %%i in (.) do set CURDIR=%%~dpnxi
|
||||
echo @echo off> test.cmd
|
||||
echo echo %%VAR%%>> test.cmd
|
||||
echo setlocal>> test.cmd
|
||||
echo set VAR=localval>> test.cmd
|
||||
echo md foobar2>> test.cmd
|
||||
echo cd foobar2>> test.cmd
|
||||
echo echo %%VAR%%>> test.cmd
|
||||
echo for /d %%%%i in (.) do echo %%%%~dpnxi>> test.cmd
|
||||
echo endlocal>> test.cmd
|
||||
echo echo %%VAR%%>> test.cmd
|
||||
echo for /d %%%%i in (.) do echo %%%%~dpnxi>> test.cmd
|
||||
set VAR=globalval
|
||||
call test.cmd
|
||||
echo %VAR%
|
||||
for /d %%i in (.) do echo %%~dpnxi
|
||||
cd /d %curdir%
|
||||
rd foobar2
|
||||
set VAR=
|
||||
echo --- setlocal with no corresponding endlocal
|
||||
echo @echo off> test.cmd
|
||||
echo echo %%VAR%%>> test.cmd
|
||||
echo setlocal>> test.cmd
|
||||
echo set VAR=localval>> test.cmd
|
||||
echo md foobar2>> test.cmd
|
||||
echo cd foobar2>> test.cmd
|
||||
echo echo %%VAR%%>> test.cmd
|
||||
echo for /d %%%%i in (.) do echo %%%%~dpnxi>> test.cmd
|
||||
set VAR=globalval
|
||||
rem %CD% does not tork on NT4 so use the following workaround
|
||||
for /d %%i in (.) do set CURDIR=%%~dpnxi
|
||||
call test.cmd
|
||||
echo %VAR%
|
||||
for /d %%i in (.) do echo %%~dpnxi
|
||||
cd /d %curdir%
|
||||
rd foobar2
|
||||
set VAR=
|
||||
echo --- setlocal within same batch program
|
||||
set var1=one
|
||||
set var2=
|
||||
set var3=
|
||||
rem %CD% does not tork on NT4 so use the following workaround
|
||||
for /d %%i in (.) do set CURDIR=%%~dpnxi
|
||||
setlocal
|
||||
set var2=two
|
||||
mkdir foobar2
|
||||
cd foobar2
|
||||
setlocal
|
||||
set var3=three
|
||||
if "%var1%"=="one" echo Var1 ok 1
|
||||
if "%var2%"=="two" echo Var2 ok 2
|
||||
if "%var3%"=="three" echo Var3 ok 3
|
||||
for /d %%i in (.) do set curdir2=%%~dpnxi
|
||||
if "%curdir2%"=="%curdir%\foobar2" echo Directory is ok 1
|
||||
endlocal
|
||||
if "%var1%"=="one" echo Var1 ok 1
|
||||
if "%var2%"=="two" echo Var2 ok 2
|
||||
if "%var3%"=="" echo Var3 ok 3
|
||||
for /d %%i in (.) do set curdir2=%%~dpnxi
|
||||
if "%curdir2%"=="%curdir%\foobar2" echo Directory is ok 2
|
||||
endlocal
|
||||
if "%var1%"=="one" echo Var1 ok 1
|
||||
if "%var2%"=="" echo Var2 ok 2
|
||||
if "%var3%"=="" echo Var3 ok 3
|
||||
for /d %%i in (.) do set curdir2=%%~dpnxi
|
||||
if "%curdir2%"=="%curdir%" echo Directory is ok 3
|
||||
rd foobar2 /s /q
|
||||
set var1=
|
||||
|
||||
echo --- Mismatched set and end locals
|
||||
mkdir foodir2 2>nul
|
||||
mkdir foodir3 2>nul
|
||||
mkdir foodir4 2>nul
|
||||
rem %CD% does not tork on NT4 so use the following workaround
|
||||
for /d %%i in (.) do set curdir=%%~dpnxi
|
||||
|
||||
echo @echo off> 2set1end.cmd
|
||||
echo echo %%VAR%%>> 2set1end.cmd
|
||||
echo setlocal>> 2set1end.cmd
|
||||
echo set VAR=2set1endvalue1>> 2set1end.cmd
|
||||
echo cd ..\foodir3>> 2set1end.cmd
|
||||
echo setlocal>> 2set1end.cmd
|
||||
echo set VAR=2set1endvalue2>> 2set1end.cmd
|
||||
echo cd ..\foodir4>> 2set1end.cmd
|
||||
echo endlocal>> 2set1end.cmd
|
||||
echo echo %%VAR%%>> 2set1end.cmd
|
||||
echo for /d %%%%i in (.) do echo %%%%~dpnxi>> 2set1end.cmd
|
||||
|
||||
echo @echo off> 1set2end.cmd
|
||||
echo echo %%VAR%%>> 1set2end.cmd
|
||||
echo setlocal>> 1set2end.cmd
|
||||
echo set VAR=1set2endvalue1>> 1set2end.cmd
|
||||
echo cd ..\foodir3>> 1set2end.cmd
|
||||
echo endlocal>> 1set2end.cmd
|
||||
echo echo %%VAR%%>> 1set2end.cmd
|
||||
echo for /d %%%%i in (.) do echo %%%%~dpnxi>> 1set2end.cmd
|
||||
echo endlocal>> 1set2end.cmd
|
||||
echo echo %%VAR%%>> 1set2end.cmd
|
||||
echo for /d %%%%i in (.) do echo %%%%~dpnxi>> 1set2end.cmd
|
||||
|
||||
echo --- Extra setlocal in called batch
|
||||
set VAR=value1
|
||||
rem -- setlocal1 == this batch, should never be used inside a called routine
|
||||
setlocal
|
||||
set var=value2
|
||||
cd foodir2
|
||||
call %curdir%\2set1end.cmd
|
||||
echo Finished:
|
||||
echo %VAR%
|
||||
for /d %%i in (.) do echo %%~dpnxi
|
||||
endlocal
|
||||
echo %VAR%
|
||||
for /d %%i in (.) do echo %%~dpnxi
|
||||
cd /d %curdir%
|
||||
|
||||
echo --- Extra endlocal in called batch
|
||||
set VAR=value1
|
||||
rem -- setlocal1 == this batch, should never be used inside a called routine
|
||||
setlocal
|
||||
set var=value2
|
||||
cd foodir2
|
||||
call %curdir%\1set2end.cmd
|
||||
echo Finished:
|
||||
echo %VAR%
|
||||
for /d %%i in (.) do echo %%~dpnxi
|
||||
endlocal
|
||||
echo %VAR%
|
||||
for /d %%i in (.) do echo %%~dpnxi
|
||||
cd /d %curdir%
|
||||
|
||||
echo --- endlocal in called function rather than batch pgm is ineffective
|
||||
@echo off
|
||||
set var=1
|
||||
set var2=1
|
||||
setlocal
|
||||
set var=2
|
||||
call :endlocalroutine
|
||||
echo %var%
|
||||
endlocal
|
||||
echo %var%
|
||||
goto :endlocalfinished
|
||||
:endlocalroutine
|
||||
echo %var%
|
||||
endlocal
|
||||
echo %var%
|
||||
setlocal
|
||||
set var2=2
|
||||
endlocal
|
||||
echo %var2%
|
||||
endlocal
|
||||
echo %var%
|
||||
echo %var2%
|
||||
goto :eof
|
||||
:endlocalfinished
|
||||
echo %var%
|
||||
|
||||
cd .. & rd /q/s foobar
|
||||
|
||||
echo ------------ Testing Errorlevel ------------
|
||||
|
|
|
@ -853,12 +853,60 @@ ErrLev: 0
|
|||
--- setlocal with corresponding endlocal
|
||||
globalval
|
||||
localval
|
||||
@pwd@\foobar\foobar2
|
||||
globalval
|
||||
@pwd@\foobar
|
||||
globalval
|
||||
@pwd@\foobar
|
||||
--- setlocal with no corresponding endlocal
|
||||
globalval
|
||||
localval
|
||||
@todo_wine@globalval
|
||||
@pwd@\foobar\foobar2
|
||||
globalval
|
||||
@pwd@\foobar
|
||||
--- setlocal within same batch program
|
||||
Var1 ok 1
|
||||
Var2 ok 2
|
||||
Var3 ok 3
|
||||
Directory is ok 1
|
||||
Var1 ok 1
|
||||
Var2 ok 2
|
||||
Var3 ok 3
|
||||
Directory is ok 2
|
||||
Var1 ok 1
|
||||
Var2 ok 2
|
||||
Var3 ok 3
|
||||
Directory is ok 3
|
||||
--- Mismatched set and end locals
|
||||
--- Extra setlocal in called batch
|
||||
value2
|
||||
2set1endvalue1
|
||||
@pwd@\foobar\foodir3
|
||||
Finished:
|
||||
value2
|
||||
@pwd@\foobar\foodir2
|
||||
value1
|
||||
@pwd@\foobar
|
||||
--- Extra endlocal in called batch
|
||||
value2
|
||||
value2
|
||||
@pwd@\foobar\foodir2
|
||||
value2
|
||||
@pwd@\foobar\foodir2
|
||||
Finished:
|
||||
value2
|
||||
@pwd@\foobar\foodir2
|
||||
value1
|
||||
@pwd@\foobar
|
||||
--- endlocal in called function rather than batch pgm is ineffective
|
||||
2
|
||||
2
|
||||
1
|
||||
2
|
||||
1
|
||||
2
|
||||
1
|
||||
1
|
||||
------------ Testing Errorlevel ------------
|
||||
9009
|
||||
1
|
||||
|
|
|
@ -149,6 +149,7 @@ struct env_stack
|
|||
WCHAR cwd; /* Only used for set/endlocal */
|
||||
} u;
|
||||
WCHAR *strings;
|
||||
HANDLE batchhandle; /* Used to ensure set/endlocals stay in scope */
|
||||
};
|
||||
|
||||
/* Data structure to save setlocal and pushd information */
|
||||
|
|
Loading…
Reference in New Issue