OSDN Git Service

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