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