OSDN Git Service

824a02988363a30b0fc98e5f0e370825d315afb9
[pf3gnuchains/gcc-fork.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 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 = 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 */