]> git.ipfire.org Git - thirdparty/gcc.git/blame - libiberty/argv.c
Initial revision
[thirdparty/gcc.git] / libiberty / argv.c
CommitLineData
6599da04
JM
1/* Create and destroy argument vectors (argv's)
2 Copyright (C) 1992 Free Software Foundation, Inc.
3 Written by Fred Fish @ Cygnus Support
4
5This file is part of the libiberty library.
6Libiberty is free software; you can redistribute it and/or
7modify it under the terms of the GNU Library General Public
8License as published by the Free Software Foundation; either
9version 2 of the License, or (at your option) any later version.
10
11Libiberty is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14Library General Public License for more details.
15
16You should have received a copy of the GNU Library General Public
17License along with libiberty; see the file COPYING.LIB. If
18not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, 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>
38extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */
39extern size_t strlen (const char *s); /* 4.11.6.3 */
40extern void *malloc (size_t size); /* 4.10.3.3 */
41extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */
42extern void free (void *ptr); /* 4.10.3.2 */
43extern char *strdup (const char *s); /* Non-ANSI */
44
45#else /* !__STDC__ */
46
47#if !defined _WIN32 || defined __GNUC__
48extern char *memcpy (); /* Copy memory region */
49extern int strlen (); /* Count length of string */
50extern char *malloc (); /* Standard memory allocater */
51extern char *realloc (); /* Standard memory reallocator */
52extern void free (); /* Free malloc'd memory */
53extern 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
73NAME
74
75 freeargv -- free an argument vector
76
77SYNOPSIS
78
79 void freeargv (vector)
80 char **vector;
81
82DESCRIPTION
83
84 Free an argument vector that was built using buildargv. Simply scans
85 through the vector, freeing the memory for each argument until the
86 terminating NULL is found, and then frees the vector itself.
87
88RETURNS
89
90 No value.
91
92*/
93
94void freeargv (vector)
95char **vector;
96{
97 register char **scan;
98
99 if (vector != NULL)
100 {
101 for (scan = vector; *scan != NULL; scan++)
102 {
103 free (*scan);
104 }
105 free (vector);
106 }
107}
108
109/*
110
111NAME
112
113 buildargv -- build an argument vector from a string
114
115SYNOPSIS
116
117 char **buildargv (sp)
118 char *sp;
119
120DESCRIPTION
121
122 Given a pointer to a string, parse the string extracting fields
123 separated by whitespace and optionally enclosed within either single
124 or double quotes (which are stripped off), and build a vector of
125 pointers to copies of the string for each field. The input string
126 remains unchanged.
127
128 All of the memory for the pointer array and copies of the string
129 is obtained from malloc. All of the memory can be returned to the
130 system with the single function call freeargv, which takes the
131 returned result of buildargv, as it's argument.
132
133 The memory for the argv array is dynamically expanded as necessary.
134
135RETURNS
136
137 Returns a pointer to the argument vector if successful. Returns NULL
138 if the input string pointer is NULL or if there is insufficient
139 memory to complete building the argument vector.
140
141NOTES
142
143 In order to provide a working buffer for extracting arguments into,
144 with appropriate stripping of quotes and translation of backslash
145 sequences, we allocate a working buffer at least as long as the input
146 string. This ensures that we always have enough space in which to
147 work, since the extracted arg is never larger than the input string.
148
149 If the input is a null string (as opposed to a NULL pointer), then
150 buildarg returns an argv that has one arg, a null string.
151
152 Argv is always kept terminated with a NULL arg pointer, so it can
153 be passed to freeargv at any time, or returned, as appropriate.
154*/
155
156char **buildargv (input)
157char *input;
158{
159 char *arg;
160 char *copybuf;
161 int squote = 0;
162 int dquote = 0;
163 int bsquote = 0;
164 int argc = 0;
165 int maxargc = 0;
166 char **argv = NULL;
167 char **nargv;
168
169 if (input != NULL)
170 {
171 copybuf = alloca (strlen (input) + 1);
172 /* Is a do{}while to always execute the loop once. Always return an
173 argv, even for null strings. See NOTES above, test case below. */
174 do
175 {
176 /* Pick off argv[argc] */
177 while (isspace (*input))
178 {
179 input++;
180 }
181 if ((maxargc == 0) || (argc >= (maxargc - 1)))
182 {
183 /* argv needs initialization, or expansion */
184 if (argv == NULL)
185 {
186 maxargc = INITIAL_MAXARGC;
187 nargv = (char **) malloc (maxargc * sizeof (char *));
188 }
189 else
190 {
191 maxargc *= 2;
192 nargv = (char **) realloc (argv, maxargc * sizeof (char *));
193 }
194 if (nargv == NULL)
195 {
196 if (argv != NULL)
197 {
198 freeargv (argv);
199 argv = NULL;
200 }
201 break;
202 }
203 argv = nargv;
204 argv[argc] = NULL;
205 }
206 /* Begin scanning arg */
207 arg = copybuf;
208 while (*input != EOS)
209 {
210 if (isspace (*input) && !squote && !dquote && !bsquote)
211 {
212 break;
213 }
214 else
215 {
216 if (bsquote)
217 {
218 bsquote = 0;
219 *arg++ = *input;
220 }
221 else if (*input == '\\')
222 {
223 bsquote = 1;
224 }
225 else if (squote)
226 {
227 if (*input == '\'')
228 {
229 squote = 0;
230 }
231 else
232 {
233 *arg++ = *input;
234 }
235 }
236 else if (dquote)
237 {
238 if (*input == '"')
239 {
240 dquote = 0;
241 }
242 else
243 {
244 *arg++ = *input;
245 }
246 }
247 else
248 {
249 if (*input == '\'')
250 {
251 squote = 1;
252 }
253 else if (*input == '"')
254 {
255 dquote = 1;
256 }
257 else
258 {
259 *arg++ = *input;
260 }
261 }
262 input++;
263 }
264 }
265 *arg = EOS;
266 argv[argc] = strdup (copybuf);
267 if (argv[argc] == NULL)
268 {
269 freeargv (argv);
270 argv = NULL;
271 break;
272 }
273 argc++;
274 argv[argc] = NULL;
275
276 while (isspace (*input))
277 {
278 input++;
279 }
280 }
281 while (*input != EOS);
282 }
283 return (argv);
284}
285
286#ifdef MAIN
287
288/* Simple little test driver. */
289
290static char *tests[] =
291{
292 "a simple command line",
293 "arg 'foo' is single quoted",
294 "arg \"bar\" is double quoted",
295 "arg \"foo bar\" has embedded whitespace",
296 "arg 'Jack said \\'hi\\'' has single quotes",
297 "arg 'Jack said \\\"hi\\\"' has double quotes",
298 "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",
299
300 /* This should be expanded into only one argument. */
301 "trailing-whitespace ",
302
303 "",
304 NULL
305};
306
307main ()
308{
309 char **argv;
310 char **test;
311 char **targs;
312
313 for (test = tests; *test != NULL; test++)
314 {
315 printf ("buildargv(\"%s\")\n", *test);
316 if ((argv = buildargv (*test)) == NULL)
317 {
318 printf ("failed!\n\n");
319 }
320 else
321 {
322 for (targs = argv; *targs != NULL; targs++)
323 {
324 printf ("\t\"%s\"\n", *targs);
325 }
326 printf ("\n");
327 }
328 freeargv (argv);
329 }
330
331}
332
333#endif /* MAIN */