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.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 298 *argc = __argc; 299 if (__argv == NULL) 300 { 301 __argv = (char**)malloc(sizeof(char*)); 302 __argv[0] = 0; 303 } 304 *argv = __argv; 305 *env = _environ; 306 307 _pgmptr = malloc(MAX_PATH * sizeof(char)); 308 if (_pgmptr) 309 { 310 if (!GetModuleFileNameA(NULL, _pgmptr, MAX_PATH)) 311 _pgmptr[0] = '\0'; 312 else 313 _pgmptr[MAX_PATH - 1] = '\0'; 314 } 315 else 316 { 317 _pgmptr = _strdup(__argv[0]); 318 } 319 320 HeapValidate(GetProcessHeap(), 0, NULL); 321 322 // if (new_mode) _set_new_mode(*new_mode); 323 } 324 325 /* 326 * @implemented 327 */ 328 void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv, 329 int expand_wildcards, int* new_mode) 330 { 331 int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex, anyLetter; 332 size_t len; 333 wchar_t* buffer; 334 335 /* missing threading init */ 336 337 i = 0; 338 doexpand = expand_wildcards; 339 escapedQuote = FALSE; 340 anyLetter = TRUE; 341 slashesAdded = 0; 342 inQuotes = 0; 343 bufferIndex = 0; 344 345 if (__wargv && __winitenv) 346 { 347 *wargv = __wargv; 348 *wenv = __winitenv; 349 *argc = __argc; 350 return; 351 } 352 353 __argc = 0; 354 355 len = wcslen(_wcmdln); 356 buffer = malloc(sizeof(wchar_t) * len); 357 358 // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461.aspx 359 while (TRUE) 360 { 361 // Arguments are delimited by white space, which is either a space or a tab. 362 if (i >= len || ((_wcmdln[i] == ' ' || _wcmdln[i] == '\t') && !inQuotes)) 363 { 364 // Handle the case when empty spaces are in the end of the cmdline 365 if (anyLetter) 366 { 367 wexpand(wcsndup(buffer, bufferIndex), doexpand); 368 } 369 // Copy the last element from buffer and quit the loop 370 if (i >= len) 371 { 372 break; 373 } 374 375 while (_wcmdln[i] == ' ' || _wcmdln[i] == '\t') 376 ++i; 377 anyLetter = FALSE; 378 bufferIndex = 0; 379 slashesAdded = 0; 380 escapedQuote = FALSE; 381 continue; 382 } 383 384 anyLetter = TRUE; 385 386 if (_wcmdln[i] == '\\') 387 { 388 buffer[bufferIndex++] = _wcmdln[i]; 389 ++slashesAdded; 390 ++i; 391 escapedQuote = FALSE; 392 continue; 393 } 394 395 if (_wcmdln[i] == '\"') 396 { 397 if (slashesAdded > 0) 398 { 399 if (slashesAdded % 2 == 0) 400 { 401 // If an even number of backslashes is followed by a double quotation mark, then one backslash (\) 402 // is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (") 403 // is interpreted as a string delimiter. 404 bufferIndex -= slashesAdded / 2; 405 } 406 else 407 { 408 // If an odd number of backslashes is followed by a double quotation mark, then one backslash (\) 409 // is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is 410 // interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (") 411 // to be placed in argv. 412 bufferIndex -= slashesAdded / 2 + 1; 413 buffer[bufferIndex++] = '\"'; 414 slashesAdded = 0; 415 escapedQuote = TRUE; 416 ++i; 417 continue; 418 } 419 slashesAdded = 0; 420 } 421 else if (!inQuotes && i > 0 && _wcmdln[i - 1] == '\"' && !escapedQuote) 422 { 423 buffer[bufferIndex++] = '\"'; 424 ++i; 425 escapedQuote = TRUE; 426 continue; 427 } 428 slashesAdded = 0; 429 escapedQuote = FALSE; 430 inQuotes = !inQuotes; 431 doexpand = inQuotes ? FALSE : expand_wildcards; 432 ++i; 433 continue; 434 } 435 436 buffer[bufferIndex++] = _wcmdln[i]; 437 slashesAdded = 0; 438 escapedQuote = FALSE; 439 ++i; 440 } 441 442 /* Free the temporary buffer. */ 443 free(buffer); 444 445 *argc = __argc; 446 if (__wargv == NULL) 447 { 448 __wargv = (wchar_t**)malloc(sizeof(wchar_t*)); 449 __wargv[0] = 0; 450 } 451 *wargv = __wargv; 452 *wenv = __winitenv; 453 454 _wpgmptr = malloc(MAX_PATH * sizeof(wchar_t)); 455 if (_wpgmptr) 456 { 457 if (!GetModuleFileNameW(NULL, _wpgmptr, MAX_PATH)) 458 _wpgmptr[0] = '\0'; 459 else 460 _wpgmptr[MAX_PATH - 1] = '\0'; 461 } 462 else 463 { 464 _wpgmptr = _wcsdup(__wargv[0]); 465 } 466 467 HeapValidate(GetProcessHeap(), 0, NULL); 468 469 // if (new_mode) _set_new_mode(*new_mode); 470 } 471 472 /* 473 * @implemented 474 */ 475 int* __p___argc(void) 476 { 477 return &__argc; 478 } 479 480 /* 481 * @implemented 482 */ 483 char*** __p___argv(void) 484 { 485 return &__argv; 486 } 487 488 /* 489 * @implemented 490 */ 491 wchar_t*** __p___wargv(void) 492 { 493 return &__wargv; 494 } 495 496 497