mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-03 12:23:25 +00:00
[CRT][CRT_APITEST] Fix __getmainargs and __wgetmainargs parsing, verified with apitests. Patch by Yaroslav Veremenko. CORE-11673 #resolve #comment Thanks!
svn path=/trunk/; revision=72214
This commit is contained in:
@@ -181,16 +181,18 @@ int aexpand(char* name, int expand_wildcards)
|
||||
*/
|
||||
void __getmainargs(int* argc, char*** argv, char*** env, int expand_wildcards, int* new_mode)
|
||||
{
|
||||
int i, afterlastspace, ignorespace, doexpand;
|
||||
int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex;
|
||||
size_t len;
|
||||
char* aNewCmdln;
|
||||
char* buffer;
|
||||
|
||||
/* missing threading init */
|
||||
|
||||
i = 0;
|
||||
afterlastspace = 0;
|
||||
ignorespace = 0;
|
||||
doexpand = expand_wildcards;
|
||||
escapedQuote = FALSE;
|
||||
slashesAdded = 0;
|
||||
inQuotes = 0;
|
||||
bufferIndex = 0;
|
||||
|
||||
if (__argv && _environ)
|
||||
{
|
||||
@@ -203,58 +205,94 @@ void __getmainargs(int* argc, char*** argv, char*** env, int expand_wildcards, i
|
||||
__argc = 0;
|
||||
|
||||
len = strlen(_acmdln);
|
||||
buffer = malloc(sizeof(char) * len);
|
||||
|
||||
/* Allocate a temporary buffer to be used instead of the original _acmdln parameter. */
|
||||
aNewCmdln = strndup(_acmdln, len);
|
||||
|
||||
while (aNewCmdln[i])
|
||||
// Reference: https://msdn.microsoft.com/en-us/library/a1y7w461(v=vs.71).aspx
|
||||
while (TRUE)
|
||||
{
|
||||
if (aNewCmdln[i] == '"')
|
||||
// Arguments are delimited by white space, which is either a space or a tab.
|
||||
if (i >= len || ((_acmdln[i] == ' ' || _acmdln[i] == '\t') && !inQuotes))
|
||||
{
|
||||
if(ignorespace)
|
||||
aexpand(strndup(buffer, bufferIndex), doexpand);
|
||||
// Copy the last element from buffer and quit the loop
|
||||
if (i >= len)
|
||||
{
|
||||
ignorespace = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ignorespace = 1;
|
||||
doexpand = 0;
|
||||
}
|
||||
memmove(aNewCmdln + i, aNewCmdln + i + 1, len - i);
|
||||
len--;
|
||||
|
||||
while (_acmdln[i] == ' ' || _acmdln[i] == '\t')
|
||||
++i;
|
||||
bufferIndex = 0;
|
||||
slashesAdded = 0;
|
||||
escapedQuote = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (aNewCmdln[i] == ' ' && !ignorespace)
|
||||
if (_acmdln[i] == '\\')
|
||||
{
|
||||
aexpand(strndup(aNewCmdln + afterlastspace, i - afterlastspace), doexpand);
|
||||
i++;
|
||||
while (aNewCmdln[i] == ' ')
|
||||
i++;
|
||||
afterlastspace=i;
|
||||
doexpand = expand_wildcards;
|
||||
buffer[bufferIndex++] = _acmdln[i];
|
||||
++slashesAdded;
|
||||
++i;
|
||||
escapedQuote = FALSE;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (aNewCmdln[afterlastspace] != 0)
|
||||
{
|
||||
aexpand(strndup(aNewCmdln + afterlastspace, i - afterlastspace), doexpand);
|
||||
if (_acmdln[i] == '\"')
|
||||
{
|
||||
if (slashesAdded > 0)
|
||||
{
|
||||
if (slashesAdded % 2 == 0)
|
||||
{
|
||||
// If an even number of backslashes is followed by a double quotation mark, then one backslash (\)
|
||||
// is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (")
|
||||
// is interpreted as a string delimiter.
|
||||
bufferIndex -= slashesAdded / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If an odd number of backslashes is followed by a double quotation mark, then one backslash (\)
|
||||
// is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is
|
||||
// interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (")
|
||||
// to be placed in argv.
|
||||
bufferIndex -= slashesAdded / 2 + 1;
|
||||
buffer[bufferIndex++] = '\"';
|
||||
slashesAdded = 0;
|
||||
escapedQuote = TRUE;
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
slashesAdded = 0;
|
||||
}
|
||||
else if (!inQuotes && i > 0 && _acmdln[i - 1] == '\"' && !escapedQuote)
|
||||
{
|
||||
buffer[bufferIndex++] = '\"';
|
||||
++i;
|
||||
escapedQuote = TRUE;
|
||||
continue;
|
||||
}
|
||||
slashesAdded = 0;
|
||||
escapedQuote = FALSE;
|
||||
inQuotes = !inQuotes;
|
||||
doexpand = inQuotes ? FALSE : expand_wildcards;
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferIndex++] = _acmdln[i];
|
||||
slashesAdded = 0;
|
||||
escapedQuote = FALSE;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Free the temporary buffer. */
|
||||
free(aNewCmdln);
|
||||
|
||||
free(buffer);
|
||||
HeapValidate(GetProcessHeap(), 0, NULL);
|
||||
|
||||
*argc = __argc;
|
||||
if (__argv == NULL)
|
||||
{
|
||||
__argv = (char**)malloc(sizeof(char*));
|
||||
__argv[0] = 0;
|
||||
__argv = (char**)malloc(sizeof(char*));
|
||||
__argv[0] = 0;
|
||||
}
|
||||
*argv = __argv;
|
||||
*env = _environ;
|
||||
@@ -269,16 +307,18 @@ void __getmainargs(int* argc, char*** argv, char*** env, int expand_wildcards, i
|
||||
void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv,
|
||||
int expand_wildcards, int* new_mode)
|
||||
{
|
||||
int i, afterlastspace, ignorespace, doexpand;
|
||||
int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex;
|
||||
size_t len;
|
||||
wchar_t* wNewCmdln;
|
||||
wchar_t* buffer;
|
||||
|
||||
/* missing threading init */
|
||||
|
||||
i = 0;
|
||||
afterlastspace = 0;
|
||||
ignorespace = 0;
|
||||
doexpand = expand_wildcards;
|
||||
escapedQuote = FALSE;
|
||||
slashesAdded = 0;
|
||||
inQuotes = 0;
|
||||
bufferIndex = 0;
|
||||
|
||||
if (__wargv && __winitenv)
|
||||
{
|
||||
@@ -291,58 +331,95 @@ void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv,
|
||||
__argc = 0;
|
||||
|
||||
len = wcslen(_wcmdln);
|
||||
buffer = malloc(sizeof(wchar_t) * len);
|
||||
|
||||
/* Allocate a temporary buffer to be used instead of the original _wcmdln parameter. */
|
||||
wNewCmdln = wcsndup(_wcmdln, len);
|
||||
|
||||
while (wNewCmdln[i])
|
||||
// Reference: https://msdn.microsoft.com/en-us/library/a1y7w461(v=vs.71).aspx
|
||||
while (TRUE)
|
||||
{
|
||||
if (wNewCmdln[i] == L'"')
|
||||
// Arguments are delimited by white space, which is either a space or a tab.
|
||||
if (i >= len || ((_wcmdln[i] == ' ' || _wcmdln[i] == '\t') && !inQuotes))
|
||||
{
|
||||
if(ignorespace)
|
||||
wexpand(wcsndup(buffer, bufferIndex), doexpand);
|
||||
// Copy the last element from buffer and quit the loop
|
||||
if (i >= len)
|
||||
{
|
||||
ignorespace = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
ignorespace = 1;
|
||||
doexpand = 0;
|
||||
}
|
||||
memmove(wNewCmdln + i, wNewCmdln + i + 1, (len - i) * sizeof(wchar_t));
|
||||
len--;
|
||||
|
||||
while (_wcmdln[i] == ' ' || _wcmdln[i] == '\t')
|
||||
++i;
|
||||
bufferIndex = 0;
|
||||
slashesAdded = 0;
|
||||
escapedQuote = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (wNewCmdln[i] == L' ' && !ignorespace)
|
||||
if (_wcmdln[i] == '\\')
|
||||
{
|
||||
wexpand(wcsndup(wNewCmdln + afterlastspace, i - afterlastspace), doexpand);
|
||||
i++;
|
||||
while (wNewCmdln[i] == L' ')
|
||||
i++;
|
||||
afterlastspace=i;
|
||||
doexpand = expand_wildcards;
|
||||
buffer[bufferIndex++] = _wcmdln[i];
|
||||
++slashesAdded;
|
||||
++i;
|
||||
escapedQuote = FALSE;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (wNewCmdln[afterlastspace] != 0)
|
||||
{
|
||||
wexpand(wcsndup(wNewCmdln + afterlastspace, i - afterlastspace), doexpand);
|
||||
if (_wcmdln[i] == '\"')
|
||||
{
|
||||
if (slashesAdded > 0)
|
||||
{
|
||||
if (slashesAdded % 2 == 0)
|
||||
{
|
||||
// If an even number of backslashes is followed by a double quotation mark, then one backslash (\)
|
||||
// is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (")
|
||||
// is interpreted as a string delimiter.
|
||||
bufferIndex -= slashesAdded / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If an odd number of backslashes is followed by a double quotation mark, then one backslash (\)
|
||||
// is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is
|
||||
// interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (")
|
||||
// to be placed in argv.
|
||||
bufferIndex -= slashesAdded / 2 + 1;
|
||||
buffer[bufferIndex++] = '\"';
|
||||
slashesAdded = 0;
|
||||
escapedQuote = TRUE;
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
slashesAdded = 0;
|
||||
}
|
||||
else if (!inQuotes && i > 0 && _wcmdln[i - 1] == '\"' && !escapedQuote)
|
||||
{
|
||||
buffer[bufferIndex++] = '\"';
|
||||
++i;
|
||||
escapedQuote = TRUE;
|
||||
continue;
|
||||
}
|
||||
slashesAdded = 0;
|
||||
escapedQuote = FALSE;
|
||||
inQuotes = !inQuotes;
|
||||
doexpand = inQuotes ? FALSE : expand_wildcards;
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
|
||||
buffer[bufferIndex++] = _wcmdln[i];
|
||||
slashesAdded = 0;
|
||||
escapedQuote = FALSE;
|
||||
++i;
|
||||
}
|
||||
|
||||
/* Free the temporary buffer. */
|
||||
free(wNewCmdln);
|
||||
free(buffer);
|
||||
|
||||
HeapValidate(GetProcessHeap(), 0, NULL);
|
||||
|
||||
*argc = __argc;
|
||||
if (__wargv == NULL)
|
||||
{
|
||||
__wargv = (wchar_t**)malloc(sizeof(wchar_t*));
|
||||
__wargv[0] = 0;
|
||||
__wargv = (wchar_t**)malloc(sizeof(wchar_t*));
|
||||
__wargv[0] = 0;
|
||||
}
|
||||
*wargv = __wargv;
|
||||
*wenv = __winitenv;
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* PROJECT: ReactOS api tests
|
||||
* LICENSE: GPLv2+ - See COPYING in the top level directory
|
||||
* PURPOSE: Test for __getmainargs and __wgetmainargs
|
||||
* PROGRAMMER: Yaroslav Veremenko <[email protected]>
|
||||
*/
|
||||
|
||||
#include <apitest.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
const char **__p__acmdln(void);
|
||||
void __getmainargs(int* argc, char*** argv, char*** env, int expand_wildcards, int* new_mode);
|
||||
const wchar_t **__p__wcmdln(void);
|
||||
void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv, int expand_wildcards, int* new_mode);
|
||||
|
||||
|
||||
#define winetest_ok_str(x, y) \
|
||||
winetest_ok(strcmp(x, y) == 0, "Wrong string. Expected '%s', got '%s'\n", y, x)
|
||||
#define winetest_ok_wstr(x, y) \
|
||||
winetest_ok(wcscmp(x, y) == 0, "Wrong string. Expected '%s', got '%s'\n", wine_dbgstr_w(y), wine_dbgstr_w(x))
|
||||
#define ok_argsA (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : ok_argsA_imp
|
||||
#define ok_argsW (winetest_set_location(__FILE__, __LINE__), 0) ? (void)0 : ok_argsW_imp
|
||||
|
||||
|
||||
void
|
||||
ok_argsA_imp(const char* input_args, const char* arg1, const char* arg2, const char* arg3)
|
||||
{
|
||||
int argc = 0, mode = 0;
|
||||
char** argv, **env;
|
||||
|
||||
/* Remove cached argv, setup our input as program argument. */
|
||||
*__p___argv() = NULL;
|
||||
*__p__acmdln() = input_args;
|
||||
|
||||
/* Process the commandline stored in _acmdln */
|
||||
__getmainargs(&argc, &argv, &env, 0, &mode);
|
||||
|
||||
winetest_ok(argc == 4, "Wrong value for argc, expected: 4, got: %d\n", argc);
|
||||
if(argc != 4)
|
||||
return;
|
||||
|
||||
winetest_ok_str(argv[0], "test.exe");
|
||||
winetest_ok_str(argv[1], arg1);
|
||||
winetest_ok_str(argv[2], arg2);
|
||||
winetest_ok_str(argv[3], arg3);
|
||||
}
|
||||
|
||||
void
|
||||
ok_argsW_imp(const wchar_t* input_args, const wchar_t* arg1, const wchar_t* arg2, const wchar_t* arg3)
|
||||
{
|
||||
int argc = 0, mode = 0;
|
||||
wchar_t** argv, **env;
|
||||
|
||||
/* Remove cached wargv, setup our input as program argument. */
|
||||
*__p___wargv() = NULL;
|
||||
*__p__wcmdln() = input_args;
|
||||
|
||||
/* Process the commandline stored in _wcmdln */
|
||||
__wgetmainargs(&argc, &argv, &env, 0, &mode);
|
||||
|
||||
winetest_ok(argc == 4, "Wrong value for argc, expected: 4, got: %d\n", argc);
|
||||
if(argc != 4)
|
||||
return;
|
||||
|
||||
winetest_ok_wstr(argv[0], L"test.exe");
|
||||
winetest_ok_wstr(argv[1], arg1);
|
||||
winetest_ok_wstr(argv[2], arg2);
|
||||
winetest_ok_wstr(argv[3], arg3);
|
||||
}
|
||||
|
||||
START_TEST(__getmainargs)
|
||||
{
|
||||
ok_argsA("test.exe \"a b c\" d e", "a b c", "d", "e");
|
||||
ok_argsA("test.exe \"ab\\\"c\" \"\\\\\" d", "ab\"c", "\\", "d");
|
||||
ok_argsA("test.exe a\\\\\\b d\"e f\"g h", "a\\\\\\b", "de fg", "h");
|
||||
ok_argsA("test.exe a\\\\\\\"b c d", "a\\\"b", "c", "d");
|
||||
ok_argsA("test.exe a\\\\\\\\\"b c\" d e", "a\\\\b c", "d", "e");
|
||||
ok_argsA("test.exe a b \"\"", "a", "b", "");
|
||||
ok_argsA("test.exe a \"\" b", "a", "", "b");
|
||||
ok_argsA("test.exe a \"b\"\" c", "a", "b\"", "c");
|
||||
ok_argsA("test.exe a \"b\\\"\" c", "a", "b\"", "c");
|
||||
ok_argsA("test.exe a \" b\\ \"\" c", "a", " b\\ \"", "c");
|
||||
ok_argsA("test.exe a \"b\\ \"\"\" c\" d", "a", "b\\ \" c", "d");
|
||||
ok_argsA("test.exe a \"b\\ \"\"\" \"c \"\"\"\" d", "a", "b\\ \" c", "\" d");
|
||||
|
||||
ok_argsW(L"test.exe \"a b c\" d e", L"a b c", L"d", L"e");
|
||||
ok_argsW(L"test.exe \"ab\\\"c\" \"\\\\\" d", L"ab\"c", L"\\", L"d");
|
||||
ok_argsW(L"test.exe a\\\\\\b d\"e f\"g h", L"a\\\\\\b", L"de fg", L"h");
|
||||
ok_argsW(L"test.exe a\\\\\\\"b c d", L"a\\\"b", L"c", L"d");
|
||||
ok_argsW(L"test.exe a\\\\\\\\\"b c\" d e", L"a\\\\b c", L"d", L"e");
|
||||
ok_argsW(L"test.exe a b \"\"", L"a", L"b", L"");
|
||||
ok_argsW(L"test.exe a \"\" b", L"a", L"", L"b");
|
||||
ok_argsW(L"test.exe a \"b\"\" c", L"a", L"b\"", L"c");
|
||||
ok_argsW(L"test.exe a \"b\\\"\" c", L"a", L"b\"", L"c");
|
||||
ok_argsW(L"test.exe a \" b\\ \"\" c", L"a", L" b\\ \"", L"c");
|
||||
ok_argsW(L"test.exe a \"b\\ \"\"\" c\" d", L"a", L"b\\ \" c", L"d");
|
||||
ok_argsW(L"test.exe a \"b\\ \"\"\" \"c \"\"\"\" d", L"a", L"b\\ \" c", L"\" d");
|
||||
}
|
||||
@@ -66,7 +66,7 @@ list(APPEND SOURCE_MSVCRT
|
||||
# __doserrno.c
|
||||
# __fpecode.c
|
||||
# __get_app_type.c
|
||||
# __getmainargs.c
|
||||
__getmainargs.c
|
||||
# __initenv
|
||||
# __iob_func.c
|
||||
# __isascii.c
|
||||
|
||||
@@ -25,6 +25,7 @@ extern void func_strtoul(void);
|
||||
extern void func_wcsnlen(void);
|
||||
extern void func_wcstombs(void);
|
||||
extern void func_wcstoul(void);
|
||||
extern void func___getmainargs(void);
|
||||
|
||||
extern void func_static_construct(void);
|
||||
extern void func_static_init(void);
|
||||
@@ -50,6 +51,7 @@ const struct test winetest_testlist[] =
|
||||
#endif
|
||||
#if defined(TEST_STATIC_CRT)
|
||||
#elif defined(TEST_MSVCRT)
|
||||
{ "__getmainargs", func___getmainargs },
|
||||
{ "_vscprintf", func__vscprintf },
|
||||
{ "_vscwprintf", func__vscwprintf },
|
||||
|
||||
|
||||
Reference in New Issue
Block a user