Mercurial > hg > CbC > CbC_gcc
annotate libiberty/argv.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
rev | line source |
---|---|
0 | 1 /* Create and destroy argument vectors (argv's) |
145 | 2 Copyright (C) 1992-2020 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 | |
145 | 330 /* Write out a pair of quotes for an empty argument. */ |
331 if (arg == *argv) | |
332 if (EOF == fputs ("\"\"", f)) | |
333 { | |
334 status = 1; | |
335 goto done; | |
336 } | |
337 | |
0 | 338 if (EOF == fputc ('\n', f)) |
339 { | |
340 status = 1; | |
341 goto done; | |
342 } | |
343 argv++; | |
344 } | |
345 | |
346 done: | |
347 return status; | |
348 } | |
349 | |
350 /* | |
351 | |
352 @deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) | |
353 | |
354 The @var{argcp} and @code{argvp} arguments are pointers to the usual | |
355 @code{argc} and @code{argv} arguments to @code{main}. This function | |
356 looks for arguments that begin with the character @samp{@@}. Any such | |
357 arguments are interpreted as ``response files''. The contents of the | |
358 response file are interpreted as additional command line options. In | |
359 particular, the file is separated into whitespace-separated strings; | |
360 each such string is taken as a command-line option. The new options | |
361 are inserted in place of the option naming the response file, and | |
362 @code{*argcp} and @code{*argvp} will be updated. If the value of | |
363 @code{*argvp} is modified by this function, then the new value has | |
364 been dynamically allocated and can be deallocated by the caller with | |
365 @code{freeargv}. However, most callers will simply call | |
366 @code{expandargv} near the beginning of @code{main} and allow the | |
367 operating system to free the memory when the program exits. | |
368 | |
369 @end deftypefn | |
370 | |
371 */ | |
372 | |
373 void | |
374 expandargv (int *argcp, char ***argvp) | |
375 { | |
376 /* The argument we are currently processing. */ | |
377 int i = 0; | |
131 | 378 /* To check if ***argvp has been dynamically allocated. */ |
379 char ** const original_argv = *argvp; | |
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
|
380 /* 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
|
381 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
|
382 unsigned int iteration_limit = 2000; |
0 | 383 /* Loop over the arguments, handling response files. We always skip |
384 ARGVP[0], as that is the name of the program being run. */ | |
385 while (++i < *argcp) | |
386 { | |
387 /* The name of the response file. */ | |
388 const char *filename; | |
389 /* The response file. */ | |
390 FILE *f; | |
391 /* An upper bound on the number of characters in the response | |
392 file. */ | |
393 long pos; | |
394 /* The number of characters in the response file, when actually | |
395 read. */ | |
396 size_t len; | |
397 /* A dynamically allocated buffer used to hold options read from a | |
398 response file. */ | |
399 char *buffer; | |
400 /* Dynamically allocated storage for the options read from the | |
401 response file. */ | |
402 char **file_argv; | |
403 /* The number of options read from the response file, if any. */ | |
404 size_t file_argc; | |
111 | 405 #ifdef S_ISDIR |
406 struct stat sb; | |
407 #endif | |
0 | 408 /* We are only interested in options of the form "@file". */ |
409 filename = (*argvp)[i]; | |
410 if (filename[0] != '@') | |
411 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
|
412 /* 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
|
413 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
|
414 { |
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
|
415 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
|
416 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
|
417 } |
111 | 418 #ifdef S_ISDIR |
419 if (stat (filename+1, &sb) < 0) | |
420 continue; | |
421 if (S_ISDIR(sb.st_mode)) | |
422 { | |
423 fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]); | |
424 xexit (1); | |
425 } | |
426 #endif | |
0 | 427 /* Read the contents of the file. */ |
428 f = fopen (++filename, "r"); | |
429 if (!f) | |
430 continue; | |
431 if (fseek (f, 0L, SEEK_END) == -1) | |
432 goto error; | |
433 pos = ftell (f); | |
434 if (pos == -1) | |
435 goto error; | |
436 if (fseek (f, 0L, SEEK_SET) == -1) | |
437 goto error; | |
438 buffer = (char *) xmalloc (pos * sizeof (char) + 1); | |
439 len = fread (buffer, sizeof (char), pos, f); | |
440 if (len != (size_t) pos | |
441 /* On Windows, fread may return a value smaller than POS, | |
442 due to CR/LF->CR translation when reading text files. | |
443 That does not in-and-of itself indicate failure. */ | |
444 && ferror (f)) | |
445 goto error; | |
446 /* Add a NUL terminator. */ | |
447 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
|
448 /* 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
|
449 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
|
450 instead. */ |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
451 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
|
452 { |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
453 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
|
454 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
|
455 } |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
456 else |
77e2b8dfacca
update it from 4.4.3 to 4.5.0
ryoma <e075725@ie.u-ryukyu.ac.jp>
parents:
0
diff
changeset
|
457 /* 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
|
458 file_argv = buildargv (buffer); |
0 | 459 /* If *ARGVP is not already dynamically allocated, copy it. */ |
131 | 460 if (*argvp == original_argv) |
111 | 461 *argvp = dupargv (*argvp); |
0 | 462 /* Count the number of arguments. */ |
463 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
|
464 while (file_argv[file_argc]) |
0 | 465 ++file_argc; |
131 | 466 /* Free the original option's memory. */ |
467 free ((*argvp)[i]); | |
0 | 468 /* Now, insert FILE_ARGV into ARGV. The "+1" below handles the |
469 NULL terminator at the end of ARGV. */ | |
470 *argvp = ((char **) | |
471 xrealloc (*argvp, | |
472 (*argcp + file_argc + 1) * sizeof (char *))); | |
473 memmove (*argvp + i + file_argc, *argvp + i + 1, | |
474 (*argcp - i) * sizeof (char *)); | |
475 memcpy (*argvp + i, file_argv, file_argc * sizeof (char *)); | |
476 /* The original option has been replaced by all the new | |
477 options. */ | |
478 *argcp += file_argc - 1; | |
479 /* Free up memory allocated to process the response file. We do | |
480 not use freeargv because the individual options in FILE_ARGV | |
481 are now in the main ARGV. */ | |
482 free (file_argv); | |
483 free (buffer); | |
484 /* Rescan all of the arguments just read to support response | |
485 files that include other response files. */ | |
486 --i; | |
487 error: | |
488 /* We're all done with the file now. */ | |
489 fclose (f); | |
490 } | |
491 } | |
492 | |
111 | 493 /* |
494 | |
495 @deftypefn Extension int countargv (char * const *@var{argv}) | |
496 | |
497 Return the number of elements in @var{argv}. | |
498 Returns zero if @var{argv} is NULL. | |
499 | |
500 @end deftypefn | |
501 | |
502 */ | |
503 | |
504 int | |
505 countargv (char * const *argv) | |
506 { | |
507 int argc; | |
508 | |
509 if (argv == NULL) | |
510 return 0; | |
511 for (argc = 0; argv[argc] != NULL; argc++) | |
512 continue; | |
513 return argc; | |
514 } | |
515 | |
0 | 516 #ifdef MAIN |
517 | |
518 /* Simple little test driver. */ | |
519 | |
520 static const char *const tests[] = | |
521 { | |
522 "a simple command line", | |
523 "arg 'foo' is single quoted", | |
524 "arg \"bar\" is double quoted", | |
525 "arg \"foo bar\" has embedded whitespace", | |
526 "arg 'Jack said \\'hi\\'' has single quotes", | |
527 "arg 'Jack said \\\"hi\\\"' has double quotes", | |
528 "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", | |
529 | |
530 /* This should be expanded into only one argument. */ | |
531 "trailing-whitespace ", | |
532 | |
533 "", | |
534 NULL | |
535 }; | |
536 | |
537 int | |
538 main (void) | |
539 { | |
540 char **argv; | |
541 const char *const *test; | |
542 char **targs; | |
543 | |
544 for (test = tests; *test != NULL; test++) | |
545 { | |
546 printf ("buildargv(\"%s\")\n", *test); | |
547 if ((argv = buildargv (*test)) == NULL) | |
548 { | |
549 printf ("failed!\n\n"); | |
550 } | |
551 else | |
552 { | |
553 for (targs = argv; *targs != NULL; targs++) | |
554 { | |
555 printf ("\t\"%s\"\n", *targs); | |
556 } | |
557 printf ("\n"); | |
558 } | |
559 freeargv (argv); | |
560 } | |
561 | |
562 return 0; | |
563 } | |
564 | |
565 #endif /* MAIN */ |