From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- programs/cmd/batch.c | 64 +++++++++++++++++++++++++ programs/cmd/builtins.c | 104 ++++++++++------------------------------ programs/cmd/wcmd.h | 2 + 3 files changed, 91 insertions(+), 79 deletions(-)
diff --git a/programs/cmd/batch.c b/programs/cmd/batch.c index 4416dab1705..5ed7dda871e 100644 --- a/programs/cmd/batch.c +++ b/programs/cmd/batch.c @@ -702,3 +702,67 @@ RETURN_CODE WCMD_call(WCHAR *command) } return return_code; } + +void WCMD_set_label_end(WCHAR *string) +{ + static const WCHAR labelEndsW[] = L"><|& :\t"; + WCHAR *p; + + /* Label ends at whitespace or redirection characters */ + if ((p = wcspbrk(string, labelEndsW))) *p = L'\0'; +} + +static BOOL find_next_label(HANDLE h, ULONGLONG end, WCHAR candidate[MAXSTRING]) +{ + while (WCMD_fgets(candidate, MAXSTRING, h)) + { + WCHAR *str = candidate; + + /* Ignore leading whitespace or no-echo character */ + while (*str == L'@' || iswspace(*str)) str++; + + /* If the first real character is a : then this is a label */ + if (*str == L':') + { + /* Skip spaces between : and label */ + for (str++; iswspace(*str); str++) {} + memmove(candidate, str, (wcslen(str) + 1) * sizeof(WCHAR)); + WCMD_set_label_end(candidate); + + return TRUE; + } + if (end) + { + LARGE_INTEGER li = {.QuadPart = 0}, curli; + if (!SetFilePointerEx(h, li, &curli, FILE_CURRENT)) return FALSE; + if (curli.QuadPart > end) break; + } + } + return FALSE; +} + +BOOL WCMD_find_label(HANDLE h, const WCHAR *label, LARGE_INTEGER *pos) +{ + LARGE_INTEGER where = *pos, zeroli = {.QuadPart = 0}; + WCHAR candidate[MAXSTRING]; + + if (!*label) return FALSE; + + if (!SetFilePointerEx(h, *pos, NULL, FILE_BEGIN)) return FALSE; + while (find_next_label(h, ~(ULONGLONG)0, candidate)) + { + TRACE("comparing found label %s\n", wine_dbgstr_w(candidate)); + if (!lstrcmpiW(candidate, label)) + return SetFilePointerEx(h, zeroli, pos, FILE_CURRENT); + } + TRACE("Label not found, trying from beginning of file\n"); + if (!SetFilePointerEx(h, zeroli, NULL, FILE_BEGIN)) return FALSE; + while (find_next_label(h, where.QuadPart, candidate)) + { + TRACE("comparing found label %s\n", wine_dbgstr_w(candidate)); + if (!lstrcmpiW(candidate, label)) + return SetFilePointerEx(h, zeroli, pos, FILE_CURRENT); + } + TRACE("Reached wrap point, label not found\n"); + return FALSE; +} diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index a728c4141b9..4eec2119462 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -1815,89 +1815,35 @@ RETURN_CODE WCMD_give_help(WCHAR *args)
RETURN_CODE WCMD_goto(void) { - WCHAR string[MAX_PATH]; - WCHAR *labelend = NULL; - const WCHAR labelEndsW[] = L"><|& :\t"; - - if (context != NULL) { - WCHAR *paramStart = param1, *str; - - if (param1[0] == 0x00) { - WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOARG)); - return ERROR_INVALID_FUNCTION; - } - - /* Handle special :EOF label */ - if (lstrcmpiW(L":eof", param1) == 0) { - context -> skip_rest = TRUE; - return RETURN_CODE_ABORTED; - } - - /* Support goto :label as well as goto label plus remove trailing chars */ - if (*paramStart == ':') paramStart++; - labelend = wcspbrk(paramStart, labelEndsW); - if (labelend) *labelend = 0x00; - WINE_TRACE("goto label: '%s'\n", wine_dbgstr_w(paramStart)); - - /* Loop through potentially twice - once from current file position - through to the end, and second time from start to current file - position */ - if (*paramStart) { - int loop; - LARGE_INTEGER startli; - for (loop=0; loop<2; loop++) { - if (loop==0) { - /* On first loop, save the file size */ - startli.QuadPart = 0; - startli.u.LowPart = SetFilePointer(context -> h, startli.u.LowPart, - &startli.u.HighPart, FILE_CURRENT); - } else { - /* On second loop, start at the beginning of the file */ - WINE_TRACE("Label not found, trying from beginning of file\n"); - if (loop==1) SetFilePointer (context -> h, 0, NULL, FILE_BEGIN); - } - - while (WCMD_fgets (string, ARRAY_SIZE(string), context -> h)) { - str = string; - - /* Ignore leading whitespace or no-echo character */ - while (*str=='@' || iswspace (*str)) str++; - - /* If the first real character is a : then this is a label */ - if (*str == ':') { - str++; - - /* Skip spaces between : and label */ - while (iswspace (*str)) str++; - WINE_TRACE("str before brk %s\n", wine_dbgstr_w(str)); + if (context != NULL) + { + WCHAR *paramStart = param1; + LARGE_INTEGER li, zeroli = {.QuadPart = 0}; + if (!param1[0]) + { + WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOARG)); + return ERROR_INVALID_FUNCTION; + }
- /* Label ends at whitespace or redirection characters */ - labelend = wcspbrk(str, labelEndsW); - if (labelend) *labelend = 0x00; - WINE_TRACE("comparing found label %s\n", wine_dbgstr_w(str)); + /* Handle special :EOF label */ + if (lstrcmpiW(L":eof", param1) == 0) + { + context->skip_rest = TRUE; + return RETURN_CODE_ABORTED; + }
- if (lstrcmpiW (str, paramStart) == 0) return RETURN_CODE_ABORTED; - } + /* Support goto :label as well as goto label plus remove trailing chars */ + if (*paramStart == ':') paramStart++; + WCMD_set_label_end(paramStart); + TRACE("goto label: '%s'\n", wine_dbgstr_w(paramStart));
- /* See if we have gone beyond the end point if second time through */ - if (loop==1) { - LARGE_INTEGER curli; - curli.QuadPart = 0; - curli.u.LowPart = SetFilePointer(context -> h, curli.u.LowPart, - &curli.u.HighPart, FILE_CURRENT); - if (curli.QuadPart > startli.QuadPart) { - WINE_TRACE("Reached wrap point, label not found\n"); - break; - } - } - } - } + SetFilePointerEx(context->h, zeroli, &li, FILE_CURRENT); + if (WCMD_find_label(context->h, paramStart, &li)) + return RETURN_CODE_ABORTED; + WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOTARGET)); + context->skip_rest = TRUE; } - - WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOTARGET)); - context -> skip_rest = TRUE; - } - return ERROR_INVALID_FUNCTION; + return ERROR_INVALID_FUNCTION; }
/***************************************************************************** diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 4fad2884e1e..5b76872b8e9 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -221,6 +221,8 @@ void node_dispose_tree(CMD_NODE *cmds); RETURN_CODE node_execute(CMD_NODE *node);
RETURN_CODE WCMD_call_batch(const WCHAR *, WCHAR *); +BOOL WCMD_find_label(HANDLE h, const WCHAR*, LARGE_INTEGER *pos); +void WCMD_set_label_end(WCHAR *string);
void *xrealloc(void *, size_t) __WINE_ALLOC_SIZE(2) __WINE_DEALLOC(free);