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