Index: sdk/lib/crt/misc/getargs.c =================================================================== --- sdk/lib/crt/misc/getargs.c (revision 72035) +++ sdk/lib/crt/misc/getargs.c (working copy) @@ -181,16 +181,21 @@ */ 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; + len = strlen(_acmdln); + escapedQuote = FALSE; + slashesAdded = 0; + inQuotes = 0; + buffer = malloc(sizeof(char) * len); + bufferIndex = 0; if (__argv && _environ) { @@ -202,52 +207,89 @@ __argc = 0; - len = strlen(_acmdln); - /* 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] == '"') - { - if(ignorespace) - { - ignorespace = 0; - } - else - { - ignorespace = 1; - doexpand = 0; - } - memmove(aNewCmdln + i, aNewCmdln + i + 1, len - i); - len--; - continue; - } + // Arguments are delimited by white space, which is either a space or a tab. + if (i >= len || (aNewCmdln[i] == ' ' || aNewCmdln[i] == '\t') && !inQuotes) + { + aexpand(strndup(buffer, bufferIndex), doexpand); + // Copy the last element from buffer and quit the loop + if (i >= len) + { + break; + } + + while (aNewCmdln[i] == ' ') + ++i; + bufferIndex = 0; + slashesAdded = 0; + escapedQuote = FALSE; + continue; + } - if (aNewCmdln[i] == ' ' && !ignorespace) - { - aexpand(strndup(aNewCmdln + afterlastspace, i - afterlastspace), doexpand); - i++; - while (aNewCmdln[i] == ' ') - i++; - afterlastspace=i; - doexpand = expand_wildcards; - } - else - { - i++; - } - } + if (aNewCmdln[i] == '\\') + { + buffer[bufferIndex++] = aNewCmdln[i]; + ++slashesAdded; + ++i; + escapedQuote = FALSE; + continue; + } - if (aNewCmdln[afterlastspace] != 0) - { - aexpand(strndup(aNewCmdln + afterlastspace, i - afterlastspace), doexpand); + if (aNewCmdln[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 && aNewCmdln[i -1] == '\"' && !escapedQuote) + { + buffer[bufferIndex++] = '\"'; + ++i; + escapedQuote = TRUE; + continue; + } + slashesAdded = 0; + escapedQuote = FALSE; + inQuotes = !inQuotes; + doexpand = inQuotes ? FALSE : expand_wildcards; + ++i; + continue; + } + + buffer[bufferIndex++] = aNewCmdln[i]; + slashesAdded = 0; + escapedQuote = FALSE; + ++i; } - /* Free the temporary buffer. */ + /* Free the temporary buffers. */ + free(buffer); free(aNewCmdln); - HeapValidate(GetProcessHeap(), 0, NULL); *argc = __argc; @@ -269,16 +311,21 @@ 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; + len = wcslen(_wcmdln); + escapedQuote = FALSE; + slashesAdded = 0; + inQuotes = 0; + buffer = malloc(sizeof(wchar_t) * len); + bufferIndex = 0; if (__wargv && __winitenv) { @@ -290,50 +337,88 @@ __argc = 0; - len = wcslen(_wcmdln); - - /* Allocate a temporary buffer to be used instead of the original _wcmdln parameter. */ + /* 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'"') - { - if(ignorespace) - { - ignorespace = 0; - } - else - { - ignorespace = 1; - doexpand = 0; - } - memmove(wNewCmdln + i, wNewCmdln + i + 1, (len - i) * sizeof(wchar_t)); - len--; - continue; - } + // Arguments are delimited by white space, which is either a space or a tab. + if (i >= len || (wNewCmdln[i] == ' ' || wNewCmdln[i] == '\t') && !inQuotes) + { + wexpand(wcsndup(buffer, bufferIndex), doexpand); + // Copy the last element from buffer and quit the loop + if (i >= len) + { + break; + } + + while (wNewCmdln[i] == ' ') + ++i; + bufferIndex = 0; + slashesAdded = 0; + escapedQuote = FALSE; + continue; + } - if (wNewCmdln[i] == L' ' && !ignorespace) - { - wexpand(wcsndup(wNewCmdln + afterlastspace, i - afterlastspace), doexpand); - i++; - while (wNewCmdln[i] == L' ') - i++; - afterlastspace=i; - doexpand = expand_wildcards; - } - else - { - i++; - } - } + if (wNewCmdln[i] == '\\') + { + buffer[bufferIndex++] = wNewCmdln[i]; + ++slashesAdded; + ++i; + escapedQuote = FALSE; + continue; + } - if (wNewCmdln[afterlastspace] != 0) - { - wexpand(wcsndup(wNewCmdln + afterlastspace, i - afterlastspace), doexpand); + if (wNewCmdln[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 && wNewCmdln[i -1] == '\"' && !escapedQuote) + { + buffer[bufferIndex++] = '\"'; + ++i; + escapedQuote = TRUE; + continue; + } + slashesAdded = 0; + escapedQuote = FALSE; + inQuotes = !inQuotes; + doexpand = inQuotes ? FALSE : expand_wildcards; + ++i; + continue; + } + + buffer[bufferIndex++] = wNewCmdln[i]; + slashesAdded = 0; + escapedQuote = FALSE; + ++i; } - /* Free the temporary buffer. */ + /* Free the temporary buffers. */ + free(buffer); free(wNewCmdln); HeapValidate(GetProcessHeap(), 0, NULL);