Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
ae4571fb
Commit
ae4571fb
authored
Nov 05, 2012
by
Jason Edmeades
Committed by
Alexandre Julliard
Nov 06, 2012
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd: Fix for loops within for loops.
parent
f2699f9f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
141 additions
and
92 deletions
+141
-92
batch.c
programs/cmd/batch.c
+22
-13
builtins.c
programs/cmd/builtins.c
+58
-19
test_builtins.cmd.exp
programs/cmd/tests/test_builtins.cmd.exp
+10
-10
wcmd.h
programs/cmd/wcmd.h
+13
-4
wcmdmain.c
programs/cmd/wcmdmain.c
+38
-46
No files found.
programs/cmd/batch.c
View file @
ae4571fb
...
...
@@ -92,7 +92,7 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA
/* Note: although this batch program itself may be called, we are not retrying
the command as a result of a call failing to find a program, hence the
retryCall parameter below is FALSE */
WCMD_process_commands
(
toExecute
,
FALSE
,
NULL
,
NULL
,
FALSE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
FALSE
);
WCMD_free_commands
(
toExecute
);
toExecute
=
NULL
;
}
...
...
@@ -358,8 +358,8 @@ void WCMD_splitpath(const WCHAR* path, WCHAR* drv, WCHAR* dir, WCHAR* name, WCHA
/****************************************************************************
* WCMD_HandleTildaModifiers
*
* Handle the ~ modifiers when expanding %0-9 or (%a-z in for command)
* %~xxxxxV (V=0-9 or A-Z)
* Handle the ~ modifiers when expanding %0-9 or (%a-z
/A-Z
in for command)
* %~xxxxxV (V=0-9 or A-Z
, a-z
)
* Where xxxx is any combination of:
* ~ - Removes quotes
* f - Fully qualified path (assumes current dir if not drive\dir)
...
...
@@ -387,8 +387,8 @@ void WCMD_splitpath(const WCHAR* path, WCHAR* drv, WCHAR* dir, WCHAR* name, WCHA
* Hence search forwards until find an invalid modifier, and then
* backwards until find for variable or 0-9
*/
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
const
WCHAR
*
forVariable
,
const
WCHAR
*
forValue
,
BOOL
justFors
)
{
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
BOOL
justFors
)
{
#define NUMMODIFIERS 11
static
const
WCHAR
validmodifiers
[
NUMMODIFIERS
]
=
{
...
...
@@ -442,18 +442,19 @@ void WCMD_HandleTildaModifiers(WCHAR **start, const WCHAR *forVariable,
}
while
(
lastModifier
>
firstModifier
)
{
WINE_TRACE
(
"Looking backwards for parameter id: %s
/ %s
\n
"
,
wine_dbgstr_w
(
lastModifier
)
,
wine_dbgstr_w
(
forVariable
)
);
WINE_TRACE
(
"Looking backwards for parameter id: %s
\n
"
,
wine_dbgstr_w
(
lastModifier
));
if
(
!
justFors
&&
context
&&
(
*
lastModifier
>=
'0'
&&
*
lastModifier
<=
'9'
))
{
/* Its a valid parameter identifier - OK */
break
;
}
else
if
(
forVariable
&&
*
lastModifier
==
*
(
forVariable
+
1
))
{
}
else
{
int
foridx
=
FOR_VAR_IDX
(
*
lastModifier
);
/* Its a valid parameter identifier - OK */
break
;
if
((
foridx
>=
0
)
&&
(
forloopcontext
.
variable
[
foridx
]
!=
NULL
))
break
;
}
else
{
/* Its not a valid parameter identifier - step backwards */
lastModifier
--
;
}
}
...
...
@@ -468,7 +469,8 @@ void WCMD_HandleTildaModifiers(WCHAR **start, const WCHAR *forVariable,
*
lastModifier
-
'0'
+
context
->
shift_count
[
*
lastModifier
-
'0'
],
NULL
,
FALSE
,
TRUE
));
}
else
{
strcpyW
(
outputparam
,
forValue
);
int
foridx
=
FOR_VAR_IDX
(
*
lastModifier
);
strcpyW
(
outputparam
,
forloopcontext
.
variable
[
foridx
]);
}
/* So now, firstModifier points to beginning of modifiers, lastModifier
...
...
@@ -696,17 +698,24 @@ void WCMD_call (WCHAR *command) {
if
(
context
)
{
LARGE_INTEGER
li
;
FOR_CONTEXT
oldcontext
;
/* Save the for variable context, then start with an empty context
as for loop variables do not survive a call */
oldcontext
=
forloopcontext
;
memset
(
&
forloopcontext
,
0
,
sizeof
(
forloopcontext
));
/* Save the current file position, call the same file,
restore position */
li
.
QuadPart
=
0
;
li
.
u
.
LowPart
=
SetFilePointer
(
context
->
h
,
li
.
u
.
LowPart
,
&
li
.
u
.
HighPart
,
FILE_CURRENT
);
WCMD_batch
(
param1
,
command
,
TRUE
,
gotoLabel
,
context
->
h
);
SetFilePointer
(
context
->
h
,
li
.
u
.
LowPart
,
&
li
.
u
.
HighPart
,
FILE_BEGIN
);
/* Restore the for loop context */
forloopcontext
=
oldcontext
;
}
else
{
WCMD_output_asis_stderr
(
WCMD_LoadMessage
(
WCMD_CALLINSCRIPT
));
}
...
...
programs/cmd/builtins.c
View file @
ae4571fb
This diff is collapsed.
Click to expand it.
programs/cmd/tests/test_builtins.cmd.exp
View file @
ae4571fb
...
...
@@ -648,16 +648,16 @@ B'
"A B"
C
--- imbricated FORs
@todo_wine@
X Y
@todo_wine@
X Y
@todo_wine@
A C
@todo_wine@
A D
@todo_wine@
B C
@todo_wine@
B D
@todo_wine@
A C
@todo_wine@
A D
@todo_wine@
B C
@todo_wine@
B D
X Y
X Y
A C
A D
B C
B D
A C
A D
B C
B D
--- basic wildcards
bazbaz
--- for /d
...
...
programs/cmd/wcmd.h
View file @
ae4571fb
...
...
@@ -112,7 +112,7 @@ WCHAR *WCMD_parameter_with_delims (WCHAR *s, int n, WCHAR **start, BOOL raw,
BOOL
wholecmdline
,
const
WCHAR
*
delims
);
WCHAR
*
WCMD_skip_leading_spaces
(
WCHAR
*
string
);
BOOL
WCMD_keyword_ws_found
(
const
WCHAR
*
keyword
,
int
len
,
const
WCHAR
*
ptr
);
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
const
WCHAR
*
forVariable
,
const
WCHAR
*
forValue
,
BOOL
justFors
);
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
BOOL
justFors
);
void
WCMD_splitpath
(
const
WCHAR
*
path
,
WCHAR
*
drv
,
WCHAR
*
dir
,
WCHAR
*
name
,
WCHAR
*
ext
);
void
WCMD_strip_quotes
(
WCHAR
*
cmd
);
...
...
@@ -122,11 +122,9 @@ void WCMD_strsubstW(WCHAR *start, const WCHAR* next, const WCHAR* insert, int le
BOOL
WCMD_ReadFile
(
const
HANDLE
hIn
,
WCHAR
*
intoBuf
,
const
DWORD
maxChars
,
LPDWORD
charsRead
);
WCHAR
*
WCMD_ReadAndParseLine
(
const
WCHAR
*
initialcmd
,
CMD_LIST
**
output
,
HANDLE
readFrom
);
CMD_LIST
*
WCMD_process_commands
(
CMD_LIST
*
thisCmd
,
BOOL
oneBracket
,
const
WCHAR
*
var
,
const
WCHAR
*
val
,
BOOL
retrycall
);
CMD_LIST
*
WCMD_process_commands
(
CMD_LIST
*
thisCmd
,
BOOL
oneBracket
,
BOOL
retrycall
);
void
WCMD_free_commands
(
CMD_LIST
*
cmds
);
void
WCMD_execute
(
const
WCHAR
*
orig_command
,
const
WCHAR
*
redirects
,
const
WCHAR
*
parameter
,
const
WCHAR
*
substitution
,
CMD_LIST
**
cmdList
,
BOOL
retrycall
);
/* Data structure to hold context when executing batch files */
...
...
@@ -163,6 +161,16 @@ typedef struct _DIRECTORY_STACK
WCHAR
*
fileName
;
}
DIRECTORY_STACK
;
/* Data structure to for loop variables during for body execution, bearing
in mind that for loops can be nested */
#define MAX_FOR_VARIABLES 52
#define FOR_VAR_IDX(c) (((c)>='a'&&(c)<='z')?((c)-'a'):\
((c)>='A'&&(c)<='Z')?(26+(c)-'A'):-1)
typedef
struct
_FOR_CONTEXT
{
WCHAR
*
variable
[
MAX_FOR_VARIABLES
];
/* a-z then A-Z */
}
FOR_CONTEXT
;
/*
* Global variables quals, param1, param2 contain the current qualifiers
* (uppercased and concatenated) and parameters entered, with environment
...
...
@@ -171,6 +179,7 @@ typedef struct _DIRECTORY_STACK
extern
WCHAR
quals
[
MAX_PATH
],
param1
[
MAXSTRING
],
param2
[
MAXSTRING
];
extern
DWORD
errorlevel
;
extern
BATCH_CONTEXT
*
context
;
extern
FOR_CONTEXT
forloopcontext
;
#endif
/* !RC_INVOKED */
...
...
programs/cmd/wcmdmain.c
View file @
ae4571fb
...
...
@@ -40,6 +40,7 @@ BATCH_CONTEXT *context = NULL;
DWORD
errorlevel
;
WCHAR
quals
[
MAX_PATH
],
param1
[
MAXSTRING
],
param2
[
MAXSTRING
];
BOOL
interactive
;
FOR_CONTEXT
forloopcontext
;
/* The 'for' loop context */
int
defaultColor
=
7
;
BOOL
echo_mode
=
TRUE
;
...
...
@@ -549,8 +550,8 @@ static inline BOOL WCMD_is_magic_envvar(const WCHAR *s, const WCHAR *magicvar)
*
* Expands environment variables, allowing for WCHARacter substitution
*/
static
WCHAR
*
WCMD_expand_envvar
(
WCHAR
*
start
,
const
WCHAR
*
forVar
,
const
WCHAR
*
forVal
)
{
static
WCHAR
*
WCMD_expand_envvar
(
WCHAR
*
start
)
{
WCHAR
*
endOfVar
=
NULL
,
*
s
;
WCHAR
*
colonpos
=
NULL
;
WCHAR
thisVar
[
MAXSTRING
];
...
...
@@ -565,8 +566,7 @@ static WCHAR *WCMD_expand_envvar(WCHAR *start,
static
const
WCHAR
Random
[]
=
{
'R'
,
'A'
,
'N'
,
'D'
,
'O'
,
'M'
,
'\0'
};
static
const
WCHAR
Delims
[]
=
{
'%'
,
':'
,
'\0'
};
WINE_TRACE
(
"Expanding: %s (%s,%s)
\n
"
,
wine_dbgstr_w
(
start
),
wine_dbgstr_w
(
forVal
),
wine_dbgstr_w
(
forVar
));
WINE_TRACE
(
"Expanding: %s
\n
"
,
wine_dbgstr_w
(
start
));
/* Find the end of the environment variable, and extract name */
endOfVar
=
strpbrkW
(
start
+
1
,
Delims
);
...
...
@@ -629,17 +629,6 @@ static WCHAR *WCMD_expand_envvar(WCHAR *start,
static
const
WCHAR
fmt
[]
=
{
'%'
,
'd'
,
'\0'
};
wsprintfW
(
thisVarContents
,
fmt
,
rand
()
%
32768
);
len
=
strlenW
(
thisVarContents
);
/* Look for a matching 'for' variable */
}
else
if
(
forVar
&&
(
CompareStringW
(
LOCALE_USER_DEFAULT
,
SORT_STRINGSORT
,
thisVar
,
(
colonpos
-
thisVar
)
-
1
,
forVar
,
-
1
)
==
CSTR_EQUAL
))
{
strcpyW
(
thisVarContents
,
forVal
);
len
=
strlenW
(
thisVarContents
);
}
else
{
len
=
ExpandEnvironmentStringsW
(
thisVar
,
thisVarContents
,
...
...
@@ -802,8 +791,7 @@ static WCHAR *WCMD_expand_envvar(WCHAR *start,
* read in and not again, except for 'for' variable substitution.
* eg. As evidence, "echo %1 && shift && echo %1" or "echo %%path%%"
*/
static
void
handleExpansion
(
WCHAR
*
cmd
,
BOOL
justFors
,
const
WCHAR
*
forVariable
,
const
WCHAR
*
forValue
)
{
static
void
handleExpansion
(
WCHAR
*
cmd
,
BOOL
justFors
)
{
/* For commands in a context (batch program): */
/* Expand environment variables in a batch file %{0-9} first */
...
...
@@ -818,6 +806,15 @@ static void handleExpansion(WCHAR *cmd, BOOL justFors,
WCHAR
*
t
;
int
i
;
/* Display the FOR variables in effect */
for
(
i
=
0
;
i
<
52
;
i
++
)
{
if
(
forloopcontext
.
variable
[
i
])
{
WINE_TRACE
(
"FOR variable context: %c = '%s'
\n
"
,
i
<
26
?
i
+
'a'
:
(
i
-
26
)
+
'A'
,
wine_dbgstr_w
(
forloopcontext
.
variable
[
i
]));
}
}
while
((
p
=
strchrW
(
p
,
'%'
)))
{
WINE_TRACE
(
"Translate command:%s %d (at: %s)
\n
"
,
...
...
@@ -833,7 +830,7 @@ static void handleExpansion(WCHAR *cmd, BOOL justFors,
/* Replace %~ modifications if in batch program */
}
else
if
(
*
(
p
+
1
)
==
'~'
)
{
WCMD_HandleTildaModifiers
(
&
p
,
forVariable
,
forValue
,
justFors
);
WCMD_HandleTildaModifiers
(
&
p
,
justFors
);
p
++
;
/* Replace use of %0...%9 if in batch program*/
...
...
@@ -853,20 +850,18 @@ static void handleExpansion(WCHAR *cmd, BOOL justFors,
}
else
WCMD_strsubstW
(
p
,
p
+
2
,
NULL
,
0
);
}
else
if
(
forVariable
&&
(
CompareStringW
(
LOCALE_USER_DEFAULT
,
SORT_STRINGSORT
,
p
,
strlenW
(
forVariable
),
forVariable
,
-
1
)
==
CSTR_EQUAL
))
{
WCMD_strsubstW
(
p
,
p
+
strlenW
(
forVariable
),
forValue
,
-
1
);
}
else
if
(
!
justFors
)
{
p
=
WCMD_expand_envvar
(
p
,
forVariable
,
forValue
);
/* In a FOR loop, see if this is the variable to replace */
}
else
{
/* Ignore %'s on second pass of batch program */
p
++
;
}
else
{
int
forvaridx
=
FOR_VAR_IDX
(
*
(
p
+
1
));
if
(
forvaridx
!=
-
1
&&
forloopcontext
.
variable
[
forvaridx
])
{
/* Replace the 2 characters, % and for variable character */
WCMD_strsubstW
(
p
,
p
+
2
,
forloopcontext
.
variable
[
forvaridx
],
-
1
);
}
else
if
(
!
justFors
)
{
p
=
WCMD_expand_envvar
(
p
);
/* In a FOR loop, see if this is the variable to replace */
}
else
{
/* Ignore %'s on second pass of batch program */
p
++
;
}
}
}
...
...
@@ -1224,7 +1219,7 @@ void WCMD_run_program (WCHAR *command, BOOL called)
/* Parse the command string, without reading any more input */
WCMD_ReadAndParseLine
(
command
,
&
toExecute
,
INVALID_HANDLE_VALUE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
NULL
,
NULL
,
called
);
WCMD_process_commands
(
toExecute
,
FALSE
,
called
);
WCMD_free_commands
(
toExecute
);
toExecute
=
NULL
;
return
;
...
...
@@ -1248,7 +1243,6 @@ void WCMD_run_program (WCHAR *command, BOOL called)
* we are attempting this retry.
*/
void
WCMD_execute
(
const
WCHAR
*
command
,
const
WCHAR
*
redirects
,
const
WCHAR
*
forVariable
,
const
WCHAR
*
forValue
,
CMD_LIST
**
cmdList
,
BOOL
retrycall
)
{
WCHAR
*
cmd
,
*
p
,
*
redir
;
...
...
@@ -1267,9 +1261,8 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
STD_ERROR_HANDLE
};
BOOL
prev_echo_mode
,
piped
=
FALSE
;
WINE_TRACE
(
"command on entry:%s (%p), with forVariable '%s'='%s'
\n
"
,
wine_dbgstr_w
(
command
),
cmdList
,
wine_dbgstr_w
(
forVariable
),
wine_dbgstr_w
(
forValue
));
WINE_TRACE
(
"command on entry:%s (%p)
\n
"
,
wine_dbgstr_w
(
command
),
cmdList
);
/* If the next command is a pipe then we implement pipes by redirecting
the output from this command to a temp file and input into the
...
...
@@ -1323,8 +1316,8 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
/* Expand variables in command line mode only (batch mode will
be expanded as the line is read in, except for 'for' loops) */
handleExpansion
(
new_cmd
,
(
context
!=
NULL
)
,
forVariable
,
forValue
);
handleExpansion
(
new_redir
,
(
context
!=
NULL
)
,
forVariable
,
forValue
);
handleExpansion
(
new_cmd
,
(
context
!=
NULL
));
handleExpansion
(
new_redir
,
(
context
!=
NULL
));
cmd
=
new_cmd
;
/*
...
...
@@ -1847,7 +1840,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
}
/* Replace env vars if in a batch context */
if
(
context
)
handleExpansion
(
extraSpace
,
FALSE
,
NULL
,
NULL
);
if
(
context
)
handleExpansion
(
extraSpace
,
FALSE
);
/* Skip preceding whitespace */
while
(
*
curPos
==
' '
||
*
curPos
==
'\t'
)
curPos
++
;
...
...
@@ -2244,7 +2237,7 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
}
while
(
*
extraData
==
0x00
);
curPos
=
extraSpace
;
if
(
context
)
handleExpansion
(
extraSpace
,
FALSE
,
NULL
,
NULL
);
if
(
context
)
handleExpansion
(
extraSpace
,
FALSE
);
/* Continue to echo commands IF echo is on and in batch program */
if
(
context
&&
echo_mode
&&
extraSpace
[
0
]
&&
(
extraSpace
[
0
]
!=
'@'
))
{
WCMD_output_asis
(
extraSpace
);
...
...
@@ -2265,7 +2258,6 @@ WCHAR *WCMD_ReadAndParseLine(const WCHAR *optionalcmd, CMD_LIST **output, HANDLE
* Process all the commands read in so far
*/
CMD_LIST
*
WCMD_process_commands
(
CMD_LIST
*
thisCmd
,
BOOL
oneBracket
,
const
WCHAR
*
var
,
const
WCHAR
*
val
,
BOOL
retrycall
)
{
int
bdepth
=
-
1
;
...
...
@@ -2291,7 +2283,7 @@ CMD_LIST *WCMD_process_commands(CMD_LIST *thisCmd, BOOL oneBracket,
Also, skip over any batch labels (eg. :fred) */
if
(
thisCmd
->
command
&&
thisCmd
->
command
[
0
]
!=
':'
)
{
WINE_TRACE
(
"Executing command: '%s'
\n
"
,
wine_dbgstr_w
(
thisCmd
->
command
));
WCMD_execute
(
thisCmd
->
command
,
thisCmd
->
redirects
,
var
,
val
,
&
thisCmd
,
retrycall
);
WCMD_execute
(
thisCmd
->
command
,
thisCmd
->
redirects
,
&
thisCmd
,
retrycall
);
}
/* Step on unless the command itself already stepped on */
...
...
@@ -2581,7 +2573,7 @@ int wmain (int argc, WCHAR *argvW[])
/* Parse the command string, without reading any more input */
WCMD_ReadAndParseLine
(
cmd
,
&
toExecute
,
INVALID_HANDLE_VALUE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
NULL
,
NULL
,
FALSE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
FALSE
);
WCMD_free_commands
(
toExecute
);
toExecute
=
NULL
;
...
...
@@ -2668,7 +2660,7 @@ int wmain (int argc, WCHAR *argvW[])
if
(
opt_k
)
{
/* Parse the command string, without reading any more input */
WCMD_ReadAndParseLine
(
cmd
,
&
toExecute
,
INVALID_HANDLE_VALUE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
NULL
,
NULL
,
FALSE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
FALSE
);
WCMD_free_commands
(
toExecute
);
toExecute
=
NULL
;
HeapFree
(
GetProcessHeap
(),
0
,
cmd
);
...
...
@@ -2688,7 +2680,7 @@ int wmain (int argc, WCHAR *argvW[])
if
(
echo_mode
)
WCMD_show_prompt
();
if
(
!
WCMD_ReadAndParseLine
(
NULL
,
&
toExecute
,
GetStdHandle
(
STD_INPUT_HANDLE
)))
break
;
WCMD_process_commands
(
toExecute
,
FALSE
,
NULL
,
NULL
,
FALSE
);
WCMD_process_commands
(
toExecute
,
FALSE
,
FALSE
);
WCMD_free_commands
(
toExecute
);
toExecute
=
NULL
;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment