From 51b0d941d0b9c9dc60ecbcc99ed0eacae4329e85 Mon Sep 17 00:00:00 2001 From: Jason Edmeades Date: Tue, 23 Oct 2012 22:05:06 +0100 Subject: [PATCH] cmd: Add for /f delims= support. --- programs/cmd/batch.c | 29 ++++++++++++++++++------ programs/cmd/builtins.c | 13 ++++++----- programs/cmd/tests/test_builtins.cmd.exp | 12 +++++----- programs/cmd/wcmd.h | 2 ++ 4 files changed, 37 insertions(+), 19 deletions(-) diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index 1c0bc24ffa9..7b037d7fbec 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -121,9 +121,10 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA } /******************************************************************* - * WCMD_parameter + * WCMD_parameter_with_delims * - * Extracts a delimited parameter from an input string + * Extracts a delimited parameter from an input string, providing + * the delimiters characters to use * * PARAMS * s [I] input string, non NULL @@ -135,6 +136,7 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA * wholecmdline [I] True to indicate this routine is being used to parse the * command line, and special logic for arg0->1 transition * needs to be applied. + * delims[I] The delimiter characters to use * * RETURNS * Success: The nth delimited parameter found in s @@ -150,10 +152,9 @@ void WCMD_batch (WCHAR *file, WCHAR *command, BOOL called, WCHAR *startLabel, HA * other API calls, e.g. c:\"a b"\c is returned as c:\a b\c. However, some commands * need to preserve the exact syntax (echo, for, etc) hence the raw option. */ -WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, WCHAR **end, BOOL raw, - BOOL wholecmdline) +WCHAR *WCMD_parameter_with_delims (WCHAR *s, int n, WCHAR **start, WCHAR **end, + BOOL raw, BOOL wholecmdline, const WCHAR *delims) { - static const WCHAR defaultDelims[] = { ' ', '\t', ',', '=', ';', '\0' }; int curParamNb = 0; static WCHAR param[MAX_PATH]; WCHAR *p = s, *begin; @@ -165,7 +166,7 @@ WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, WCHAR **end, BOOL raw, while (TRUE) { /* Absorb repeated word delimiters until we get to the next token (or the end!) */ - while (*p && (strchrW(defaultDelims, *p) != NULL)) + while (*p && (strchrW(delims, *p) != NULL)) p++; if (*p == '\0') return param; @@ -179,7 +180,7 @@ WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, WCHAR **end, BOOL raw, /* Loop character by character, but just need to special case quotes */ while (*p) { /* Once we have found a delimiter, break */ - if (strchrW(defaultDelims, *p) != NULL) break; + if (strchrW(delims, *p) != NULL) break; /* Very odd special case - Seems as if a ( acts as a delimiter which is not swallowed but is effective only when it comes between the program @@ -218,6 +219,20 @@ WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, WCHAR **end, BOOL raw, } } +/******************************************************************* + * WCMD_parameter + * + * Extracts a delimited parameter from an input string, using a + * default set of delimiter characters. For parameters, see the main + * function above. + */ +WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, WCHAR **end, BOOL raw, + BOOL wholecmdline) +{ + static const WCHAR defaultDelims[] = { ' ', '\t', ',', '=', ';', '\0' }; + return WCMD_parameter_with_delims (s, n, start, end, raw, wholecmdline, defaultDelims); +} + /**************************************************************************** * WCMD_fgets * diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index 4bb4702a9be..8eaa9e77b94 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1600,7 +1600,7 @@ static BOOL WCMD_parse_forf_options(WCHAR *options, WCHAR *eol, int *skip, } if (*pos==' ' && *(pos+1)==0) delims[i++] = *pos; delims[i++] = 0; /* Null terminate the delims */ - WINE_FIXME("Found delims as '%s'\n", wine_dbgstr_w(delims)); + WINE_TRACE("Found delims as '%s'\n", wine_dbgstr_w(delims)); /* Save the tokens being requested */ } else if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, @@ -1694,6 +1694,7 @@ static void WCMD_add_dirstowalk(DIRECTORY_STACK *dirsToWalk) { * doExecuted [O] - Set to TRUE if the DO is ever executed once * forf_skip [I/O] - How many lines to skip first * forf_eol [I] - The 'end of line' (comment) character + * forf_delims [I] - The delimiters to use when breaking the string apart */ static void WCMD_parse_line(CMD_LIST *cmdStart, const WCHAR *firstCmd, @@ -1702,7 +1703,8 @@ static void WCMD_parse_line(CMD_LIST *cmdStart, WCHAR *buffer, BOOL *doExecuted, int *forf_skip, - WCHAR forf_eol) { + WCHAR forf_eol, + WCHAR *forf_delims) { WCHAR *parm, *where; @@ -1713,7 +1715,7 @@ static void WCMD_parse_line(CMD_LIST *cmdStart, } /* Extract the parameter */ - parm = WCMD_parameter (buffer, 0, &where, NULL, FALSE, FALSE); + parm = WCMD_parameter_with_delims(buffer, 0, &where, NULL, FALSE, FALSE, forf_delims); WINE_TRACE("Parsed parameter: %s from %s\n", wine_dbgstr_w(parm), wine_dbgstr_w(buffer)); @@ -2070,7 +2072,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) { /* Read line by line until end of file */ while (WCMD_fgets(buffer, sizeof(buffer)/sizeof(WCHAR), input)) { WCMD_parse_line(cmdStart, firstCmd, &cmdEnd, variable, buffer, &doExecuted, - &forf_skip, forf_eol); + &forf_skip, forf_eol, forf_delims); buffer[0] = 0; } CloseHandle (input); @@ -2090,7 +2092,6 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) { Note that the last quote is removed from the set and the string terminates there to mimic windows */ WCHAR *strend = strrchrW(itemStart, forf_usebackq?'\'':'"'); - if (strend) { *strend = 0x00; itemStart++; @@ -2099,7 +2100,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) { /* Copy the item away from the global buffer used by WCMD_parameter */ strcpyW(buffer, itemStart); WCMD_parse_line(cmdStart, firstCmd, &cmdEnd, variable, buffer, &doExecuted, - &forf_skip, forf_eol); + &forf_skip, forf_eol, forf_delims); /* Only one string can be supplied in the whole set, abort future set processing */ thisSet = NULL; diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index c15a58d190c..9b5eb3bc64b 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -826,14 +826,14 @@ ad z@y a|d no output -@todo_wine@no output +no output ------ delims option -@todo_wine@a -@todo_wine@a@space@ -@todo_wine@a d a -@todo_wine@C r -@todo_wine@foo bar baz +a@space@ +a d +a +C r +foo bar baz @todo_wine@c:\ ------ skip option c diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index d4d148f72d7..26b89c650f1 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -108,6 +108,8 @@ static inline BOOL WCMD_is_console_handle(HANDLE h) } WCHAR *WCMD_fgets (WCHAR *buf, DWORD n, HANDLE stream); WCHAR *WCMD_parameter (WCHAR *s, int n, WCHAR **start, WCHAR **end, BOOL raw, BOOL wholecmdline); +WCHAR *WCMD_parameter_with_delims (WCHAR *s, int n, WCHAR **start, WCHAR **end, 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);