Mercurial > hg > CbC > CbC_gcc
annotate libiberty/argv.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
rev | line source |
---|---|
0 | 1 /* Create and destroy argument vectors (argv's) |
111 | 2 Copyright (C) 1992-2017 Free Software Foundation, Inc. |
0 | 3 Written by Fred Fish @ Cygnus Support |
4 | |
5 This file is part of the libiberty library. | |
6 Libiberty is free software; you can redistribute it and/or | |
7 modify it under the terms of the GNU Library General Public | |
8 License as published by the Free Software Foundation; either | |
9 version 2 of the License, or (at your option) any later version. | |
10 | |
11 Libiberty is distributed in the hope that it will be useful, | |
12 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 Library General Public License for more details. | |
15 | |
16 You should have received a copy of the GNU Library General Public | |
17 License along with libiberty; see the file COPYING.LIB. If | |
18 not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, | |
19 Boston, MA 02110-1301, USA. */ | |
20 | |
21 | |
22 /* Create and destroy argument vectors. An argument vector is simply an | |
23 array of string pointers, terminated by a NULL pointer. */ | |
24 | |
25 #ifdef HAVE_CONFIG_H | |
26 #include "config.h" | |
27 #endif | |
28 #include "ansidecl.h" | |
29 #include "libiberty.h" | |
30 #include "safe-ctype.h" | |
31 | |
32 /* Routines imported from standard C runtime libraries. */ | |
33 | |
34 #include <stddef.h> | |
35 #include <string.h> | |
36 #include <stdlib.h> | |
37 #include <stdio.h> | |
111 | 38 #include <sys/types.h> |
39 #ifdef HAVE_UNISTD_H | |
40 #include <unistd.h> | |
41 #endif | |
42 #if HAVE_SYS_STAT_H | |
43 #include <sys/stat.h> | |
44 #endif | |
0 | 45 |
46 #ifndef NULL | |
47 #define NULL 0 | |
48 #endif | |
49 | |
50 #ifndef EOS | |
51 #define EOS '\0' | |
52 #endif | |
53 | |
54 #define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ | |
55 | |
56 | |
57 /* | |
58 | |
111 | 59 @deftypefn Extension char** dupargv (char * const *@var{vector}) |
0 | 60 |
61 Duplicate an argument vector. Simply scans through @var{vector}, | |
62 duplicating each argument until the terminating @code{NULL} is found. | |
63 Returns a pointer to the argument vector if successful. Returns | |
64 @code{NULL} if there is insufficient memory to complete building the | |
65 argument vector. | |
66 | |
67 @end deftypefn | |
68 | |
69 */ | |
70 | |
71 char ** | |
111 | 72 dupargv (char * const *argv) |
0 | 73 { |
74 int argc; | |
75 char **copy; | |
76 | |
77 if (argv == NULL) | |
78 return NULL; | |
79 | |
80 /* the vector */ | |
81 for (argc = 0; argv[argc] != NULL; argc++); | |
111 | 82 copy = (char **) xmalloc ((argc + 1) * sizeof (char *)); |
83 | |
0 | 84 /* the strings */ |
85 for (argc = 0; argv[argc] != NULL; argc++) | |
111 | 86 copy[argc] = xstrdup (argv[argc]); |
0 | 87 copy[argc] = NULL; |
88 return copy; | |
89 } | |
90 | |
91 /* | |
92 | |
93 @deftypefn Extension void freeargv (char **@var{vector}) | |
94 | |
95 Free an argument vector that was built using @code{buildargv}. Simply | |
96 scans through @var{vector}, freeing the memory for each argument until | |
97 the terminating @code{NULL} is found, and then frees @var{vector} | |
98 itself. | |
99 | |
100 @end deftypefn | |
101 | |
102 */ | |
103 | |
104 void freeargv (char **vector) | |
105 { | |
106 register char **scan; | |
107 | |
108 if (vector != NULL) | |
109 { | |
110 for (scan = vector; *scan != NULL; scan++) | |
111 { | |
112 free (*scan); | |
113 } | |
114 free (vector); | |
115 } | |
116 } | |
117 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
118 static void |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
119 consume_whitespace (const char **input) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
120 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
121 while (ISSPACE (**input)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
122 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
123 (*input)++; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
124 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
125 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
126 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
127 static int |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
128 only_whitespace (const char* input) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
129 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
130 while (*input != EOS && ISSPACE (*input)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
131 input++; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
132 |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
133 return (*input == EOS); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
134 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
135 |
0 | 136 /* |
137 | |
138 @deftypefn Extension char** buildargv (char *@var{sp}) | |
139 | |
140 Given a pointer to a string, parse the string extracting fields | |
141 separated by whitespace and optionally enclosed within either single | |
142 or double quotes (which are stripped off), and build a vector of | |
143 pointers to copies of the string for each field. The input string | |
144 remains unchanged. The last element of the vector is followed by a | |
145 @code{NULL} element. | |
146 | |
147 All of the memory for the pointer array and copies of the string | |
111 | 148 is obtained from @code{xmalloc}. All of the memory can be returned to the |
0 | 149 system with the single function call @code{freeargv}, which takes the |
150 returned result of @code{buildargv}, as it's argument. | |
151 | |
152 Returns a pointer to the argument vector if successful. Returns | |
153 @code{NULL} if @var{sp} is @code{NULL} or if there is insufficient | |
154 memory to complete building the argument vector. | |
155 | |
156 If the input is a null string (as opposed to a @code{NULL} pointer), | |
157 then buildarg returns an argument vector that has one arg, a null | |
158 string. | |
159 | |
160 @end deftypefn | |
161 | |
162 The memory for the argv array is dynamically expanded as necessary. | |
163 | |
164 In order to provide a working buffer for extracting arguments into, | |
165 with appropriate stripping of quotes and translation of backslash | |
166 sequences, we allocate a working buffer at least as long as the input | |
167 string. This ensures that we always have enough space in which to | |
168 work, since the extracted arg is never larger than the input string. | |
169 | |
170 The argument vector is always kept terminated with a @code{NULL} arg | |
171 pointer, so it can be passed to @code{freeargv} at any time, or | |
172 returned, as appropriate. | |
173 | |
174 */ | |
175 | |
176 char **buildargv (const char *input) | |
177 { | |
178 char *arg; | |
179 char *copybuf; | |
180 int squote = 0; | |
181 int dquote = 0; | |
182 int bsquote = 0; | |
183 int argc = 0; | |
184 int maxargc = 0; | |
185 char **argv = NULL; | |
186 char **nargv; | |
187 | |
188 if (input != NULL) | |
189 { | |
111 | 190 copybuf = (char *) xmalloc (strlen (input) + 1); |
0 | 191 /* Is a do{}while to always execute the loop once. Always return an |
192 argv, even for null strings. See NOTES above, test case below. */ | |
193 do | |
194 { | |
195 /* Pick off argv[argc] */ | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
196 consume_whitespace (&input); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
197 |
0 | 198 if ((maxargc == 0) || (argc >= (maxargc - 1))) |
199 { | |
200 /* argv needs initialization, or expansion */ | |
201 if (argv == NULL) | |
202 { | |
203 maxargc = INITIAL_MAXARGC; | |
111 | 204 nargv = (char **) xmalloc (maxargc * sizeof (char *)); |
0 | 205 } |
206 else | |
207 { | |
208 maxargc *= 2; | |
111 | 209 nargv = (char **) xrealloc (argv, maxargc * sizeof (char *)); |
0 | 210 } |
211 argv = nargv; | |
212 argv[argc] = NULL; | |
213 } | |
214 /* Begin scanning arg */ | |
215 arg = copybuf; | |
216 while (*input != EOS) | |
217 { | |
218 if (ISSPACE (*input) && !squote && !dquote && !bsquote) | |
219 { | |
220 break; | |
221 } | |
222 else | |
223 { | |
224 if (bsquote) | |
225 { | |
226 bsquote = 0; | |
227 *arg++ = *input; | |
228 } | |
229 else if (*input == '\\') | |
230 { | |
231 bsquote = 1; | |
232 } | |
233 else if (squote) | |
234 { | |
235 if (*input == '\'') | |
236 { | |
237 squote = 0; | |
238 } | |
239 else | |
240 { | |
241 *arg++ = *input; | |
242 } | |
243 } | |
244 else if (dquote) | |
245 { | |
246 if (*input == '"') | |
247 { | |
248 dquote = 0; | |
249 } | |
250 else | |
251 { | |
252 *arg++ = *input; | |
253 } | |
254 } | |
255 else | |
256 { | |
257 if (*input == '\'') | |
258 { | |
259 squote = 1; | |
260 } | |
261 else if (*input == '"') | |
262 { | |
263 dquote = 1; | |
264 } | |
265 else | |
266 { | |
267 *arg++ = *input; | |
268 } | |
269 } | |
270 input++; | |
271 } | |
272 } | |
273 *arg = EOS; | |
111 | 274 argv[argc] = xstrdup (copybuf); |
0 | 275 argc++; |
276 argv[argc] = NULL; | |
277 | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
278 consume_whitespace (&input); |
0 | 279 } |
280 while (*input != EOS); | |
111 | 281 |
282 free (copybuf); | |
0 | 283 } |
284 return (argv); | |
285 } | |
286 | |
287 /* | |
288 | |
111 | 289 @deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file}) |
0 | 290 |
291 Write each member of ARGV, handling all necessary quoting, to the file | |
292 named by FILE, separated by whitespace. Return 0 on success, non-zero | |
293 if an error occurred while writing to FILE. | |
294 | |
295 @end deftypefn | |
296 | |
297 */ | |
298 | |
299 int | |
111 | 300 writeargv (char * const *argv, FILE *f) |
0 | 301 { |
302 int status = 0; | |
303 | |
304 if (f == NULL) | |
305 return 1; | |
306 | |
307 while (*argv != NULL) | |
308 { | |
309 const char *arg = *argv; | |
310 | |
311 while (*arg != EOS) | |
312 { | |
313 char c = *arg; | |
314 | |
315 if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') | |
316 if (EOF == fputc ('\\', f)) | |
317 { | |
318 status = 1; | |
319 goto done; | |
320 } | |
321 | |
322 if (EOF == fputc (c, f)) | |
323 { | |
324 status = 1; | |
325 goto done; | |
326 } | |
327 arg++; | |
328 } | |
329 | |
330 if (EOF == fputc ('\n', f)) | |
331 { | |
332 status = 1; | |
333 goto done; | |
334 } | |
335 argv++; | |
336 } | |
337 | |
338 done: | |
339 return status; | |
340 } | |
341 | |
342 /* | |
343 | |
344 @deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) | |
345 | |
346 The @var{argcp} and @code{argvp} arguments are pointers to the usual | |
347 @code{argc} and @code{argv} arguments to @code{main}. This function | |
348 looks for arguments that begin with the character @samp{@@}. Any such | |
349 arguments are interpreted as ``response files''. The contents of the | |
350 response file are interpreted as additional command line options. In | |
351 particular, the file is separated into whitespace-separated strings; | |
352 each such string is taken as a command-line option. The new options | |
353 are inserted in place of the option naming the response file, and | |
354 @code{*argcp} and @code{*argvp} will be updated. If the value of | |
355 @code{*argvp} is modified by this function, then the new value has | |
356 been dynamically allocated and can be deallocated by the caller with | |
357 @code{freeargv}. However, most callers will simply call | |
358 @code{expandargv} near the beginning of @code{main} and allow the | |
359 operating system to free the memory when the program exits. | |
360 | |
361 @end deftypefn | |
362 | |
363 */ | |
364 | |
365 void | |
366 expandargv (int *argcp, char ***argvp) | |
367 { | |
368 /* The argument we are currently processing. */ | |
369 int i = 0; | |
370 /* Non-zero if ***argvp has been dynamically allocated. */ | |
371 int argv_dynamic = 0; | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
372 /* Limit the number of response files that we parse in order |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
373 to prevent infinite recursion. */ |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
374 unsigned int iteration_limit = 2000; |
0 | 375 /* Loop over the arguments, handling response files. We always skip |
376 ARGVP[0], as that is the name of the program being run. */ | |
377 while (++i < *argcp) | |
378 { | |
379 /* The name of the response file. */ | |
380 const char *filename; | |
381 /* The response file. */ | |
382 FILE *f; | |
383 /* An upper bound on the number of characters in the response | |
384 file. */ | |
385 long pos; | |
386 /* The number of characters in the response file, when actually | |
387 read. */ | |
388 size_t len; | |
389 /* A dynamically allocated buffer used to hold options read from a | |
390 response file. */ | |
391 char *buffer; | |
392 /* Dynamically allocated storage for the options read from the | |
393 response file. */ | |
394 char **file_argv; | |
395 /* The number of options read from the response file, if any. */ | |
396 size_t file_argc; | |
111 | 397 #ifdef S_ISDIR |
398 struct stat sb; | |
399 #endif | |
0 | 400 /* We are only interested in options of the form "@file". */ |
401 filename = (*argvp)[i]; | |
402 if (filename[0] != '@') | |
403 continue; | |
67
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
404 /* If we have iterated too many times then stop. */ |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
405 if (-- iteration_limit == 0) |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
406 { |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
407 fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]); |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
408 xexit (1); |
f6334be47118
update gcc from gcc-4.6-20100522 to gcc-4.6-20110318
nobuyasu <dimolto@cr.ie.u-ryukyu.ac.jp>
parents:
55
diff
changeset
|
409 } |
111 | 410 #ifdef S_ISDIR |
411 if (stat (filename+1, &sb) < 0) | |
412 continue; | |
413 if (S_ISDIR(sb.st_mode)) | |
414 { | |
415 fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]); | |
416 xexit (1); | |
417 } | |
418 #endif | |
0 | 419 /* Read the contents of the file. */ |
420 f = fopen (++filename, "r"); | |
421 if (!f) | |
422 continue; | |
423 if (fseek (f, 0L, SEEK_END) == -1) | |
424 goto error; | |
425 pos = ftell (f); | |
426 if (pos == -1) | |
427 goto error; | |
428 if (fseek (f, 0L, SEEK_SET) == -1) | |
429 goto error; | |
430 buffer = (char *) xmalloc (pos * sizeof (char) + 1); | |
431 len = fread (buffer, sizeof (char), pos, f); | |
432 if (len != (size_t) pos | |
433 /* On Windows, fread may return a value smaller than POS, | |
434 due to CR/LF->CR translation when reading text files. | |
435 That does not in-and-of itself indicate failure. */ | |
436 && ferror (f)) | |
437 goto error; | |
438 /* Add a NUL terminator. */ | |
439 buffer[len] = '\0'; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
440 /* If the file is empty or contains only whitespace, buildargv would |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
441 return a single empty argument. In this context we want no arguments, |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
442 instead. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
443 if (only_whitespace (buffer)) |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
444 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
445 file_argv = (char **) xmalloc (sizeof (char *)); |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
446 file_argv[0] = NULL; |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
447 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
448 else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
449 /* Parse the string. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
450 file_argv = buildargv (buffer); |
0 | 451 /* If *ARGVP is not already dynamically allocated, copy it. */ |
452 if (!argv_dynamic) | |
111 | 453 *argvp = dupargv (*argvp); |
0 | 454 /* Count the number of arguments. */ |
455 file_argc = 0; | |
55
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
456 while (file_argv[file_argc]) |
0 | 457 ++file_argc; |
458 /* Now, insert FILE_ARGV into ARGV. The "+1" below handles the | |
459 NULL terminator at the end of ARGV. */ | |
460 *argvp = ((char **) | |
461 xrealloc (*argvp, | |
462 (*argcp + file_argc + 1) * sizeof (char *))); | |
463 memmove (*argvp + i + file_argc, *argvp + i + 1, | |
464 (*argcp - i) * sizeof (char *)); | |
465 memcpy (*argvp + i, file_argv, file_argc * sizeof (char *)); | |
466 /* The original option has been replaced by all the new | |
467 options. */ | |
468 *argcp += file_argc - 1; | |
469 /* Free up memory allocated to process the response file. We do | |
470 not use freeargv because the individual options in FILE_ARGV | |
471 are now in the main ARGV. */ | |
472 free (file_argv); | |
473 free (buffer); | |
474 /* Rescan all of the arguments just read to support response | |
475 files that include other response files. */ | |
476 --i; | |
477 error: | |
478 /* We're all done with the file now. */ | |
479 fclose (f); | |
480 } | |
481 } | |
482 | |
111 | 483 /* |
484 | |
485 @deftypefn Extension int countargv (char * const *@var{argv}) | |
486 | |
487 Return the number of elements in @var{argv}. | |
488 Returns zero if @var{argv} is NULL. | |
489 | |
490 @end deftypefn | |
491 | |
492 */ | |
493 | |
494 int | |
495 countargv (char * const *argv) | |
496 { | |
497 int argc; | |
498 | |
499 if (argv == NULL) | |
500 return 0; | |
501 for (argc = 0; argv[argc] != NULL; argc++) | |
502 continue; | |
503 return argc; | |
504 } | |
505 | |
0 | 506 #ifdef MAIN |
507 | |
508 /* Simple little test driver. */ | |
509 | |
510 static const char *const tests[] = | |
511 { | |
512 "a simple command line", | |
513 "arg 'foo' is single quoted", | |
514 "arg \"bar\" is double quoted", | |
515 "arg \"foo bar\" has embedded whitespace", | |
516 "arg 'Jack said \\'hi\\'' has single quotes", | |
517 "arg 'Jack said \\\"hi\\\"' has double quotes", | |
518 "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9", | |
519 | |
520 /* This should be expanded into only one argument. */ | |
521 "trailing-whitespace ", | |
522 | |
523 "", | |
524 NULL | |
525 }; | |
526 | |
527 int | |
528 main (void) | |
529 { | |
530 char **argv; | |
531 const char *const *test; | |
532 char **targs; | |
533 | |
534 for (test = tests; *test != NULL; test++) | |
535 { | |
536 printf ("buildargv(\"%s\")\n", *test); | |
537 if ((argv = buildargv (*test)) == NULL) | |
538 { | |
539 printf ("failed!\n\n"); | |
540 } | |
541 else | |
542 { | |
543 for (targs = argv; *targs != NULL; targs++) | |
544 { | |
545 printf ("\t\"%s\"\n", *targs); | |
546 } | |
547 printf ("\n"); | |
548 } | |
549 freeargv (argv); | |
550 } | |
551 | |
552 return 0; | |
553 } | |
554 | |
555 #endif /* MAIN */ |