[CRT] Use MAX_PATH for buffer meant to contain an arbitrary path
[reactos.git] / 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[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