#include #include #include extern char*_acmdln; extern wchar_t* _wcmdln; #undef _pgmptr extern char*_pgmptr; #undef _wpgmptr extern wchar_t*_wpgmptr; #undef _environ extern char**_environ; #undef __argv #undef __argc char**__argv = NULL; #undef __wargv wchar_t**__wargv = NULL; int __argc = 0; extern wchar_t **__winitenv; char* strndup(char const* name, size_t len) { char *s = malloc(len + 1); if (s != NULL) { memcpy(s, name, len); s[len] = 0; } return s; } wchar_t* wcsndup(wchar_t* name, size_t len) { wchar_t *s = malloc((len + 1) * sizeof(wchar_t)); if (s != NULL) { memcpy(s, name, len*sizeof(wchar_t)); s[len] = 0; } return s; } #define SIZE (4096 / sizeof(char*)) int wadd(wchar_t* name) { wchar_t** _new; if ((__argc % SIZE) == 0) { if (__wargv == NULL) _new = malloc(sizeof(wchar_t*) * (1 + SIZE)); else _new = realloc(__wargv, sizeof(wchar_t*) * (__argc + 1 + SIZE)); if (_new == NULL) return -1; __wargv = _new; } __wargv[__argc++] = name; __wargv[__argc] = NULL; return 0; } int wexpand(wchar_t* name, int expand_wildcards) { wchar_t* s; WIN32_FIND_DATAW fd; HANDLE hFile; BOOLEAN first = TRUE; wchar_t buffer[MAX_PATH]; uintptr_t pos; if (expand_wildcards && (s = wcspbrk(name, L"*?"))) { hFile = FindFirstFileW(name, &fd); if (hFile != INVALID_HANDLE_VALUE) { while(s != name && *s != L'/' && *s != L'\\') s--; pos = s - name; if (*s == L'/' || *s == L'\\') pos++; wcsncpy(buffer, name, pos); do { if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { wcscpy(&buffer[pos], fd.cFileName); if (wadd(_wcsdup(buffer)) < 0) { FindClose(hFile); return -1; } first = FALSE; } } while(FindNextFileW(hFile, &fd)); FindClose(hFile); } } if (first) { if (wadd(name) < 0) return -1; } else free(name); return 0; } int aadd(char* name) { char** _new; if ((__argc % SIZE) == 0) { if (__argv == NULL) _new = malloc(sizeof(char*) * (1 + SIZE)); else _new = realloc(__argv, sizeof(char*) * (__argc + 1 + SIZE)); if (_new == NULL) return -1; __argv = _new; } __argv[__argc++] = name; __argv[__argc] = NULL; return 0; } int aexpand(char* name, int expand_wildcards) { char* s; WIN32_FIND_DATAA fd; HANDLE hFile; BOOLEAN first = TRUE; char buffer[MAX_PATH]; uintptr_t pos; if (expand_wildcards && (s = strpbrk(name, "*?"))) { hFile = FindFirstFileA(name, &fd); if (hFile != INVALID_HANDLE_VALUE) { while(s != name && *s != '/' && *s != '\\') s--; pos = s - name; if (*s == '/' || *s == '\\') pos++; strncpy(buffer, name, pos); do { if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { strcpy(&buffer[pos], fd.cFileName); if (aadd(_strdup(buffer)) < 0) { FindClose(hFile); return -1; } first = FALSE; } } while(FindNextFileA(hFile, &fd)); FindClose(hFile); } } if (first) { if (aadd(name) < 0) return -1; } else free(name); return 0; } /* * @implemented */ void __getmainargs(int* argc, char*** argv, char*** env, int expand_wildcards, int* new_mode) { int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex, anyLetter; size_t len; char* buffer; /* missing threading init */ i = 0; doexpand = expand_wildcards; escapedQuote = FALSE; anyLetter = FALSE; slashesAdded = 0; inQuotes = 0; bufferIndex = 0; if (__argv && _environ) { *argv = __argv; *env = _environ; *argc = __argc; return; } __argc = 0; len = strlen(_acmdln); buffer = malloc(sizeof(char) * len); // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461.aspx while (TRUE) { // Arguments are delimited by white space, which is either a space or a tab. if (i >= len || ((_acmdln[i] == ' ' || _acmdln[i] == '\t') && !inQuotes)) { // Handle the case when empty spaces are in the end of the cmdline if (anyLetter) { aexpand(strndup(buffer, bufferIndex), doexpand); } // Copy the last element from buffer and quit the loop if (i >= len) { break; } while (_acmdln[i] == ' ' || _acmdln[i] == '\t') ++i; anyLetter = FALSE; bufferIndex = 0; slashesAdded = 0; escapedQuote = FALSE; continue; } anyLetter = TRUE; if (_acmdln[i] == '\\') { buffer[bufferIndex++] = _acmdln[i]; ++slashesAdded; ++i; escapedQuote = FALSE; continue; } 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(buffer); *argc = __argc; if (__argv == NULL) { __argv = (char**)malloc(sizeof(char*)); __argv[0] = 0; } *argv = __argv; *env = _environ; _pgmptr = malloc(MAX_PATH * sizeof(char)); if (_pgmptr) { if (!GetModuleFileNameA(NULL, _pgmptr, MAX_PATH)) _pgmptr[0] = '\0'; else _pgmptr[MAX_PATH - 1] = '\0'; } else { _pgmptr = _strdup(__argv[0]); } HeapValidate(GetProcessHeap(), 0, NULL); // if (new_mode) _set_new_mode(*new_mode); } /* * @implemented */ void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv, int expand_wildcards, int* new_mode) { int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex, anyLetter; size_t len; wchar_t* buffer; /* missing threading init */ i = 0; doexpand = expand_wildcards; escapedQuote = FALSE; anyLetter = TRUE; slashesAdded = 0; inQuotes = 0; bufferIndex = 0; if (__wargv && __winitenv) { *wargv = __wargv; *wenv = __winitenv; *argc = __argc; return; } __argc = 0; len = wcslen(_wcmdln); buffer = malloc(sizeof(wchar_t) * len); // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461.aspx while (TRUE) { // Arguments are delimited by white space, which is either a space or a tab. if (i >= len || ((_wcmdln[i] == ' ' || _wcmdln[i] == '\t') && !inQuotes)) { // Handle the case when empty spaces are in the end of the cmdline if (anyLetter) { wexpand(wcsndup(buffer, bufferIndex), doexpand); } // Copy the last element from buffer and quit the loop if (i >= len) { break; } while (_wcmdln[i] == ' ' || _wcmdln[i] == '\t') ++i; anyLetter = FALSE; bufferIndex = 0; slashesAdded = 0; escapedQuote = FALSE; continue; } anyLetter = TRUE; if (_wcmdln[i] == '\\') { buffer[bufferIndex++] = _wcmdln[i]; ++slashesAdded; ++i; escapedQuote = FALSE; continue; } 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(buffer); *argc = __argc; if (__wargv == NULL) { __wargv = (wchar_t**)malloc(sizeof(wchar_t*)); __wargv[0] = 0; } *wargv = __wargv; *wenv = __winitenv; _wpgmptr = malloc(MAX_PATH * sizeof(wchar_t)); if (_wpgmptr) { if (!GetModuleFileNameW(NULL, _wpgmptr, MAX_PATH)) _wpgmptr[0] = '\0'; else _wpgmptr[MAX_PATH - 1] = '\0'; } else { _wpgmptr = _wcsdup(__wargv[0]); } HeapValidate(GetProcessHeap(), 0, NULL); // if (new_mode) _set_new_mode(*new_mode); } /* * @implemented */ int* __p___argc(void) { return &__argc; } /* * @implemented */ char*** __p___argv(void) { return &__argv; } /* * @implemented */ wchar_t*** __p___wargv(void) { return &__wargv; }