|
|
1.1 root 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., 675 Mass Ave,
19: Cambridge, MA 02139, 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: /* AIX requires this to be the first thing in the file. */
26: #ifdef __GNUC__
27: #define alloca __builtin_alloca
28: #else /* not __GNUC__ */
29: #ifdef sparc
30: #include <alloca.h>
31: extern char *__builtin_alloca(); /* Stupid include file doesn't declare it */
32: #else
33: #ifdef _AIX
34: #pragma alloca
35: #else
36: char *alloca ();
37: #endif
38: #endif /* sparc */
39: #endif /* not __GNUC__ */
40:
41: #define isspace(ch) ((ch) == ' ' || (ch) == '\t')
42:
43: #include "alloca-conf.h"
44:
45: /* Routines imported from standard C runtime libraries. */
46:
47: #ifdef __STDC__
48:
49: #include <stddef.h>
50: extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */
51: extern size_t strlen (const char *s); /* 4.11.6.3 */
52: extern void *malloc (size_t size); /* 4.10.3.3 */
53: extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */
54: extern void free (void *ptr); /* 4.10.3.2 */
55: extern char *strdup (const char *s); /* Non-ANSI */
56:
57: #else /* !__STDC__ */
58:
59: extern char *memcpy (); /* Copy memory region */
60: extern int strlen (); /* Count length of string */
61: extern char *malloc (); /* Standard memory allocater */
62: extern char *realloc (); /* Standard memory reallocator */
63: extern void free (); /* Free malloc'd memory */
64: extern char *strdup (); /* Duplicate a string */
65:
66: #endif /* __STDC__ */
67:
68: #ifndef NULL
69: #define NULL 0
70: #endif
71:
72: #ifndef EOS
73: #define EOS '\0'
74: #endif
75:
76: #define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
77:
78:
79: /*
80:
81: NAME
82:
83: freeargv -- free an argument vector
84:
85: SYNOPSIS
86:
87: void freeargv (vector)
88: char **vector;
89:
90: DESCRIPTION
91:
92: Free an argument vector that was built using buildargv. Simply scans
93: through the vector, freeing the memory for each argument until the
94: terminating NULL is found, and then frees the vector itself.
95:
96: RETURNS
97:
98: No value.
99:
100: */
101:
102: void freeargv (vector)
103: char **vector;
104: {
105: register char **scan;
106:
107: if (vector != NULL)
108: {
109: for (scan = vector; *scan != NULL; scan++)
110: {
111: free (*scan);
112: }
113: free (vector);
114: }
115: }
116:
117: /*
118:
119: NAME
120:
121: buildargv -- build an argument vector from a string
122:
123: SYNOPSIS
124:
125: char **buildargv (sp)
126: char *sp;
127:
128: DESCRIPTION
129:
130: Given a pointer to a string, parse the string extracting fields
131: separated by whitespace and optionally enclosed within either single
132: or double quotes (which are stripped off), and build a vector of
133: pointers to copies of the string for each field. The input string
134: remains unchanged.
135:
136: All of the memory for the pointer array and copies of the string
137: is obtained from malloc. All of the memory can be returned to the
138: system with the single function call freeargv, which takes the
139: returned result of buildargv, as it's argument.
140:
141: The memory for the argv array is dynamically expanded as necessary.
142:
143: RETURNS
144:
145: Returns a pointer to the argument vector if successful. Returns NULL
146: if the input string pointer is NULL or if there is insufficient
147: memory to complete building the argument vector.
148:
149: NOTES
150:
151: In order to provide a working buffer for extracting arguments into,
152: with appropriate stripping of quotes and translation of backslash
153: sequences, we allocate a working buffer at least as long as the input
154: string. This ensures that we always have enough space in which to
155: work, since the extracted arg is never larger than the input string.
156:
157: If the input is a null string (as opposed to a NULL pointer), then
158: buildarg returns an argv that has one arg, a null string.
159:
160: Argv is always kept terminated with a NULL arg pointer, so it can
161: be passed to freeargv at any time, or returned, as appropriate.
162: */
163:
164: char **buildargv (input)
165: char *input;
166: {
167: char *arg;
168: char *copybuf;
169: int squote = 0;
170: int dquote = 0;
171: int bsquote = 0;
172: int argc = 0;
173: int maxargc = 0;
174: char **argv = NULL;
175: char **nargv;
176:
177: if (input != NULL)
178: {
179: copybuf = alloca (strlen (input) + 1);
180: /* Is a do{}while to always execute the loop once. Always return an
181: argv, even for null strings. See NOTES above, test case below. */
182: do
183: {
184: /* Pick off argv[argc] */
185: while (isspace (*input))
186: {
187: input++;
188: }
189: if ((maxargc == 0) || (argc >= (maxargc - 1)))
190: {
191: /* argv needs initialization, or expansion */
192: if (argv == NULL)
193: {
194: maxargc = INITIAL_MAXARGC;
195: nargv = (char **) malloc (maxargc * sizeof (char *));
196: }
197: else
198: {
199: maxargc *= 2;
200: nargv = (char **) realloc (argv, maxargc * sizeof (char *));
201: }
202: if (nargv == NULL)
203: {
204: if (argv != NULL)
205: {
206: freeargv (argv);
207: argv = NULL;
208: }
209: break;
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;
274: argv[argc] = strdup (copybuf);
275: if (argv[argc] == NULL)
276: {
277: freeargv (argv);
278: argv = NULL;
279: break;
280: }
281: argc++;
282: argv[argc] = NULL;
283: }
284: while (*input != EOS);
285: }
286: return (argv);
287: }
288:
289: #ifdef MAIN
290:
291: /* Simple little test driver. */
292:
293: static char *tests[] =
294: {
295: "a simple command line",
296: "arg 'foo' is single quoted",
297: "arg \"bar\" is double quoted",
298: "arg \"foo bar\" has embedded whitespace",
299: "arg 'Jack said \\'hi\\'' has single quotes",
300: "arg 'Jack said \\\"hi\\\"' has double quotes",
301: "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",
302: "",
303: NULL
304: };
305:
306: main ()
307: {
308: char **argv;
309: char **test;
310: char **targs;
311:
312: for (test = tests; *test != NULL; test++)
313: {
314: printf ("buildargv(\"%s\")\n", *test);
315: if ((argv = buildargv (*test)) == NULL)
316: {
317: printf ("failed!\n\n");
318: }
319: else
320: {
321: for (targs = argv; *targs != NULL; targs++)
322: {
323: printf ("\t\"%s\"\n", *targs);
324: }
325: printf ("\n");
326: }
327: freeargv (argv);
328: }
329:
330: }
331:
332: #endif /* MAIN */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.