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
strndup(char const * name,size_t len)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
wcsndup(wchar_t * name,size_t len)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
wadd(wchar_t * name)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
wexpand(wchar_t * name,int expand_wildcards)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
aadd(char * name)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
aexpand(char * name,int expand_wildcards)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 */
__getmainargs(int * argc,char *** argv,char *** env,int expand_wildcards,int * new_mode)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 */
__wgetmainargs(int * argc,wchar_t *** wargv,wchar_t *** wenv,int expand_wildcards,int * new_mode)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 */
__p___argc(void)475 int* __p___argc(void)
476 {
477 return &__argc;
478 }
479
480 /*
481 * @implemented
482 */
__p___argv(void)483 char*** __p___argv(void)
484 {
485 return &__argv;
486 }
487
488 /*
489 * @implemented
490 */
__p___wargv(void)491 wchar_t*** __p___wargv(void)
492 {
493 return &__wargv;
494 }
495
496
497