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