1 /* $Id: buildargv.c,v 1.2 2006/02/27 03:17:51 rockyb Exp $ */
2 /* Create and destroy argument vectors (argv's)
3    Copyright (C) 1992, 2001 Free Software Foundation, Inc.
4    Written by Fred Fish @ Cygnus Support
5 
6    Copyright (C) 2008 R. Bernstein rocky@gnu.org
7 
8 This file is part of the libiberty library.
9 Libiberty is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Library General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13 
14 Libiberty is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 Library General Public License for more details.
18 
19 You should have received a copy of the GNU Library General Public
20 License along with libiberty; see the file COPYING.LIB.  If
21 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23 
24 /* rocky: Below we only need/use the freeargv and buildargv routine
25    from the above.  Some small adaption was made to include outside of
26    libiberty.
27 */
28 #include <ctype.h>
29 #ifdef HAVE_ALLOCA_H
30 #include <alloca.h>
31 #endif
32 #include <string.h>
33 #include <stdlib.h>
34 #include "buildargv.h"
35 
36 #ifndef EOS
37 #define EOS '\0'
38 #endif
39 
40 #define INITIAL_MAXARGC 8	/* Number of args + NULL in initial argv */
41 #define ISBLANK(ch) ((ch) == ' ' || (ch) == '\t')
42 
43 /*
44 
45 @deftypefn Extension void freeargv (char **@var{vector})
46 
47 Free an argument vector that was built using @code{buildargv}.  Simply
48 scans through @var{vector}, freeing the memory for each argument until
49 the terminating @code{NULL} is found, and then frees @var{vector}
50 itself.
51 
52 @end deftypefn
53 
54 */
55 
freeargv(vector)56 void freeargv (vector)
57 char **vector;
58 {
59   register char **scan;
60 
61   if (vector != NULL)
62     {
63       for (scan = vector; *scan != NULL; scan++)
64 	{
65 	  free (*scan);
66 	}
67       free (vector);
68     }
69 }
70 
71 /*
72 
73 @deftypefn Extension char** buildargv (char *@var{sp})
74 
75 Given a pointer to a string, parse the string extracting fields
76 separated by whitespace and optionally enclosed within either single
77 or double quotes (which are stripped off), and build a vector of
78 pointers to copies of the string for each field.  The input string
79 remains unchanged.  The last element of the vector is followed by a
80 @code{NULL} element.
81 
82 All of the memory for the pointer array and copies of the string
83 is obtained from @code{malloc}.  All of the memory can be returned to the
84 system with the single function call @code{freeargv}, which takes the
85 returned result of @code{buildargv}, as it's argument.
86 
87 Returns a pointer to the argument vector if successful.  Returns
88 @code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
89 memory to complete building the argument vector.
90 
91 If the input is a null string (as opposed to a @code{NULL} pointer),
92 then buildarg returns an argument vector that has one arg, a null
93 string.
94 
95 @end deftypefn
96 
97 The memory for the argv array is dynamically expanded as necessary.
98 
99 In order to provide a working buffer for extracting arguments into,
100 with appropriate stripping of quotes and translation of backslash
101 sequences, we allocate a working buffer at least as long as the input
102 string.  This ensures that we always have enough space in which to
103 work, since the extracted arg is never larger than the input string.
104 
105 The argument vector is always kept terminated with a @code{NULL} arg
106 pointer, so it can be passed to @code{freeargv} at any time, or
107 returned, as appropriate.
108 
109 */
110 
buildargv(input)111 char **buildargv (input)
112      const char *input;
113 {
114   char *arg;
115   char *copybuf;
116   int squote = 0;
117   int dquote = 0;
118   int bsquote = 0;
119   int argc = 0;
120   int maxargc = 0;
121   char **argv = NULL;
122   char **nargv;
123 
124   if (input != NULL)
125     {
126       copybuf = (char *) alloca (strlen (input) + 1);
127       /* Is a do{}while to always execute the loop once.  Always return an
128 	 argv, even for null strings.  See NOTES above, test case below. */
129       do
130 	{
131 	  /* Pick off argv[argc] */
132 	  while (ISBLANK (*input))
133 	    {
134 	      input++;
135 	    }
136 	  if ((maxargc == 0) || (argc >= (maxargc - 1)))
137 	    {
138 	      /* argv needs initialization, or expansion */
139 	      if (argv == NULL)
140 		{
141 		  maxargc = INITIAL_MAXARGC;
142 		  nargv = (char **) malloc (maxargc * sizeof (char *));
143 		}
144 	      else
145 		{
146 		  maxargc *= 2;
147 		  nargv = (char **) realloc (argv, maxargc * sizeof (char *));
148 		}
149 	      if (nargv == NULL)
150 		{
151 		  if (argv != NULL)
152 		    {
153 		      freeargv (argv);
154 		      argv = NULL;
155 		    }
156 		  break;
157 		}
158 	      argv = nargv;
159 	      argv[argc] = NULL;
160 	    }
161 	  /* Begin scanning arg */
162 	  arg = copybuf;
163 	  while (*input != EOS)
164 	    {
165 	      if (ISBLANK (*input) && !squote && !dquote && !bsquote)
166 		{
167 		  break;
168 		}
169 	      else
170 		{
171 		  if (bsquote)
172 		    {
173 		      bsquote = 0;
174 		      *arg++ = *input;
175 		    }
176 		  else if (*input == '\\')
177 		    {
178 		      bsquote = 1;
179 		    }
180 		  else if (squote)
181 		    {
182 		      if (*input == '\'')
183 			{
184 			  squote = 0;
185 			}
186 		      else
187 			{
188 			  *arg++ = *input;
189 			}
190 		    }
191 		  else if (dquote)
192 		    {
193 		      if (*input == '"')
194 			{
195 			  dquote = 0;
196 			}
197 		      else
198 			{
199 			  *arg++ = *input;
200 			}
201 		    }
202 		  else
203 		    {
204 		      if (*input == '\'')
205 			{
206 			  squote = 1;
207 			}
208 		      else if (*input == '"')
209 			{
210 			  dquote = 1;
211 			}
212 		      else
213 			{
214 			  *arg++ = *input;
215 			}
216 		    }
217 		  input++;
218 		}
219 	    }
220 	  *arg = EOS;
221 	  argv[argc] = strdup (copybuf);
222 	  if (argv[argc] == NULL)
223 	    {
224 	      freeargv (argv);
225 	      argv = NULL;
226 	      break;
227 	    }
228 	  argc++;
229 	  argv[argc] = NULL;
230 
231 	  while (ISBLANK (*input))
232 	    {
233 	      input++;
234 	    }
235 	}
236       while (*input != EOS);
237     }
238   return (argv);
239 }
240