[PATCH 4/6] [cmd] Add for /f parsingkeyword parsing, add support for skip=
Ann and Jason Edmeades
jason at edmeades.me.uk
Tue Oct 16 18:42:23 CDT 2012
Parse the options you can provide with for /f to control the
subsequent parsing, and add support for the simplest (skip).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20121017/7188bf76/attachment-0001.html>
-------------- next part --------------
From 0f4ef89f4878c1f8589e7ccb6ce2d5b96fe43122 Mon Sep 17 00:00:00 2001
From: Jason Edmeades <jason at edmeades.me.uk>
Date: Sun, 14 Oct 2012 22:57:53 +0100
Subject: [PATCH 4/6] [cmd] Add for /f parsingkeyword parsing, add support for
skip=
Parse the options you can provide with for /f to control the
subsequent parsing, and add support for the simplest (skip).
---
programs/cmd/builtins.c | 112 ++++++++++++++++++++++++++++--
programs/cmd/tests/test_builtins.cmd | 2 +
programs/cmd/tests/test_builtins.cmd.exp | 8 ++-
3 files changed, 112 insertions(+), 10 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 8ae9eb2..73b2b52 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -1536,7 +1536,6 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
int thisDepth;
WCHAR optionsRoot[MAX_PATH];
DIRECTORY_STACK *dirsToWalk = NULL;
-
BOOL expandDirs = FALSE;
BOOL useNumbers = FALSE;
BOOL doFileset = FALSE;
@@ -1546,6 +1545,13 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
int itemNum;
CMD_LIST *thisCmdStart;
int parameterNo = 0;
+ WCHAR forf_eol=0;
+ int forf_skip=0;
+ WCHAR forf_delims[256];
+ WCHAR forf_tokens[MAXSTRING];
+ BOOL forf_usebackq = FALSE;
+ static const WCHAR forf_defaultdelims[] = {' ', '\t'};
+ static const WCHAR forf_defaulttokens[] = {'1'};
/* Handle optional qualifiers (multiple are allowed) */
WCHAR *thisArg = WCMD_parameter(p, parameterNo++, NULL, NULL, FALSE, FALSE);
@@ -1579,10 +1585,6 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
if (thisArg && *thisArg != '/' && *thisArg != '%') {
parameterNo++;
strcpyW(optionsRoot, thisArg);
- if (!doRecurse) {
- static unsigned int once;
- if (!once++) WINE_FIXME("/F needs to handle options\n");
- }
}
break;
}
@@ -1600,8 +1602,97 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
return;
}
+ /* With for /f parse the options if provided */
+ if (doFileset) {
+
+ WCHAR *pos = optionsRoot;
+ int len = strlenW(optionsRoot);
+ static const WCHAR eolW[] = {'e','o','l','='};
+ static const WCHAR skipW[] = {'s','k','i','p','='};
+ static const WCHAR tokensW[] = {'t','o','k','e','n','s','='};
+ static const WCHAR delimsW[] = {'d','e','l','i','m','s','='};
+ static const WCHAR usebackqW[] = {'u','s','e','b','a','c','k','q'};
+
+ strcpyW(forf_delims, forf_defaultdelims);
+ strcpyW(forf_delims, forf_defaulttokens);
+
+ /* Strip leading and trailing quotes */
+ if ((*pos == '"') && (pos[len-1] == '"')) {
+ pos[len-1] = 0;
+ pos++;
+ }
+
+ /* Process each keyword */
+ while (pos && *pos) {
+ if (*pos == ' ' || *pos == '\t') {
+ pos++;
+
+ /* Save End of line character (Ignore line if first token (based on delims) starts with it) */
+ } else if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ pos, sizeof(eolW)/sizeof(WCHAR),
+ eolW, sizeof(eolW)/sizeof(WCHAR)) == CSTR_EQUAL) {
+ forf_eol = *(pos + sizeof(eolW)/sizeof(WCHAR));
+ pos = pos + sizeof(eolW)/sizeof(WCHAR) + 1;
+ WINE_FIXME("Found eol as %c(%x)\n", forf_eol, forf_eol);
+
+ /* Save number of lines to skip (Can be in base 10, hex (0x...) or octal (0xx) */
+ } else if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ pos, sizeof(skipW)/sizeof(WCHAR),
+ skipW, sizeof(skipW)/sizeof(WCHAR)) == CSTR_EQUAL) {
+ WCHAR *nextchar = NULL;
+ pos = pos + sizeof(skipW)/sizeof(WCHAR);
+ forf_skip = strtoulW(pos, &nextchar, 0);
+ WINE_TRACE("Found skip as %d lines\n", forf_skip);
+ pos = nextchar;
+
+ /* Save if usebackq semantics are in effect */
+ } else if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ pos, sizeof(usebackqW)/sizeof(WCHAR),
+ usebackqW, sizeof(usebackqW)/sizeof(WCHAR)) == CSTR_EQUAL) {
+ forf_usebackq = TRUE;
+ pos = pos + sizeof(usebackqW)/sizeof(WCHAR);
+ if (forf_usebackq) WINE_FIXME("Found usebackq\n");
+
+ /* Save the supplied delims. Slightly odd as space can be a delimiter but only
+ if you finish the optionsroot string with delims= otherwise the space is
+ just a token delimiter! */
+ } else if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ pos, sizeof(delimsW)/sizeof(WCHAR),
+ delimsW, sizeof(delimsW)/sizeof(WCHAR)) == CSTR_EQUAL) {
+ int i=0;
+
+ pos = pos + sizeof(delimsW)/sizeof(WCHAR);
+ while (*pos && *pos != ' ') {
+ forf_delims[i++] = *pos;
+ pos++;
+ }
+ if (*pos==' ' && *(pos+1)==0) forf_delims[i++] = *pos;
+ forf_delims[i++] = 0; /* Null terminate the delims */
+ WINE_FIXME("Found delims as '%s'\n", wine_dbgstr_w(forf_delims));
+
+ /* Save the tokens being requested */
+ } else if (CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT,
+ pos, sizeof(tokensW)/sizeof(WCHAR),
+ tokensW, sizeof(tokensW)/sizeof(WCHAR)) == CSTR_EQUAL) {
+ int i=0;
+
+ pos = pos + sizeof(tokensW)/sizeof(WCHAR);
+ while (*pos && *pos != ' ') {
+ forf_tokens[i++] = *pos;
+ pos++;
+ }
+ forf_tokens[i++] = 0; /* Null terminate the tokens */
+ WINE_FIXME("Found tokens as '%s'\n", wine_dbgstr_w(forf_tokens));
+
+ } else {
+ WINE_TRACE("Unexpected data in optionsroot: '%s'\n", wine_dbgstr_w(pos));
+ WCMD_output_stderr (WCMD_LoadMessage(WCMD_SYNTAXERR));
+ return;
+ }
+ }
+
/* Set up the list of directories to recurse if we are going to */
- if (doRecurse) {
+ } else if (doRecurse) {
/* Allocate memory, add to list */
dirsToWalk = HeapAlloc(GetProcessHeap(), 0, sizeof(DIRECTORY_STACK));
dirsToWalk->next = NULL;
@@ -1835,6 +1926,13 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
while (WCMD_fgets(buffer, sizeof(buffer)/sizeof(WCHAR), input)) {
+ /* Skip lines if requested */
+ if (forf_skip) {
+ forf_skip--;
+ buffer[0] = 0;
+ continue;
+ }
+
/* Skip blank lines*/
parm = WCMD_parameter (buffer, 0, &where, NULL, FALSE, FALSE);
WINE_TRACE("Parsed parameter: %s from %s\n", wine_dbgstr_w(parm),
@@ -1871,7 +1969,7 @@ void WCMD_for (WCHAR *p, CMD_LIST **cmdList) {
WINE_TRACE("Parsed parameter: %s from %s\n", wine_dbgstr_w(parm),
wine_dbgstr_w(buffer));
- if (where) {
+ if (where && forf_skip == 0) {
/* FIXME: The following should be moved into its own routine and
reused for the string literal parsing below */
thisCmdStart = cmdStart;
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index 3d01151..578826b 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -1032,6 +1032,8 @@ for /f "skip=3" %%i in (foo) do echo %%i > output_file
if not exist output_file (echo no output) else (del output_file)
for /f "skip=4" %%i in (foo) do echo %%i > output_file
if not exist output_file (echo no output) else (del output_file)
+for /f "skip=02" %%i in (foo) do echo %%i
+for /f "skip=0x2" %%i in (foo) do echo %%i
cd ..
rd /s/q foobar
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index b7e8397..12fbd8f 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -653,9 +653,11 @@ a|d
foo bar baz
@todo_wine at c:\
------ skip option
- at todo_wine@c
- at todo_wine@no output
- at todo_wine@no output
+c
+no output
+no output
+c
+c
------------ Testing del /a ------------
not-r.test not found after delete, good
r.test found before delete, good
--
1.7.9.5
More information about the wine-patches
mailing list