1 /* $MirOS: src/gnu/usr.bin/binutils/libiberty/argv.c,v 1.4 2005/06/05 21:24:44 tg Exp $ */
2
3 /* Create and destroy argument vectors (argv's)
4 Copyright (C) 1992, 2001 Free Software Foundation, Inc.
5 Written by Fred Fish @ Cygnus Support
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., 51 Franklin Street - Fifth Floor,
21 Boston, MA 02110-1301, 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 #include <sys/cdefs.h>
28 __RCSID("$MirOS: src/gnu/usr.bin/binutils/libiberty/argv.c,v 1.4 2005/06/05 21:24:44 tg Exp $");
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 #include "ansidecl.h"
34 #include "libiberty.h"
35
36 #define ISBLANK(ch) ((ch) == ' ' || (ch) == '\t')
37
38 /* Routines imported from standard C runtime libraries. */
39
40 #include <stddef.h>
41 #include <string.h>
42 #include <stdlib.h>
43
44 #ifndef NULL
45 #define NULL 0
46 #endif
47
48 #ifndef EOS
49 #define EOS '\0'
50 #endif
51
52 #define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
53
54
55 /*
56
57 @deftypefn Extension char** dupargv (char **@var{vector})
58
59 Duplicate an argument vector. Simply scans through @var{vector},
60 duplicating each argument until the terminating @code{NULL} is found.
61 Returns a pointer to the argument vector if successful. Returns
62 @code{NULL} if there is insufficient memory to complete building the
63 argument vector.
64
65 @end deftypefn
66
67 */
68
69 char **
dupargv(char ** argv)70 dupargv (char **argv)
71 {
72 int argc;
73 char **copy;
74
75 if (argv == NULL)
76 return NULL;
77
78 /* the vector */
79 for (argc = 0; argv[argc] != NULL; argc++);
80 copy = (char **) malloc ((argc + 1) * sizeof (char *));
81 if (copy == NULL)
82 return NULL;
83
84 /* the strings */
85 for (argc = 0; argv[argc] != NULL; argc++)
86 {
87 int len = strlen (argv[argc]);
88 copy[argc] = (char *) malloc (len + 1);
89 if (copy[argc] == NULL)
90 {
91 freeargv (copy);
92 return NULL;
93 }
94 strlcpy (copy[argc], argv[argc], sizeof (char *) * (len + 1));
95 }
96 copy[argc] = NULL;
97 return copy;
98 }
99
100 /*
101
102 @deftypefn Extension void freeargv (char **@var{vector})
103
104 Free an argument vector that was built using @code{buildargv}. Simply
105 scans through @var{vector}, freeing the memory for each argument until
106 the terminating @code{NULL} is found, and then frees @var{vector}
107 itself.
108
109 @end deftypefn
110
111 */
112
freeargv(char ** vector)113 void freeargv (char **vector)
114 {
115 register char **scan;
116
117 if (vector != NULL)
118 {
119 for (scan = vector; *scan != NULL; scan++)
120 {
121 free (*scan);
122 }
123 free (vector);
124 }
125 }
126
127 /*
128
129 @deftypefn Extension char** buildargv (char *@var{sp})
130
131 Given a pointer to a string, parse the string extracting fields
132 separated by whitespace and optionally enclosed within either single
133 or double quotes (which are stripped off), and build a vector of
134 pointers to copies of the string for each field. The input string
135 remains unchanged. The last element of the vector is followed by a
136 @code{NULL} element.
137
138 All of the memory for the pointer array and copies of the string
139 is obtained from @code{malloc}. All of the memory can be returned to the
140 system with the single function call @code{freeargv}, which takes the
141 returned result of @code{buildargv}, as it's argument.
142
143 Returns a pointer to the argument vector if successful. Returns
144 @code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
145 memory to complete building the argument vector.
146
147 If the input is a null string (as opposed to a @code{NULL} pointer),
148 then buildarg returns an argument vector that has one arg, a null
149 string.
150
151 @end deftypefn
152
153 The memory for the argv array is dynamically expanded as necessary.
154
155 In order to provide a working buffer for extracting arguments into,
156 with appropriate stripping of quotes and translation of backslash
157 sequences, we allocate a working buffer at least as long as the input
158 string. This ensures that we always have enough space in which to
159 work, since the extracted arg is never larger than the input string.
160
161 The argument vector is always kept terminated with a @code{NULL} arg
162 pointer, so it can be passed to @code{freeargv} at any time, or
163 returned, as appropriate.
164
165 */
166
buildargv(const char * input)167 char **buildargv (const char *input)
168 {
169 char *arg;
170 char *copybuf;
171 int squote = 0;
172 int dquote = 0;
173 int bsquote = 0;
174 int argc = 0;
175 int maxargc = 0;
176 char **argv = NULL;
177 char **nargv;
178
179 if (input != NULL)
180 {
181 copybuf = (char *) alloca (strlen (input) + 1);
182 /* Is a do{}while to always execute the loop once. Always return an
183 argv, even for null strings. See NOTES above, test case below. */
184 do
185 {
186 /* Pick off argv[argc] */
187 while (ISBLANK (*input))
188 {
189 input++;
190 }
191 if ((maxargc == 0) || (argc >= (maxargc - 1)))
192 {
193 /* argv needs initialization, or expansion */
194 if (argv == NULL)
195 {
196 maxargc = INITIAL_MAXARGC;
197 nargv = (char **) malloc (maxargc * sizeof (char *));
198 }
199 else
200 {
201 maxargc *= 2;
202 nargv = (char **) realloc (argv, maxargc * sizeof (char *));
203 }
204 if (nargv == NULL)
205 {
206 if (argv != NULL)
207 {
208 freeargv (argv);
209 argv = NULL;
210 }
211 break;
212 }
213 argv = nargv;
214 argv[argc] = NULL;
215 }
216 /* Begin scanning arg */
217 arg = copybuf;
218 while (*input != EOS)
219 {
220 if (ISBLANK (*input) && !squote && !dquote && !bsquote)
221 {
222 break;
223 }
224 else
225 {
226 if (bsquote)
227 {
228 bsquote = 0;
229 *arg++ = *input;
230 }
231 else if (*input == '\\')
232 {
233 bsquote = 1;
234 }
235 else if (squote)
236 {
237 if (*input == '\'')
238 {
239 squote = 0;
240 }
241 else
242 {
243 *arg++ = *input;
244 }
245 }
246 else if (dquote)
247 {
248 if (*input == '"')
249 {
250 dquote = 0;
251 }
252 else
253 {
254 *arg++ = *input;
255 }
256 }
257 else
258 {
259 if (*input == '\'')
260 {
261 squote = 1;
262 }
263 else if (*input == '"')
264 {
265 dquote = 1;
266 }
267 else
268 {
269 *arg++ = *input;
270 }
271 }
272 input++;
273 }
274 }
275 *arg = EOS;
276 argv[argc] = strdup (copybuf);
277 if (argv[argc] == NULL)
278 {
279 freeargv (argv);
280 argv = NULL;
281 break;
282 }
283 argc++;
284 argv[argc] = NULL;
285
286 while (ISBLANK (*input))
287 {
288 input++;
289 }
290 }
291 while (*input != EOS);
292 }
293 return (argv);
294 }
295
296 #ifdef MAIN
297
298 /* Simple little test driver. */
299
300 static const char *const tests[] =
301 {
302 "a simple command line",
303 "arg 'foo' is single quoted",
304 "arg \"bar\" is double quoted",
305 "arg \"foo bar\" has embedded whitespace",
306 "arg 'Jack said \\'hi\\'' has single quotes",
307 "arg 'Jack said \\\"hi\\\"' has double quotes",
308 "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",
309
310 /* This should be expanded into only one argument. */
311 "trailing-whitespace ",
312
313 "",
314 NULL
315 };
316
317 int
main(void)318 main (void)
319 {
320 char **argv;
321 const char *const *test;
322 char **targs;
323
324 for (test = tests; *test != NULL; test++)
325 {
326 printf ("buildargv(\"%s\")\n", *test);
327 if ((argv = buildargv (*test)) == NULL)
328 {
329 printf ("failed!\n\n");
330 }
331 else
332 {
333 for (targs = argv; *targs != NULL; targs++)
334 {
335 printf ("\t\"%s\"\n", *targs);
336 }
337 printf ("\n");
338 }
339 freeargv (argv);
340 }
341
342 return 0;
343 }
344
345 #endif /* MAIN */
346