1 #include <precomp.h> 2 #include <stdlib.h> 3 #include <string.h> 4 5 6 extern char*_acmdln; 7 extern wchar_t* _wcmdln; 8 #undef _pgmptr 9 extern char*_pgmptr; 10 #undef _wpgmptr 11 extern wchar_t*_wpgmptr; 12 #undef _environ 13 extern char**_environ; 14 15 #undef __argv 16 #undef __argc 17 18 char**__argv = NULL; 19 #undef __wargv 20 wchar_t**__wargv = NULL; 21 int __argc = 0; 22 23 extern wchar_t **__winitenv; 24 25 char* strndup(char const* name, size_t len) 26 { 27 char *s = malloc(len + 1); 28 if (s != NULL) 29 { 30 memcpy(s, name, len); 31 s[len] = 0; 32 } 33 return s; 34 } 35 36 wchar_t* wcsndup(wchar_t* name, size_t len) 37 { 38 wchar_t *s = malloc((len + 1) * sizeof(wchar_t)); 39 if (s != NULL) 40 { 41 memcpy(s, name, len*sizeof(wchar_t)); 42 s[len] = 0; 43 } 44 return s; 45 } 46 47 #define SIZE (4096 / sizeof(char*)) 48 49 int wadd(wchar_t* name) 50 { 51 wchar_t** _new; 52 if ((__argc % SIZE) == 0) 53 { 54 if (__wargv == NULL) 55 _new = malloc(sizeof(wchar_t*) * (1 + SIZE)); 56 else 57 _new = realloc(__wargv, sizeof(wchar_t*) * (__argc + 1 + SIZE)); 58 if (_new == NULL) 59 return -1; 60 __wargv = _new; 61 } 62 __wargv[__argc++] = name; 63 __wargv[__argc] = NULL; 64 return 0; 65 } 66 67 int wexpand(wchar_t* name, int expand_wildcards) 68 { 69 wchar_t* s; 70 WIN32_FIND_DATAW fd; 71 HANDLE hFile; 72 BOOLEAN first = TRUE; 73 wchar_t buffer[MAX_PATH]; 74 uintptr_t pos; 75 76 if (expand_wildcards && (s = wcspbrk(name, L"*?"))) 77 { 78 hFile = FindFirstFileW(name, &fd); 79 if (hFile != INVALID_HANDLE_VALUE) 80 { 81 while(s != name && *s != L'/' && *s != L'\\') 82 s--; 83 pos = s - name; 84 if (*s == L'/' || *s == L'\\') 85 pos++; 86 wcsncpy(buffer, name, pos); 87 do 88 { 89 if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 90 { 91 wcscpy(&buffer[pos], fd.cFileName); 92 if (wadd(_wcsdup(buffer)) < 0) 93 { 94 FindClose(hFile); 95 return -1; 96 } 97 first = FALSE; 98 } 99 } 100 while(FindNextFileW(hFile, &fd)); 101 FindClose(hFile); 102 } 103 } 104 if (first) 105 { 106 if (wadd(name) < 0) 107 return -1; 108 } 109 else 110 free(name); 111 return 0; 112 } 113 114 int aadd(char* name) 115 { 116 char** _new; 117 if ((__argc % SIZE) == 0) 118 { 119 if (__argv == NULL) 120 _new = malloc(sizeof(char*) * (1 + SIZE)); 121 else 122 _new = realloc(__argv, sizeof(char*) * (__argc + 1 + SIZE)); 123 if (_new == NULL) 124 return -1; 125 __argv = _new; 126 } 127 __argv[__argc++] = name; 128 __argv[__argc] = NULL; 129 return 0; 130 } 131 132 int aexpand(char* name, int expand_wildcards) 133 { 134 char* s; 135 WIN32_FIND_DATAA fd; 136 HANDLE hFile; 137 BOOLEAN first = TRUE; 138 char buffer[MAX_PATH]; 139 uintptr_t pos; 140 141 if (expand_wildcards && (s = strpbrk(name, "*?"))) 142 { 143 hFile = FindFirstFileA(name, &fd); 144 if (hFile != INVALID_HANDLE_VALUE) 145 { 146 while(s != name && *s != '/' && *s != '\\') 147 s--; 148 pos = s - name; 149 if (*s == '/' || *s == '\\') 150 pos++; 151 strncpy(buffer, name, pos); 152 do 153 { 154 if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) 155 { 156 strcpy(&buffer[pos], fd.cFileName); 157 if (aadd(_strdup(buffer)) < 0) 158 { 159 FindClose(hFile); 160 return -1; 161 } 162 first = FALSE; 163 } 164 } 165 while(FindNextFileA(hFile, &fd)); 166 FindClose(hFile); 167 } 168 } 169 if (first) 170 { 171 if (aadd(name) < 0) 172 return -1; 173 } 174 else 175 free(name); 176 return 0; 177 } 178 179 /* 180 * @implemented 181 */ 182 void __getmainargs(int* argc, char*** argv, char*** env, int expand_wildcards, int* new_mode) 183 { 184 int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex, anyLetter; 185 size_t len; 186 char* buffer; 187 188 /* missing threading init */ 189 190 i = 0; 191 doexpand = expand_wildcards; 192 escapedQuote = FALSE; 193 anyLetter = FALSE; 194 slashesAdded = 0; 195 inQuotes = 0; 196 bufferIndex = 0; 197 198 if (__argv && _environ) 199 { 200 *argv = __argv; 201 *env = _environ; 202 *argc = __argc; 203 return; 204 } 205 206 __argc = 0; 207 208 len = strlen(_acmdln); 209 buffer = malloc(sizeof(char) * len); 210 211 // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461(v=vs.71).aspx 212 while (TRUE) 213 { 214 // Arguments are delimited by white space, which is either a space or a tab. 215 if (i >= len || ((_acmdln[i] == ' ' || _acmdln[i] == '\t') && !inQuotes)) 216 { 217 // Handle the case when empty spaces are in the end of the cmdline 218 if (anyLetter) 219 { 220 aexpand(strndup(buffer, bufferIndex), doexpand); 221 } 222 // Copy the last element from buffer and quit the loop 223 if (i >= len) 224 { 225 break; 226 } 227 228 while (_acmdln[i] == ' ' || _acmdln[i] == '\t') 229 ++i; 230 anyLetter = FALSE; 231 bufferIndex = 0; 232 slashesAdded = 0; 233 escapedQuote = FALSE; 234 continue; 235 } 236 237 anyLetter = TRUE; 238 239 if (_acmdln[i] == '\\') 240 { 241 buffer[bufferIndex++] = _acmdln[i]; 242 ++slashesAdded; 243 ++i; 244 escapedQuote = FALSE; 245 continue; 246 } 247 248 if (_acmdln[i] == '\"') 249 { 250 if (slashesAdded > 0) 251 { 252 if (slashesAdded % 2 == 0) 253 { 254 // If an even number of backslashes is followed by a double quotation mark, then one backslash (\) 255 // is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (") 256 // is interpreted as a string delimiter. 257 bufferIndex -= slashesAdded / 2; 258 } 259 else 260 { 261 // If an odd number of backslashes is followed by a double quotation mark, then one backslash (\) 262 // is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is 263 // interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (") 264 // to be placed in argv. 265 bufferIndex -= slashesAdded / 2 + 1; 266 buffer[bufferIndex++] = '\"'; 267 slashesAdded = 0; 268 escapedQuote = TRUE; 269 ++i; 270 continue; 271 } 272 slashesAdded = 0; 273 } 274 else if (!inQuotes && i > 0 && _acmdln[i - 1] == '\"' && !escapedQuote) 275 { 276 buffer[bufferIndex++] = '\"'; 277 ++i; 278 escapedQuote = TRUE; 279 continue; 280 } 281 slashesAdded = 0; 282 escapedQuote = FALSE; 283 inQuotes = !inQuotes; 284 doexpand = inQuotes ? FALSE : expand_wildcards; 285 ++i; 286 continue; 287 } 288 289 buffer[bufferIndex++] = _acmdln[i]; 290 slashesAdded = 0; 291 escapedQuote = FALSE; 292 ++i; 293 } 294 295 /* Free the temporary buffer. */ 296 free(buffer); 297 HeapValidate(GetProcessHeap(), 0, NULL); 298 299 *argc = __argc; 300 if (__argv == NULL) 301 { 302 __argv = (char**)malloc(sizeof(char*)); 303 __argv[0] = 0; 304 } 305 *argv = __argv; 306 *env = _environ; 307 _pgmptr = _strdup(__argv[0]); 308 309 // if (new_mode) _set_new_mode(*new_mode); 310 } 311 312 /* 313 * @implemented 314 */ 315 void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv, 316 int expand_wildcards, int* new_mode) 317 { 318 int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex, anyLetter; 319 size_t len; 320 wchar_t* buffer; 321 322 /* missing threading init */ 323 324 i = 0; 325 doexpand = expand_wildcards; 326 escapedQuote = FALSE; 327 anyLetter = TRUE; 328 slashesAdded = 0; 329 inQuotes = 0; 330 bufferIndex = 0; 331 332 if (__wargv && __winitenv) 333 { 334 *wargv = __wargv; 335 *wenv = __winitenv; 336 *argc = __argc; 337 return; 338 } 339 340 __argc = 0; 341 342 len = wcslen(_wcmdln); 343 buffer = malloc(sizeof(wchar_t) * len); 344 345 // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461(v=vs.71).aspx 346 while (TRUE) 347 { 348 // Arguments are delimited by white space, which is either a space or a tab. 349 if (i >= len || ((_wcmdln[i] == ' ' || _wcmdln[i] == '\t') && !inQuotes)) 350 { 351 // Handle the case when empty spaces are in the end of the cmdline 352 if (anyLetter) 353 { 354 wexpand(wcsndup(buffer, bufferIndex), doexpand); 355 } 356 // Copy the last element from buffer and quit the loop 357 if (i >= len) 358 { 359 break; 360 } 361 362 while (_wcmdln[i] == ' ' || _wcmdln[i] == '\t') 363 ++i; 364 anyLetter = FALSE; 365 bufferIndex = 0; 366 slashesAdded = 0; 367 escapedQuote = FALSE; 368 continue; 369 } 370 371 anyLetter = TRUE; 372 373 if (_wcmdln[i] == '\\') 374 { 375 buffer[bufferIndex++] = _wcmdln[i]; 376 ++slashesAdded; 377 ++i; 378 escapedQuote = FALSE; 379 continue; 380 } 381 382 if (_wcmdln[i] == '\"') 383 { 384 if (slashesAdded > 0) 385 { 386 if (slashesAdded % 2 == 0) 387 { 388 // If an even number of backslashes is followed by a double quotation mark, then one backslash (\) 389 // is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (") 390 // is interpreted as a string delimiter. 391 bufferIndex -= slashesAdded / 2; 392 } 393 else 394 { 395 // If an odd number of backslashes is followed by a double quotation mark, then one backslash (\) 396 // is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is 397 // interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (") 398 // to be placed in argv. 399 bufferIndex -= slashesAdded / 2 + 1; 400 buffer[bufferIndex++] = '\"'; 401 slashesAdded = 0; 402 escapedQuote = TRUE; 403 ++i; 404 continue; 405 } 406 slashesAdded = 0; 407 } 408 else if (!inQuotes && i > 0 && _wcmdln[i - 1] == '\"' && !escapedQuote) 409 { 410 buffer[bufferIndex++] = '\"'; 411 ++i; 412 escapedQuote = TRUE; 413 continue; 414 } 415 slashesAdded = 0; 416 escapedQuote = FALSE; 417 inQuotes = !inQuotes; 418 doexpand = inQuotes ? FALSE : expand_wildcards; 419 ++i; 420 continue; 421 } 422 423 buffer[bufferIndex++] = _wcmdln[i]; 424 slashesAdded = 0; 425 escapedQuote = FALSE; 426 ++i; 427 } 428 429 /* Free the temporary buffer. */ 430 free(buffer); 431 432 HeapValidate(GetProcessHeap(), 0, NULL); 433 434 *argc = __argc; 435 if (__wargv == NULL) 436 { 437 __wargv = (wchar_t**)malloc(sizeof(wchar_t*)); 438 __wargv[0] = 0; 439 } 440 *wargv = __wargv; 441 *wenv = __winitenv; 442 _wpgmptr = _wcsdup(__wargv[0]); 443 444 // if (new_mode) _set_new_mode(*new_mode); 445 } 446 447 /* 448 * @implemented 449 */ 450 int* __p___argc(void) 451 { 452 return &__argc; 453 } 454 455 /* 456 * @implemented 457 */ 458 char*** __p___argv(void) 459 { 460 return &__argv; 461 } 462 463 /* 464 * @implemented 465 */ 466 wchar_t*** __p___wargv(void) 467 { 468 return &__wargv; 469 } 470 471 472