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    Modified by Akim Demaille so that it can compile out of liberty
6 
7 This file is part of the libiberty library.
8 Libiberty is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12 
13 Libiberty is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 Library General Public License for more details.
17 
18 You should have received a copy of the GNU Library General Public
19 License along with libiberty; see the file COPYING.LIB.  If
20 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22 
23 
24 /*  Create and destroy argument vectors.  An argument vector is simply an
25     array of string pointers, terminated by a NULL pointer. */
26 
27 #if HAVE_CONFIG_H
28 # include <config.h>
29 #endif
30 
31 #ifndef alloca
32 # ifdef __GNUC__
33 #  define alloca __builtin_alloca
34 #  define HAVE_ALLOCA 1
35 # else
36 #  if defined HAVE_ALLOCA_H || defined _LIBC
37 #   include <alloca.h>
38 #  else
39 #   ifdef _AIX
40  #pragma alloca
41 #   else
42 #    ifndef alloca
43 char *alloca ();
44 #    endif
45 #   endif
46 #  endif
47 # endif
48 #endif
49 
50 #if defined STDC_HEADERS || defined _LIBC
51 # include <stdlib.h>
52 #else
53 # ifdef HAVE_MALLOC_H
54 #  include <malloc.h>
55 # else
56 extern void free ();
57 extern void * calloc ();
58 extern void * malloc ();
59 extern void * realloc ();
60 # endif
61 #endif
62 
63 #ifdef HAVE_STRING_H
64 # if !STDC_HEADERS && HAVE_MEMORY_H
65 #  include <memory.h>
66 # endif
67 # include <string.h>
68 #else
69 # include <strings.h>
70 char *memchr ();
71 #endif
72 
73 
74 #include <ctype.h>
75 /* Jim Meyering writes:
76 
77    "... Some ctype macros are valid only for character codes that
78    isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
79    using /bin/cc or gcc but without giving an ansi option).  So, all
80    ctype uses should be through macros like ISPRINT...  If
81    STDC_HEADERS is defined, then autoconf has verified that the ctype
82    macros don't need to be guarded with references to isascii. ...
83    Defining isascii to 1 should let any compiler worth its salt
84    eliminate the && through constant folding."  */
85 
86 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
87 #define ISASCII(c) 1
88 #else
89 #define ISASCII(c) isascii((int) c)
90 #endif
91 
92 #define ISSPACE(c) (ISASCII (c) && isspace   ((int) c))
93 
94 #include "argv.h"
95 
96 #ifndef NULL
97 #define NULL 0
98 #endif
99 
100 #ifndef EOS
101 #define EOS '\0'
102 #endif
103 
104 #define INITIAL_MAXARGC 8	/* Number of args + NULL in initial argv */
105 
106 
107 /* dupargv -- duplicate an argument vector */
108 
109 char **
dupargv(argv)110 dupargv (argv)
111      char **argv;
112 {
113   int argc;
114   char **copy;
115 
116   if (argv == NULL)
117     return NULL;
118 
119   /* the vector */
120   for (argc = 0; argv[argc] != NULL; argc++);
121   copy = (char **) malloc ((argc + 1) * sizeof (char *));
122   if (copy == NULL)
123     return NULL;
124 
125   /* the strings */
126   for (argc = 0; argv[argc] != NULL; argc++)
127     {
128       int len = strlen (argv[argc]);
129       copy[argc] = malloc (sizeof (char *) * (len + 1));
130       if (copy[argc] == NULL)
131 	{
132 	  freeargv (copy);
133 	  return NULL;
134 	}
135       strcpy (copy[argc], argv[argc]);
136     }
137   copy[argc] = NULL;
138   return copy;
139 }
140 
141 /* freeargv -- free an argument vector */
142 
freeargv(vector)143 void freeargv (vector)
144 char **vector;
145 {
146   register char **scan;
147 
148   if (vector != NULL)
149     {
150       for (scan = vector; *scan != NULL; scan++)
151 	{
152 	  free (*scan);
153 	}
154       free (vector);
155     }
156 }
157 
freeargv_from(vector,from)158 void freeargv_from (vector, from)
159 char **vector;
160 int from;
161 {
162   register char **scan;
163 
164   if (vector != NULL)
165     {
166       for (scan = vector ; (from > 0) && (*scan != NULL) ; from--)
167  	scan ++;
168 
169       for (/* nothing */ ; *scan != NULL; scan++)
170 	free (*scan);
171       free (vector);
172     }
173 }
174 
175 /* buildargv -- build an argument vector from a string */
176 
buildargv_argc(input,argc)177 char **buildargv_argc (input, argc)
178   const char *input;
179   int * argc;
180 {
181   char *arg;
182   char *copybuf;
183   int squote = 0;
184   int dquote = 0;
185   int bsquote = 0;
186   int maxargc = 0;
187   char **argv = NULL;
188   char **nargv;
189 
190   if (input != NULL)
191     {
192       copybuf = alloca (strlen (input) + 1);
193       /* Is a do{}while to always execute the loop once.  Always return an
194 	 argv, even for null strings.  See NOTES above, test case below. */
195       do
196 	{
197 	  /* Pick off argv[*argc] */
198 	  while (ISSPACE (*input))
199             input++;
200 	  if ((maxargc == 0) || (*argc >= (maxargc - 1)))
201 	    {
202 	      /* argv needs initialization, or expansion */
203 	      if (argv == NULL)
204 		{
205 		  maxargc = *argc > INITIAL_MAXARGC ? *argc : INITIAL_MAXARGC;
206 		  nargv = (char **) malloc (maxargc * sizeof (char *));
207 		}
208 	      else
209 		{
210 		  maxargc *= 2;
211 		  nargv = (char **) realloc (argv, maxargc * sizeof (char *));
212 		}
213 	      if (nargv == NULL)
214 		{
215 		  if (argv != NULL)
216 		    {
217 		      freeargv (argv);
218 		      argv = NULL;
219 		    }
220 		  break;
221 		}
222 	      argv = nargv;
223 	      argv[*argc] = NULL;
224 	    }
225 	  /* Begin scanning arg */
226 	  arg = copybuf;
227 	  while (*input != EOS)
228 	    {
229 	      if (ISSPACE (*input) && !squote && !dquote && !bsquote)
230 		break;
231 	      else
232 		{
233 		  if (bsquote)
234 		    {
235 		      bsquote = 0;
236 		      *arg++ = *input;
237 		    }
238 		  else if (*input == '\\')
239 		    {
240 		      bsquote = 1;
241 		    }
242 		  else if (squote)
243 		    {
244 		      if (*input == '\'')
245 			squote = 0;
246 		      else
247 			*arg++ = *input;
248 		    }
249 		  else if (dquote)
250 		    {
251 		      if (*input == '"')
252 			dquote = 0;
253 		      else
254 			*arg++ = *input;
255 		    }
256 		  else
257 		    {
258 		      if (*input == '\'')
259 			{
260 			  squote = 1;
261 			}
262 		      else if (*input == '"')
263 			{
264 			  dquote = 1;
265 			}
266 		      else
267 			{
268 			  *arg++ = *input;
269 			}
270 		    }
271 		  input++;
272 		}
273 	    }
274 	  *arg = EOS;
275 	  argv[*argc] = strdup (copybuf);
276 	  if (argv[*argc] == NULL)
277 	    {
278 	      freeargv (argv);
279 	      argv = NULL;
280 	      break;
281 	    }
282 	  (*argc)++;
283 	  argv[*argc] = NULL;
284 
285 	  while (ISSPACE (*input))
286 	    input++;
287 	}
288       while (*input != EOS);
289     }
290   return (argv);
291 }
292 
293 char **
buildargv(const char * string)294 buildargv (const char * string)
295 {
296   int argc = 0;
297   return buildargv_argc (string, &argc);
298 }
299 
300 #ifdef MAIN
301 
302 /* Simple little test driver. */
303 
304 static char *tests[] =
305 {
306   "a simple command line",
307   "arg 'foo' is single quoted",
308   "arg \"bar\" is double quoted",
309   "arg \"foo bar\" has embedded whitespace",
310   "arg 'Jack said \\'hi\\'' has single quotes",
311   "arg 'Jack said \\\"hi\\\"' has double quotes",
312   "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",
313 
314   /* This should be expanded into only one argument.  */
315   "trailing-whitespace ",
316 
317   "",
318   NULL
319 };
320 
main()321 main ()
322 {
323   char **argv;
324   char **test;
325   char **targs;
326 
327   for (test = tests; *test != NULL; test++)
328     {
329       printf ("buildargv(\"%s\")\n", *test);
330       if ((argv = buildargv (*test)) == NULL)
331 	printf ("failed!\n\n");
332       else
333 	{
334 	  for (targs = argv; *targs != NULL; targs++)
335 	    printf ("\t\"%s\"\n", *targs);
336 	  printf ("\n");
337 	}
338       freeargv (argv);
339     }
340 
341 }
342 
343 #endif	/* MAIN */
344