Minor formatting changes.
[deliverable/binutils-gdb.git] / libiberty / argv.c
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 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., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, 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 #include "ansidecl.h"
26 #include "libiberty.h"
27
28 #ifdef isspace
29 #undef isspace
30 #endif
31 #define isspace(ch) ((ch) == ' ' || (ch) == '\t')
32
33 /* Routines imported from standard C runtime libraries. */
34
35 #ifdef __STDC__
36
37 #include <stddef.h>
38 extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */
39 extern size_t strlen (const char *s); /* 4.11.6.3 */
40 extern void *malloc (size_t size); /* 4.10.3.3 */
41 extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */
42 extern void free (void *ptr); /* 4.10.3.2 */
43 extern char *strdup (const char *s); /* Non-ANSI */
44
45 #else /* !__STDC__ */
46
47 #if !defined _WIN32 || defined __GNUC__
48 extern char *memcpy (); /* Copy memory region */
49 extern int strlen (); /* Count length of string */
50 extern char *malloc (); /* Standard memory allocater */
51 extern char *realloc (); /* Standard memory reallocator */
52 extern void free (); /* Free malloc'd memory */
53 extern char *strdup (); /* Duplicate a string */
54 #endif
55
56 #endif /* __STDC__ */
57
58 #include "alloca-conf.h"
59
60 #ifndef NULL
61 #define NULL 0
62 #endif
63
64 #ifndef EOS
65 #define EOS '\0'
66 #endif
67
68 #define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
69
70
71 /*
72
73 NAME
74
75 dupargv -- duplicate an argument vector
76
77 SYNOPSIS
78
79 char **dupargv (vector)
80 char **vector;
81
82 DESCRIPTION
83
84 Duplicate an argument vector. Simply scans through the
85 vector, duplicating each argument until the
86 terminating NULL is found.
87
88 RETURNS
89
90 Returns a pointer to the argument vector if
91 successful. Returns NULL if there is insufficient memory to
92 complete building the argument vector.
93
94 */
95
96 char **
97 dupargv (argv)
98 char **argv;
99 {
100 int argc;
101 char **copy;
102
103 if (argv == NULL)
104 return NULL;
105
106 /* the vector */
107 for (argc = 0; argv[argc] != NULL; argc++);
108 copy = (char **) malloc ((argc + 1) * sizeof (char *));
109 if (copy == NULL)
110 return NULL;
111
112 /* the strings */
113 for (argc = 0; argv[argc] != NULL; argc++)
114 {
115 int len = strlen (argv[argc]);
116 copy[argc] = malloc (sizeof (char *) * (len + 1));
117 if (copy[argc] == NULL)
118 {
119 freeargv (copy);
120 return NULL;
121 }
122 strcpy (copy[argc], argv[argc]);
123 }
124 copy[argc] = NULL;
125 return copy;
126 }
127
128 /*
129
130 NAME
131
132 freeargv -- free an argument vector
133
134 SYNOPSIS
135
136 void freeargv (vector)
137 char **vector;
138
139 DESCRIPTION
140
141 Free an argument vector that was built using buildargv. Simply scans
142 through the vector, freeing the memory for each argument until the
143 terminating NULL is found, and then frees the vector itself.
144
145 RETURNS
146
147 No value.
148
149 */
150
151 void freeargv (vector)
152 char **vector;
153 {
154 register char **scan;
155
156 if (vector != NULL)
157 {
158 for (scan = vector; *scan != NULL; scan++)
159 {
160 free (*scan);
161 }
162 free (vector);
163 }
164 }
165
166 /*
167
168 NAME
169
170 buildargv -- build an argument vector from a string
171
172 SYNOPSIS
173
174 char **buildargv (sp)
175 char *sp;
176
177 DESCRIPTION
178
179 Given a pointer to a string, parse the string extracting fields
180 separated by whitespace and optionally enclosed within either single
181 or double quotes (which are stripped off), and build a vector of
182 pointers to copies of the string for each field. The input string
183 remains unchanged.
184
185 All of the memory for the pointer array and copies of the string
186 is obtained from malloc. All of the memory can be returned to the
187 system with the single function call freeargv, which takes the
188 returned result of buildargv, as it's argument.
189
190 The memory for the argv array is dynamically expanded as necessary.
191
192 RETURNS
193
194 Returns a pointer to the argument vector if successful. Returns NULL
195 if the input string pointer is NULL or if there is insufficient
196 memory to complete building the argument vector.
197
198 NOTES
199
200 In order to provide a working buffer for extracting arguments into,
201 with appropriate stripping of quotes and translation of backslash
202 sequences, we allocate a working buffer at least as long as the input
203 string. This ensures that we always have enough space in which to
204 work, since the extracted arg is never larger than the input string.
205
206 If the input is a null string (as opposed to a NULL pointer), then
207 buildarg returns an argv that has one arg, a null string.
208
209 Argv is always kept terminated with a NULL arg pointer, so it can
210 be passed to freeargv at any time, or returned, as appropriate.
211 */
212
213 char **buildargv (input)
214 char *input;
215 {
216 char *arg;
217 char *copybuf;
218 int squote = 0;
219 int dquote = 0;
220 int bsquote = 0;
221 int argc = 0;
222 int maxargc = 0;
223 char **argv = NULL;
224 char **nargv;
225
226 if (input != NULL)
227 {
228 copybuf = (char *) alloca (strlen (input) + 1);
229 /* Is a do{}while to always execute the loop once. Always return an
230 argv, even for null strings. See NOTES above, test case below. */
231 do
232 {
233 /* Pick off argv[argc] */
234 while (isspace (*input))
235 {
236 input++;
237 }
238 if ((maxargc == 0) || (argc >= (maxargc - 1)))
239 {
240 /* argv needs initialization, or expansion */
241 if (argv == NULL)
242 {
243 maxargc = INITIAL_MAXARGC;
244 nargv = (char **) malloc (maxargc * sizeof (char *));
245 }
246 else
247 {
248 maxargc *= 2;
249 nargv = (char **) realloc (argv, maxargc * sizeof (char *));
250 }
251 if (nargv == NULL)
252 {
253 if (argv != NULL)
254 {
255 freeargv (argv);
256 argv = NULL;
257 }
258 break;
259 }
260 argv = nargv;
261 argv[argc] = NULL;
262 }
263 /* Begin scanning arg */
264 arg = copybuf;
265 while (*input != EOS)
266 {
267 if (isspace (*input) && !squote && !dquote && !bsquote)
268 {
269 break;
270 }
271 else
272 {
273 if (bsquote)
274 {
275 bsquote = 0;
276 *arg++ = *input;
277 }
278 else if (*input == '\\')
279 {
280 bsquote = 1;
281 }
282 else if (squote)
283 {
284 if (*input == '\'')
285 {
286 squote = 0;
287 }
288 else
289 {
290 *arg++ = *input;
291 }
292 }
293 else if (dquote)
294 {
295 if (*input == '"')
296 {
297 dquote = 0;
298 }
299 else
300 {
301 *arg++ = *input;
302 }
303 }
304 else
305 {
306 if (*input == '\'')
307 {
308 squote = 1;
309 }
310 else if (*input == '"')
311 {
312 dquote = 1;
313 }
314 else
315 {
316 *arg++ = *input;
317 }
318 }
319 input++;
320 }
321 }
322 *arg = EOS;
323 argv[argc] = strdup (copybuf);
324 if (argv[argc] == NULL)
325 {
326 freeargv (argv);
327 argv = NULL;
328 break;
329 }
330 argc++;
331 argv[argc] = NULL;
332
333 while (isspace (*input))
334 {
335 input++;
336 }
337 }
338 while (*input != EOS);
339 }
340 return (argv);
341 }
342
343 #ifdef MAIN
344
345 /* Simple little test driver. */
346
347 static char *tests[] =
348 {
349 "a simple command line",
350 "arg 'foo' is single quoted",
351 "arg \"bar\" is double quoted",
352 "arg \"foo bar\" has embedded whitespace",
353 "arg 'Jack said \\'hi\\'' has single quotes",
354 "arg 'Jack said \\\"hi\\\"' has double quotes",
355 "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",
356
357 /* This should be expanded into only one argument. */
358 "trailing-whitespace ",
359
360 "",
361 NULL
362 };
363
364 main ()
365 {
366 char **argv;
367 char **test;
368 char **targs;
369
370 for (test = tests; *test != NULL; test++)
371 {
372 printf ("buildargv(\"%s\")\n", *test);
373 if ((argv = buildargv (*test)) == NULL)
374 {
375 printf ("failed!\n\n");
376 }
377 else
378 {
379 for (targs = argv; *targs != NULL; targs++)
380 {
381 printf ("\t\"%s\"\n", *targs);
382 }
383 printf ("\n");
384 }
385 freeargv (argv);
386 }
387
388 }
389
390 #endif /* MAIN */
This page took 0.038095 seconds and 4 git commands to generate.