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