~ubuntu-branches/ubuntu/hoary/binutils/hoary

« back to all changes in this revision

Viewing changes to libiberty/argv.c

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2004-05-19 10:35:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040519103544-17h3o6e8pwndydrg
Tags: 2.14.90.0.7-8
debian/rules: don't use gcc-2.95 on m68k.  Thanks to Adam Conrad for
pointing this out.

Show diffs side-by-side

added added

removed removed

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