xref: /reactos/sdk/lib/crt/misc/getargs.c (revision 34593d93)
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