1 /* Create and destroy argument vectors (argv's)
2 Copyright (C) 1992 Free Software Foundation, Inc.
3 Written by Fred Fish @ Cygnus Support
4
5 Modified by Akim Demaille so that it can compile out of liberty
6
7 This file is part of the libiberty library.
8 Libiberty is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 Libiberty is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public
19 License along with libiberty; see the file COPYING.LIB. If
20 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
22
23
24 /* Create and destroy argument vectors. An argument vector is simply an
25 array of string pointers, terminated by a NULL pointer. */
26
27 #if HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30
31 #ifndef alloca
32 # ifdef __GNUC__
33 # define alloca __builtin_alloca
34 # define HAVE_ALLOCA 1
35 # else
36 # if defined HAVE_ALLOCA_H || defined _LIBC
37 # include <alloca.h>
38 # else
39 # ifdef _AIX
40 #pragma alloca
41 # else
42 # ifndef alloca
43 char *alloca ();
44 # endif
45 # endif
46 # endif
47 # endif
48 #endif
49
50 #if defined STDC_HEADERS || defined _LIBC
51 # include <stdlib.h>
52 #else
53 # ifdef HAVE_MALLOC_H
54 # include <malloc.h>
55 # else
56 extern void free ();
57 extern void * calloc ();
58 extern void * malloc ();
59 extern void * realloc ();
60 # endif
61 #endif
62
63 #ifdef HAVE_STRING_H
64 # if !STDC_HEADERS && HAVE_MEMORY_H
65 # include <memory.h>
66 # endif
67 # include <string.h>
68 #else
69 # include <strings.h>
70 char *memchr ();
71 #endif
72
73
74 #include <ctype.h>
75 /* Jim Meyering writes:
76
77 "... Some ctype macros are valid only for character codes that
78 isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
79 using /bin/cc or gcc but without giving an ansi option). So, all
80 ctype uses should be through macros like ISPRINT... If
81 STDC_HEADERS is defined, then autoconf has verified that the ctype
82 macros don't need to be guarded with references to isascii. ...
83 Defining isascii to 1 should let any compiler worth its salt
84 eliminate the && through constant folding." */
85
86 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
87 #define ISASCII(c) 1
88 #else
89 #define ISASCII(c) isascii((int) c)
90 #endif
91
92 #define ISSPACE(c) (ISASCII (c) && isspace ((int) c))
93
94 #include "argv.h"
95
96 #ifndef NULL
97 #define NULL 0
98 #endif
99
100 #ifndef EOS
101 #define EOS '\0'
102 #endif
103
104 #define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
105
106
107 /* dupargv -- duplicate an argument vector */
108
109 char **
dupargv(argv)110 dupargv (argv)
111 char **argv;
112 {
113 int argc;
114 char **copy;
115
116 if (argv == NULL)
117 return NULL;
118
119 /* the vector */
120 for (argc = 0; argv[argc] != NULL; argc++);
121 copy = (char **) malloc ((argc + 1) * sizeof (char *));
122 if (copy == NULL)
123 return NULL;
124
125 /* the strings */
126 for (argc = 0; argv[argc] != NULL; argc++)
127 {
128 int len = strlen (argv[argc]);
129 copy[argc] = malloc (sizeof (char *) * (len + 1));
130 if (copy[argc] == NULL)
131 {
132 freeargv (copy);
133 return NULL;
134 }
135 strcpy (copy[argc], argv[argc]);
136 }
137 copy[argc] = NULL;
138 return copy;
139 }
140
141 /* freeargv -- free an argument vector */
142
freeargv(vector)143 void freeargv (vector)
144 char **vector;
145 {
146 register char **scan;
147
148 if (vector != NULL)
149 {
150 for (scan = vector; *scan != NULL; scan++)
151 {
152 free (*scan);
153 }
154 free (vector);
155 }
156 }
157
freeargv_from(vector,from)158 void freeargv_from (vector, from)
159 char **vector;
160 int from;
161 {
162 register char **scan;
163
164 if (vector != NULL)
165 {
166 for (scan = vector ; (from > 0) && (*scan != NULL) ; from--)
167 scan ++;
168
169 for (/* nothing */ ; *scan != NULL; scan++)
170 free (*scan);
171 free (vector);
172 }
173 }
174
175 /* buildargv -- build an argument vector from a string */
176
buildargv_argc(input,argc)177 char **buildargv_argc (input, argc)
178 const char *input;
179 int * argc;
180 {
181 char *arg;
182 char *copybuf;
183 int squote = 0;
184 int dquote = 0;
185 int bsquote = 0;
186 int maxargc = 0;
187 char **argv = NULL;
188 char **nargv;
189
190 if (input != NULL)
191 {
192 copybuf = alloca (strlen (input) + 1);
193 /* Is a do{}while to always execute the loop once. Always return an
194 argv, even for null strings. See NOTES above, test case below. */
195 do
196 {
197 /* Pick off argv[*argc] */
198 while (ISSPACE (*input))
199 input++;
200 if ((maxargc == 0) || (*argc >= (maxargc - 1)))
201 {
202 /* argv needs initialization, or expansion */
203 if (argv == NULL)
204 {
205 maxargc = *argc > INITIAL_MAXARGC ? *argc : INITIAL_MAXARGC;
206 nargv = (char **) malloc (maxargc * sizeof (char *));
207 }
208 else
209 {
210 maxargc *= 2;
211 nargv = (char **) realloc (argv, maxargc * sizeof (char *));
212 }
213 if (nargv == NULL)
214 {
215 if (argv != NULL)
216 {
217 freeargv (argv);
218 argv = NULL;
219 }
220 break;
221 }
222 argv = nargv;
223 argv[*argc] = NULL;
224 }
225 /* Begin scanning arg */
226 arg = copybuf;
227 while (*input != EOS)
228 {
229 if (ISSPACE (*input) && !squote && !dquote && !bsquote)
230 break;
231 else
232 {
233 if (bsquote)
234 {
235 bsquote = 0;
236 *arg++ = *input;
237 }
238 else if (*input == '\\')
239 {
240 bsquote = 1;
241 }
242 else if (squote)
243 {
244 if (*input == '\'')
245 squote = 0;
246 else
247 *arg++ = *input;
248 }
249 else if (dquote)
250 {
251 if (*input == '"')
252 dquote = 0;
253 else
254 *arg++ = *input;
255 }
256 else
257 {
258 if (*input == '\'')
259 {
260 squote = 1;
261 }
262 else if (*input == '"')
263 {
264 dquote = 1;
265 }
266 else
267 {
268 *arg++ = *input;
269 }
270 }
271 input++;
272 }
273 }
274 *arg = EOS;
275 argv[*argc] = strdup (copybuf);
276 if (argv[*argc] == NULL)
277 {
278 freeargv (argv);
279 argv = NULL;
280 break;
281 }
282 (*argc)++;
283 argv[*argc] = NULL;
284
285 while (ISSPACE (*input))
286 input++;
287 }
288 while (*input != EOS);
289 }
290 return (argv);
291 }
292
293 char **
buildargv(const char * string)294 buildargv (const char * string)
295 {
296 int argc = 0;
297 return buildargv_argc (string, &argc);
298 }
299
300 #ifdef MAIN
301
302 /* Simple little test driver. */
303
304 static char *tests[] =
305 {
306 "a simple command line",
307 "arg 'foo' is single quoted",
308 "arg \"bar\" is double quoted",
309 "arg \"foo bar\" has embedded whitespace",
310 "arg 'Jack said \\'hi\\'' has single quotes",
311 "arg 'Jack said \\\"hi\\\"' has double quotes",
312 "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",
313
314 /* This should be expanded into only one argument. */
315 "trailing-whitespace ",
316
317 "",
318 NULL
319 };
320
main()321 main ()
322 {
323 char **argv;
324 char **test;
325 char **targs;
326
327 for (test = tests; *test != NULL; test++)
328 {
329 printf ("buildargv(\"%s\")\n", *test);
330 if ((argv = buildargv (*test)) == NULL)
331 printf ("failed!\n\n");
332 else
333 {
334 for (targs = argv; *targs != NULL; targs++)
335 printf ("\t\"%s\"\n", *targs);
336 printf ("\n");
337 }
338 freeargv (argv);
339 }
340
341 }
342
343 #endif /* MAIN */
344