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