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
b6924112
Commit
b6924112
authored
Sep 11, 2007
by
Jason Edmeades
Committed by
Alexandre Julliard
Sep 12, 2007
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cmd.exe: Expand for variables at last with tilda modifications.
parent
dc372175
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
161 additions
and
132 deletions
+161
-132
batch.c
programs/cmd/batch.c
+20
-14
builtins.c
programs/cmd/builtins.c
+1
-35
wcmd.h
programs/cmd/wcmd.h
+1
-2
wcmdmain.c
programs/cmd/wcmdmain.c
+139
-81
No files found.
programs/cmd/batch.c
View file @
b6924112
...
...
@@ -19,6 +19,9 @@
*/
#include "wcmd.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL
(
cmd
);
extern
int
echo_mode
;
extern
WCHAR
quals
[
MAX_PATH
],
param1
[
MAX_PATH
],
param2
[
MAX_PATH
];
...
...
@@ -301,7 +304,7 @@ 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
,
WCHAR
*
forVariable
)
{
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
WCHAR
*
forVariable
,
WCHAR
*
forValue
,
BOOL
justFors
)
{
#define NUMMODIFIERS 11
static
const
WCHAR
validmodifiers
[
NUMMODIFIERS
]
=
{
...
...
@@ -324,10 +327,10 @@ void WCMD_HandleTildaModifiers(WCHAR **start, WCHAR *forVariable) {
BOOL
skipFileParsing
=
FALSE
;
BOOL
doneModifier
=
FALSE
;
/* Search forwards until find invalid
WCHAR
acter modifier */
/* Search forwards until find invalid
char
acter modifier */
while
(
!
finished
)
{
/* Work on the previous
WCHAR
acter */
/* Work on the previous
char
acter */
if
(
lastModifier
!=
NULL
)
{
for
(
i
=
0
;
i
<
NUMMODIFIERS
;
i
++
)
{
...
...
@@ -355,27 +358,30 @@ void WCMD_HandleTildaModifiers(WCHAR **start, WCHAR *forVariable) {
}
}
/* Now make sure the position we stopped at is a valid parameter */
if
(
!
(
*
lastModifier
>=
'0'
||
*
lastModifier
<=
'9'
)
&&
(
forVariable
!=
NULL
)
&&
(
toupperW
(
*
lastModifier
)
!=
toupperW
(
*
forVariable
)))
{
while
(
lastModifier
>
firstModifier
)
{
WINE_TRACE
(
"Looking backwards for parameter id: %s / %s
\n
"
,
wine_dbgstr_w
(
lastModifier
),
wine_dbgstr_w
(
forVariable
));
if
(
!
justFors
&&
context
&&
(
*
lastModifier
>=
'0'
||
*
lastModifier
<=
'9'
))
{
/* Its a valid parameter identifier - OK */
break
;
/* Its not... Step backwards until it matches or we get to the start */
while
(
toupperW
(
*
lastModifier
)
!=
toupperW
(
*
forVariable
)
&&
lastModifier
>
firstModifier
)
{
}
else
if
(
forVariable
&&
*
lastModifier
==
*
(
forVariable
+
1
))
{
/* Its a valid parameter identifier - OK */
break
;
}
else
{
lastModifier
--
;
}
if
(
lastModifier
==
firstModifier
)
return
;
/* Invalid syntax */
}
if
(
lastModifier
==
firstModifier
)
return
;
/* Invalid syntax */
/* Extract the parameter to play with */
if
((
*
lastModifier
>=
'0'
&&
*
lastModifier
<=
'9'
))
{
strcpyW
(
outputparam
,
WCMD_parameter
(
context
->
command
,
*
lastModifier
-
'0'
+
context
->
shift_count
[
*
lastModifier
-
'0'
],
NULL
));
}
else
{
/* FIXME: Retrieve 'for' variable %c\n", *lastModifier); */
/* Need to get 'for' loop variable into outputparam */
return
;
strcpyW
(
outputparam
,
forValue
);
}
/* So now, firstModifier points to beginning of modifiers, lastModifier
...
...
programs/cmd/builtins.c
View file @
b6924112
...
...
@@ -992,40 +992,6 @@ void WCMD_part_execute(CMD_LIST **cmdList, WCHAR *firstcmd, WCHAR *variable,
return
;
}
/*****************************************************************************
* WCMD_Execute
*
* Execute a command after substituting variable text for the supplied parameter
*/
void
WCMD_execute
(
WCHAR
*
orig_cmd
,
WCHAR
*
param
,
WCHAR
*
subst
,
CMD_LIST
**
cmdList
)
{
WCHAR
*
new_cmd
,
*
p
,
*
s
,
*
dup
;
int
size
;
if
(
param
)
{
size
=
(
strlenW
(
orig_cmd
)
+
1
)
*
sizeof
(
WCHAR
);
new_cmd
=
(
WCHAR
*
)
LocalAlloc
(
LMEM_FIXED
|
LMEM_ZEROINIT
,
size
);
dup
=
s
=
WCMD_strdupW
(
orig_cmd
);
while
((
p
=
strstrW
(
s
,
param
)))
{
*
p
=
'\0'
;
size
+=
strlenW
(
subst
)
*
sizeof
(
WCHAR
);
new_cmd
=
(
WCHAR
*
)
LocalReAlloc
((
HANDLE
)
new_cmd
,
size
,
0
);
strcatW
(
new_cmd
,
s
);
strcatW
(
new_cmd
,
subst
);
s
=
p
+
strlenW
(
param
);
}
strcatW
(
new_cmd
,
s
);
WCMD_process_command
(
new_cmd
,
cmdList
);
free
(
dup
);
LocalFree
((
HANDLE
)
new_cmd
);
}
else
{
WCMD_process_command
(
orig_cmd
,
cmdList
);
}
}
/**************************************************************************
* WCMD_give_help
*
...
...
@@ -1067,7 +1033,7 @@ void WCMD_goto (CMD_LIST **cmdList) {
WCHAR
string
[
MAX_PATH
];
/* Do not process any more parts of a processed multipart or multilines command */
*
cmdList
=
NULL
;
if
(
cmdList
)
*
cmdList
=
NULL
;
if
(
param1
[
0
]
==
0x00
)
{
WCMD_output
(
WCMD_LoadMessage
(
WCMD_NOARG
));
...
...
programs/cmd/wcmd.h
View file @
b6924112
...
...
@@ -65,7 +65,6 @@ void WCMD_pause (void);
void
WCMD_pipe
(
CMD_LIST
**
command
,
WCHAR
*
var
,
WCHAR
*
val
);
void
WCMD_popd
(
void
);
void
WCMD_print_error
(
void
);
void
WCMD_process_command
(
WCHAR
*
command
,
CMD_LIST
**
cmdList
);
void
WCMD_pushd
(
WCHAR
*
);
int
WCMD_read_console
(
WCHAR
*
string
,
int
str_len
);
void
WCMD_remove_dir
(
WCHAR
*
command
);
...
...
@@ -92,7 +91,7 @@ WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **where);
WCHAR
*
WCMD_strtrim_leading_spaces
(
WCHAR
*
string
);
void
WCMD_strtrim_trailing_spaces
(
WCHAR
*
string
);
void
WCMD_opt_s_strip_quotes
(
WCHAR
*
cmd
);
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
WCHAR
*
forVariable
);
void
WCMD_HandleTildaModifiers
(
WCHAR
**
start
,
WCHAR
*
forVariable
,
WCHAR
*
forValue
,
BOOL
justFors
);
BOOL
WCMD_ask_confirm
(
WCHAR
*
message
,
BOOL
showSureText
,
BOOL
*
optionAll
);
void
WCMD_splitpath
(
const
WCHAR
*
path
,
WCHAR
*
drv
,
WCHAR
*
dir
,
WCHAR
*
name
,
WCHAR
*
ext
);
...
...
programs/cmd/wcmdmain.c
View file @
b6924112
...
...
@@ -95,7 +95,7 @@ static char *output_bufA = NULL;
#define MAX_WRITECONSOLE_SIZE 65535
BOOL
unicodePipes
=
FALSE
;
static
WCHAR
*
WCMD_expand_envvar
(
WCHAR
*
start
);
static
WCHAR
*
WCMD_expand_envvar
(
WCHAR
*
start
,
WCHAR
*
forvar
,
WCHAR
*
forVal
);
/*****************************************************************************
* Main entry point. This is a console application so we have a main() not a
...
...
@@ -456,6 +456,87 @@ int wmain (int argc, WCHAR *argvW[])
return
0
;
}
/*****************************************************************************
* Expand the command. Native expands lines from batch programs as they are
* read in and not again, except for 'for' variable substitution.
* eg. As evidence, "echo %1 && shift && echo %1" or "echo %%path%%"
*/
void
handleExpansion
(
WCHAR
*
cmd
,
BOOL
justFors
,
WCHAR
*
forVariable
,
WCHAR
*
forValue
)
{
/* For commands in a context (batch program): */
/* Expand environment variables in a batch file %{0-9} first */
/* including support for any ~ modifiers */
/* Additionally: */
/* Expand the DATE, TIME, CD, RANDOM and ERRORLEVEL special */
/* names allowing environment variable overrides */
/* NOTE: To support the %PATH:xxx% syntax, also perform */
/* manual expansion of environment variables here */
WCHAR
*
p
=
cmd
;
WCHAR
*
s
,
*
t
;
int
i
;
while
((
p
=
strchrW
(
p
,
'%'
)))
{
WINE_TRACE
(
"Translate command:%s %d (at: %s)
\n
"
,
wine_dbgstr_w
(
cmd
),
justFors
,
wine_dbgstr_w
(
p
));
i
=
*
(
p
+
1
)
-
'0'
;
/* Don't touch %% unless its in Batch */
if
(
!
justFors
&&
*
(
p
+
1
)
==
'%'
)
{
if
(
context
)
{
s
=
WCMD_strdupW
(
p
+
1
);
strcpyW
(
p
,
s
);
free
(
s
);
}
p
+=
1
;
/* Replace %~ modifications if in batch program */
}
else
if
(
*
(
p
+
1
)
==
'~'
)
{
WCMD_HandleTildaModifiers
(
&
p
,
forVariable
,
forValue
,
justFors
);
p
++
;
/* Replace use of %0...%9 if in batch program*/
}
else
if
(
!
justFors
&&
context
&&
(
i
>=
0
)
&&
(
i
<=
9
))
{
s
=
WCMD_strdupW
(
p
+
2
);
t
=
WCMD_parameter
(
context
->
command
,
i
+
context
->
shift_count
[
i
],
NULL
);
strcpyW
(
p
,
t
);
strcatW
(
p
,
s
);
free
(
s
);
/* Replace use of %* if in batch program*/
}
else
if
(
!
justFors
&&
context
&&
*
(
p
+
1
)
==
'*'
)
{
WCHAR
*
startOfParms
=
NULL
;
s
=
WCMD_strdupW
(
p
+
2
);
t
=
WCMD_parameter
(
context
->
command
,
1
,
&
startOfParms
);
if
(
startOfParms
!=
NULL
)
strcpyW
(
p
,
startOfParms
);
else
*
p
=
0x00
;
strcatW
(
p
,
s
);
free
(
s
);
}
else
if
(
forVariable
&&
(
CompareString
(
LOCALE_USER_DEFAULT
,
SORT_STRINGSORT
,
p
,
strlenW
(
forVariable
),
forVariable
,
-
1
)
==
2
))
{
s
=
WCMD_strdupW
(
p
+
strlenW
(
forVariable
));
strcpyW
(
p
,
forValue
);
strcatW
(
p
,
s
);
free
(
s
);
}
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
++
;
}
}
return
;
}
/*****************************************************************************
* Process one command. If the command is EXIT this routine does not return.
...
...
@@ -463,9 +544,11 @@ int wmain (int argc, WCHAR *argvW[])
*/
void
WCMD_process_command
(
WCHAR
*
command
,
CMD_LIST
**
cmdList
)
void
WCMD_execute
(
WCHAR
*
command
,
WCHAR
*
forVariable
,
WCHAR
*
forValue
,
CMD_LIST
**
cmdList
)
{
WCHAR
*
cmd
,
*
p
,
*
s
,
*
t
,
*
redir
;
WCHAR
*
cmd
,
*
p
,
*
redir
;
int
status
,
i
;
DWORD
count
,
creationDisposition
;
HANDLE
h
;
...
...
@@ -480,81 +563,24 @@ void WCMD_process_command (WCHAR *command, CMD_LIST **cmdList)
STD_OUTPUT_HANDLE
,
STD_ERROR_HANDLE
};
WINE_TRACE
(
"command on entry:%s (%p), with '%s'='%s'
\n
"
,
wine_dbgstr_w
(
command
),
cmdList
,
wine_dbgstr_w
(
forVariable
),
wine_dbgstr_w
(
forValue
));
/* Move copy of the command onto the heap so it can be expanded */
new_cmd
=
HeapAlloc
(
GetProcessHeap
(),
0
,
MAXSTRING
*
sizeof
(
WCHAR
));
strcpyW
(
new_cmd
,
command
);
/* For commands in a context (batch program): */
/* Expand environment variables in a batch file %{0-9} first */
/* including support for any ~ modifiers */
/* Additionally: */
/* Expand the DATE, TIME, CD, RANDOM and ERRORLEVEL special */
/* names allowing environment variable overrides */
/* NOTE: To support the %PATH:xxx% syntax, also perform */
/* manual expansion of environment variables here */
p
=
new_cmd
;
while
((
p
=
strchrW
(
p
,
'%'
)))
{
i
=
*
(
p
+
1
)
-
'0'
;
/* Don't touch %% */
if
(
*
(
p
+
1
)
==
'%'
)
{
p
+=
2
;
/* Replace %~ modifications if in batch program */
}
else
if
(
context
&&
*
(
p
+
1
)
==
'~'
)
{
WCMD_HandleTildaModifiers
(
&
p
,
NULL
);
p
++
;
/* Replace use of %0...%9 if in batch program*/
}
else
if
(
context
&&
(
i
>=
0
)
&&
(
i
<=
9
))
{
s
=
WCMD_strdupW
(
p
+
2
);
t
=
WCMD_parameter
(
context
->
command
,
i
+
context
->
shift_count
[
i
],
NULL
);
strcpyW
(
p
,
t
);
strcatW
(
p
,
s
);
free
(
s
);
/* Replace use of %* if in batch program*/
}
else
if
(
context
&&
*
(
p
+
1
)
==
'*'
)
{
WCHAR
*
startOfParms
=
NULL
;
s
=
WCMD_strdupW
(
p
+
2
);
t
=
WCMD_parameter
(
context
->
command
,
1
,
&
startOfParms
);
if
(
startOfParms
!=
NULL
)
strcpyW
(
p
,
startOfParms
);
else
*
p
=
0x00
;
strcatW
(
p
,
s
);
free
(
s
);
}
else
{
p
=
WCMD_expand_envvar
(
p
);
}
}
/* 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
);
cmd
=
new_cmd
;
/* In a batch program, unknown variables are replace by nothing */
/* so remove any remaining %var% */
if
(
context
)
{
p
=
cmd
;
while
((
p
=
strchrW
(
p
,
'%'
)))
{
if
(
*
(
p
+
1
)
==
'%'
)
{
p
+=
2
;
}
else
{
s
=
strchrW
(
p
+
1
,
'%'
);
if
(
!
s
)
{
*
p
=
0x00
;
}
else
{
t
=
WCMD_strdupW
(
s
+
1
);
strcpyW
(
p
,
t
);
free
(
t
);
}
}
}
/* Show prompt before batch line IF echo is on and in batch program */
if
(
echo_mode
&&
(
cmd
[
0
]
!=
'@'
))
{
WCMD_show_prompt
();
WCMD_output_asis
(
cmd
);
WCMD_output_asis
(
newline
);
}
/* Show prompt before batch line IF echo is on and in batch program */
if
(
context
&&
echo_mode
&&
(
cmd
[
0
]
!=
'@'
))
{
WCMD_show_prompt
();
WCMD_output_asis
(
cmd
);
WCMD_output_asis
(
newline
);
}
/*
...
...
@@ -1533,7 +1559,7 @@ void WCMD_pipe (CMD_LIST **cmdEntry, WCHAR *var, WCHAR *val) {
*
* Expands environment variables, allowing for WCHARacter substitution
*/
static
WCHAR
*
WCMD_expand_envvar
(
WCHAR
*
start
)
{
static
WCHAR
*
WCMD_expand_envvar
(
WCHAR
*
start
,
WCHAR
*
forVar
,
WCHAR
*
forVal
)
{
WCHAR
*
endOfVar
=
NULL
,
*
s
;
WCHAR
*
colonpos
=
NULL
;
WCHAR
thisVar
[
MAXSTRING
];
...
...
@@ -1551,20 +1577,38 @@ static WCHAR *WCMD_expand_envvar(WCHAR *start) {
static
const
WCHAR
CdP
[]
=
{
'%'
,
'C'
,
'D'
,
'%'
,
'\0'
};
static
const
WCHAR
Random
[]
=
{
'R'
,
'A'
,
'N'
,
'D'
,
'O'
,
'M'
,
'\0'
};
static
const
WCHAR
RandomP
[]
=
{
'%'
,
'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
));
/* Find the end of the environment variable, and extract name */
endOfVar
=
strchrW
(
start
+
1
,
'%'
);
if
(
endOfVar
==
NULL
)
{
endOfVar
=
strpbrkW
(
start
+
1
,
Delims
);
if
(
endOfVar
==
NULL
||
*
endOfVar
==
' '
)
{
/* In batch program, missing terminator for % and no following
':' just removes the '%' */
s
=
WCMD_strdupW
(
start
+
1
);
strcpyW
(
start
,
s
);
free
(
s
);
if
(
context
)
{
s
=
WCMD_strdupW
(
start
+
1
);
strcpyW
(
start
,
s
);
free
(
s
);
return
start
;
}
else
{
/* FIXME: Some other special conditions here depending on whether
in batch, complex or not, and whether env var exists or not! */
return
start
;
/* In command processing, just ignore it - allows command line
syntax like: for %i in (a.a) do echo %i */
return
start
+
1
;
}
}
/* If ':' found, process remaining up until '%' (or stop at ':' if
a missing '%' */
if
(
*
endOfVar
==
':'
)
{
WCHAR
*
endOfVar2
=
strchrW
(
endOfVar
+
1
,
'%'
);
if
(
endOfVar2
!=
NULL
)
endOfVar
=
endOfVar2
;
}
memcpy
(
thisVar
,
start
,
((
endOfVar
-
start
)
+
1
)
*
sizeof
(
WCHAR
));
thisVar
[(
endOfVar
-
start
)
+
1
]
=
0x00
;
colonpos
=
strchrW
(
thisVar
+
1
,
':'
);
...
...
@@ -1627,6 +1671,16 @@ static WCHAR *WCMD_expand_envvar(WCHAR *start) {
wsprintf
(
thisVarContents
,
fmt
,
rand
()
%
32768
);
len
=
strlenW
(
thisVarContents
);
/* Look for a matching 'for' variable */
}
else
if
(
forVar
&&
(
CompareString
(
LOCALE_USER_DEFAULT
,
SORT_STRINGSORT
,
thisVar
,
(
colonpos
-
thisVar
)
-
1
,
forVar
,
-
1
)
==
2
))
{
strcpyW
(
thisVarContents
,
forVal
);
len
=
strlenW
(
thisVarContents
);
}
else
{
len
=
ExpandEnvironmentStrings
(
thisVar
,
thisVarContents
,
...
...
@@ -1952,6 +2006,9 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
WCMD_output_asis
(
newline
);
}
/* Replace env vars if in a batch context */
if
(
context
)
handleExpansion
(
extraSpace
,
FALSE
,
NULL
,
NULL
);
/* Start with an empty string */
curLen
=
0
;
...
...
@@ -2234,6 +2291,7 @@ WCHAR *WCMD_ReadAndParseLine(WCHAR *optionalcmd, CMD_LIST **output, HANDLE readF
if
(
WCMD_fgets
(
extraSpace
,
MAXSTRING
,
readFrom
)
==
NULL
)
break
;
}
curPos
=
extraSpace
;
if
(
context
)
handleExpansion
(
extraSpace
,
FALSE
,
NULL
,
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