a80d815a0ff81fb28df8c2a477484e45580b695b
[reactos.git] / reactos / sdk / lib / crt / misc / getargs.c
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[256];
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[256];
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;
185 size_t len;
186 char* buffer;
187
188 /* missing threading init */
189
190 i = 0;
191 doexpand = expand_wildcards;
192 escapedQuote = FALSE;
193 slashesAdded = 0;
194 inQuotes = 0;
195 bufferIndex = 0;
196
197 if (__argv && _environ)
198 {
199 *argv = __argv;
200 *env = _environ;
201 *argc = __argc;
202 return;
203 }
204
205 __argc = 0;
206
207 len = strlen(_acmdln);
208 buffer = malloc(sizeof(char) * len);
209
210 // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461(v=vs.71).aspx
211 while (TRUE)
212 {
213 // Arguments are delimited by white space, which is either a space or a tab.
214 if (i >= len || ((_acmdln[i] == ' ' || _acmdln[i] == '\t') && !inQuotes))
215 {
216 aexpand(strndup(buffer, bufferIndex), doexpand);
217 // Copy the last element from buffer and quit the loop
218 if (i >= len)
219 {
220 break;
221 }
222
223 while (_acmdln[i] == ' ' || _acmdln[i] == '\t')
224 ++i;
225 bufferIndex = 0;
226 slashesAdded = 0;
227 escapedQuote = FALSE;
228 continue;
229 }
230
231 if (_acmdln[i] == '\\')
232 {
233 buffer[bufferIndex++] = _acmdln[i];
234 ++slashesAdded;
235 ++i;
236 escapedQuote = FALSE;
237 continue;
238 }
239
240 if (_acmdln[i] == '\"')
241 {
242 if (slashesAdded > 0)
243 {
244 if (slashesAdded % 2 == 0)
245 {
246 // If an even number of backslashes is followed by a double quotation mark, then one backslash (\)
247 // is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (")
248 // is interpreted as a string delimiter.
249 bufferIndex -= slashesAdded / 2;
250 }
251 else
252 {
253 // If an odd number of backslashes is followed by a double quotation mark, then one backslash (\)
254 // is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is
255 // interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (")
256 // to be placed in argv.
257 bufferIndex -= slashesAdded / 2 + 1;
258 buffer[bufferIndex++] = '\"';
259 slashesAdded = 0;
260 escapedQuote = TRUE;
261 ++i;
262 continue;
263 }
264 slashesAdded = 0;
265 }
266 else if (!inQuotes && i > 0 && _acmdln[i - 1] == '\"' && !escapedQuote)
267 {
268 buffer[bufferIndex++] = '\"';
269 ++i;
270 escapedQuote = TRUE;
271 continue;
272 }
273 slashesAdded = 0;
274 escapedQuote = FALSE;
275 inQuotes = !inQuotes;
276 doexpand = inQuotes ? FALSE : expand_wildcards;
277 ++i;
278 continue;
279 }
280
281 buffer[bufferIndex++] = _acmdln[i];
282 slashesAdded = 0;
283 escapedQuote = FALSE;
284 ++i;
285 }
286
287 /* Free the temporary buffer. */
288 free(buffer);
289 HeapValidate(GetProcessHeap(), 0, NULL);
290
291 *argc = __argc;
292 if (__argv == NULL)
293 {
294 __argv = (char**)malloc(sizeof(char*));
295 __argv[0] = 0;
296 }
297 *argv = __argv;
298 *env = _environ;
299 _pgmptr = _strdup(__argv[0]);
300
301 // if (new_mode) _set_new_mode(*new_mode);
302 }
303
304 /*
305 * @implemented
306 */
307 void __wgetmainargs(int* argc, wchar_t*** wargv, wchar_t*** wenv,
308 int expand_wildcards, int* new_mode)
309 {
310 int i, doexpand, slashesAdded, escapedQuote, inQuotes, bufferIndex;
311 size_t len;
312 wchar_t* buffer;
313
314 /* missing threading init */
315
316 i = 0;
317 doexpand = expand_wildcards;
318 escapedQuote = FALSE;
319 slashesAdded = 0;
320 inQuotes = 0;
321 bufferIndex = 0;
322
323 if (__wargv && __winitenv)
324 {
325 *wargv = __wargv;
326 *wenv = __winitenv;
327 *argc = __argc;
328 return;
329 }
330
331 __argc = 0;
332
333 len = wcslen(_wcmdln);
334 buffer = malloc(sizeof(wchar_t) * len);
335
336 // Reference: https://msdn.microsoft.com/en-us/library/a1y7w461(v=vs.71).aspx
337 while (TRUE)
338 {
339 // Arguments are delimited by white space, which is either a space or a tab.
340 if (i >= len || ((_wcmdln[i] == ' ' || _wcmdln[i] == '\t') && !inQuotes))
341 {
342 wexpand(wcsndup(buffer, bufferIndex), doexpand);
343 // Copy the last element from buffer and quit the loop
344 if (i >= len)
345 {
346 break;
347 }
348
349 while (_wcmdln[i] == ' ' || _wcmdln[i] == '\t')
350 ++i;
351 bufferIndex = 0;
352 slashesAdded = 0;
353 escapedQuote = FALSE;
354 continue;
355 }
356
357 if (_wcmdln[i] == '\\')
358 {
359 buffer[bufferIndex++] = _wcmdln[i];
360 ++slashesAdded;
361 ++i;
362 escapedQuote = FALSE;
363 continue;
364 }
365
366 if (_wcmdln[i] == '\"')
367 {
368 if (slashesAdded > 0)
369 {
370 if (slashesAdded % 2 == 0)
371 {
372 // If an even number of backslashes is followed by a double quotation mark, then one backslash (\)
373 // is placed in the argv array for every pair of backslashes (\\), and the double quotation mark (")
374 // is interpreted as a string delimiter.
375 bufferIndex -= slashesAdded / 2;
376 }
377 else
378 {
379 // If an odd number of backslashes is followed by a double quotation mark, then one backslash (\)
380 // is placed in the argv array for every pair of backslashes (\\) and the double quotation mark is
381 // interpreted as an escape sequence by the remaining backslash, causing a literal double quotation mark (")
382 // to be placed in argv.
383 bufferIndex -= slashesAdded / 2 + 1;
384 buffer[bufferIndex++] = '\"';
385 slashesAdded = 0;
386 escapedQuote = TRUE;
387 ++i;
388 continue;
389 }
390 slashesAdded = 0;
391 }
392 else if (!inQuotes && i > 0 && _wcmdln[i - 1] == '\"' && !escapedQuote)
393 {
394 buffer[bufferIndex++] = '\"';
395 ++i;
396 escapedQuote = TRUE;
397 continue;
398 }
399 slashesAdded = 0;
400 escapedQuote = FALSE;
401 inQuotes = !inQuotes;
402 doexpand = inQuotes ? FALSE : expand_wildcards;
403 ++i;
404 continue;
405 }
406
407 buffer[bufferIndex++] = _wcmdln[i];
408 slashesAdded = 0;
409 escapedQuote = FALSE;
410 ++i;
411 }
412
413 /* Free the temporary buffer. */
414 free(buffer);
415
416 HeapValidate(GetProcessHeap(), 0, NULL);
417
418 *argc = __argc;
419 if (__wargv == NULL)
420 {
421 __wargv = (wchar_t**)malloc(sizeof(wchar_t*));
422 __wargv[0] = 0;
423 }
424 *wargv = __wargv;
425 *wenv = __winitenv;
426 _wpgmptr = _wcsdup(__wargv[0]);
427
428 // if (new_mode) _set_new_mode(*new_mode);
429 }
430
431 /*
432 * @implemented
433 */
434 int* __p___argc(void)
435 {
436 return &__argc;
437 }
438
439 /*
440 * @implemented
441 */
442 char*** __p___argv(void)
443 {
444 return &__argv;
445 }
446
447 /*
448 * @implemented
449 */
450 wchar_t*** __p___wargv(void)
451 {
452 return &__wargv;
453 }
454
455