Subversion Repositories Kolibri OS

Rev

Rev 5191 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5191 serge 1
/* Create and destroy argument vectors (argv's)
2
   Copyright (C) 1992, 2001, 2010, 2012 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., 51 Franklin Street - Fifth Floor,
19
Boston, MA 02110-1301, 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
#ifdef HAVE_CONFIG_H
26
#include "config.h"
27
#endif
28
#include "ansidecl.h"
29
#include "libiberty.h"
30
#include "safe-ctype.h"
31
 
32
/*  Routines imported from standard C runtime libraries. */
33
 
34
#include 
35
#include 
36
#include 
37
#include 
38
 
39
#ifndef NULL
40
#define NULL 0
41
#endif
42
 
43
#ifndef EOS
44
#define EOS '\0'
45
#endif
46
 
47
#define INITIAL_MAXARGC 8	/* Number of args + NULL in initial argv */
48
 
49
 
50
/*
51
 
52
@deftypefn Extension char** dupargv (char **@var{vector})
53
 
54
Duplicate an argument vector.  Simply scans through @var{vector},
55
duplicating each argument until the terminating @code{NULL} is found.
56
Returns a pointer to the argument vector if successful.  Returns
57
@code{NULL} if there is insufficient memory to complete building the
58
argument vector.
59
 
60
@end deftypefn
61
 
62
*/
63
 
64
char **
65
dupargv (char **argv)
66
{
67
  int argc;
68
  char **copy;
5199 serge 69
 
5191 serge 70
  if (argv == NULL)
71
    return NULL;
5199 serge 72
 
5191 serge 73
  /* the vector */
74
  for (argc = 0; argv[argc] != NULL; argc++);
75
  copy = (char **) xmalloc ((argc + 1) * sizeof (char *));
76
 
77
  /* the strings */
78
  for (argc = 0; argv[argc] != NULL; argc++)
79
    {
80
      int len = strlen (argv[argc]);
81
      copy[argc] = (char *) xmalloc (len + 1);
82
      strcpy (copy[argc], argv[argc]);
83
    }
84
  copy[argc] = NULL;
85
  return copy;
86
}
87
 
88
/*
89
 
90
@deftypefn Extension void freeargv (char **@var{vector})
91
 
92
Free an argument vector that was built using @code{buildargv}.  Simply
93
scans through @var{vector}, freeing the memory for each argument until
94
the terminating @code{NULL} is found, and then frees @var{vector}
95
itself.
96
 
97
@end deftypefn
98
 
99
*/
100
 
101
void freeargv (char **vector)
102
{
103
  register char **scan;
104
 
105
  if (vector != NULL)
106
    {
107
      for (scan = vector; *scan != NULL; scan++)
108
	{
109
	  free (*scan);
110
	}
111
      free (vector);
112
    }
113
}
114
 
115
static void
116
consume_whitespace (const char **input)
117
{
118
  while (ISSPACE (**input))
119
    {
120
      (*input)++;
121
    }
122
}
123
 
124
static int
125
only_whitespace (const char* input)
126
{
127
  while (*input != EOS && ISSPACE (*input))
128
    input++;
129
 
130
  return (*input == EOS);
131
}
132
 
133
/*
134
 
135
@deftypefn Extension char** buildargv (char *@var{sp})
136
 
137
Given a pointer to a string, parse the string extracting fields
138
separated by whitespace and optionally enclosed within either single
139
or double quotes (which are stripped off), and build a vector of
140
pointers to copies of the string for each field.  The input string
141
remains unchanged.  The last element of the vector is followed by a
142
@code{NULL} element.
143
 
144
All of the memory for the pointer array and copies of the string
145
is obtained from @code{xmalloc}.  All of the memory can be returned to the
146
system with the single function call @code{freeargv}, which takes the
147
returned result of @code{buildargv}, as it's argument.
148
 
149
Returns a pointer to the argument vector if successful.  Returns
150
@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
151
memory to complete building the argument vector.
152
 
153
If the input is a null string (as opposed to a @code{NULL} pointer),
154
then buildarg returns an argument vector that has one arg, a null
155
string.
156
 
157
@end deftypefn
158
 
159
The memory for the argv array is dynamically expanded as necessary.
160
 
161
In order to provide a working buffer for extracting arguments into,
162
with appropriate stripping of quotes and translation of backslash
163
sequences, we allocate a working buffer at least as long as the input
164
string.  This ensures that we always have enough space in which to
165
work, since the extracted arg is never larger than the input string.
166
 
167
The argument vector is always kept terminated with a @code{NULL} arg
168
pointer, so it can be passed to @code{freeargv} at any time, or
169
returned, as appropriate.
170
 
171
*/
172
 
173
char **buildargv (const char *input)
174
{
175
  char *arg;
176
  char *copybuf;
177
  int squote = 0;
178
  int dquote = 0;
179
  int bsquote = 0;
180
  int argc = 0;
181
  int maxargc = 0;
182
  char **argv = NULL;
183
  char **nargv;
184
 
185
  if (input != NULL)
186
    {
187
      copybuf = (char *) xmalloc (strlen (input) + 1);
188
      /* Is a do{}while to always execute the loop once.  Always return an
189
	 argv, even for null strings.  See NOTES above, test case below. */
190
      do
191
	{
192
	  /* Pick off argv[argc] */
193
	  consume_whitespace (&input);
194
 
195
	  if ((maxargc == 0) || (argc >= (maxargc - 1)))
196
	    {
197
	      /* argv needs initialization, or expansion */
198
	      if (argv == NULL)
199
		{
200
		  maxargc = INITIAL_MAXARGC;
201
		  nargv = (char **) xmalloc (maxargc * sizeof (char *));
202
		}
203
	      else
204
		{
205
		  maxargc *= 2;
206
		  nargv = (char **) xrealloc (argv, maxargc * sizeof (char *));
207
		}
208
	      argv = nargv;
209
	      argv[argc] = NULL;
210
	    }
211
	  /* Begin scanning arg */
212
	  arg = copybuf;
213
	  while (*input != EOS)
214
	    {
215
	      if (ISSPACE (*input) && !squote && !dquote && !bsquote)
216
		{
217
		  break;
218
		}
219
	      else
220
		{
221
		  if (bsquote)
222
		    {
223
		      bsquote = 0;
224
		      *arg++ = *input;
225
		    }
226
		  else if (*input == '\\')
227
		    {
228
		      bsquote = 1;
229
		    }
230
		  else if (squote)
231
		    {
232
		      if (*input == '\'')
233
			{
234
			  squote = 0;
235
			}
236
		      else
237
			{
238
			  *arg++ = *input;
239
			}
240
		    }
241
		  else if (dquote)
242
		    {
243
		      if (*input == '"')
244
			{
245
			  dquote = 0;
246
			}
247
		      else
248
			{
249
			  *arg++ = *input;
250
			}
251
		    }
252
		  else
253
		    {
254
		      if (*input == '\'')
255
			{
256
			  squote = 1;
257
			}
258
		      else if (*input == '"')
259
			{
260
			  dquote = 1;
261
			}
262
		      else
263
			{
264
			  *arg++ = *input;
265
			}
266
		    }
267
		  input++;
268
		}
269
	    }
270
	  *arg = EOS;
271
	  argv[argc] = xstrdup (copybuf);
272
	  argc++;
273
	  argv[argc] = NULL;
274
 
275
	  consume_whitespace (&input);
276
	}
277
      while (*input != EOS);
278
 
279
      free (copybuf);
280
    }
281
  return (argv);
282
}
283
 
284
/*
285
 
286
@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@var{file})
287
 
288
Write each member of ARGV, handling all necessary quoting, to the file
289
named by FILE, separated by whitespace.  Return 0 on success, non-zero
290
if an error occurred while writing to FILE.
291
 
292
@end deftypefn
293
 
294
*/
295
 
296
int
297
writeargv (char **argv, FILE *f)
298
{
299
  int status = 0;
300
 
301
  if (f == NULL)
302
    return 1;
303
 
304
  while (*argv != NULL)
305
    {
306
      const char *arg = *argv;
307
 
308
      while (*arg != EOS)
309
        {
310
          char c = *arg;
311
 
312
          if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
313
            if (EOF == fputc ('\\', f))
314
              {
315
                status = 1;
316
                goto done;
317
              }
318
 
319
          if (EOF == fputc (c, f))
320
            {
321
              status = 1;
322
              goto done;
323
            }
324
          arg++;
325
        }
326
 
327
      if (EOF == fputc ('\n', f))
328
        {
329
          status = 1;
330
          goto done;
331
        }
332
      argv++;
333
    }
334
 
335
 done:
336
  return status;
337
}
338
 
339
/*
340
 
341
@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
342
 
343
The @var{argcp} and @code{argvp} arguments are pointers to the usual
344
@code{argc} and @code{argv} arguments to @code{main}.  This function
345
looks for arguments that begin with the character @samp{@@}.  Any such
346
arguments are interpreted as ``response files''.  The contents of the
347
response file are interpreted as additional command line options.  In
348
particular, the file is separated into whitespace-separated strings;
349
each such string is taken as a command-line option.  The new options
350
are inserted in place of the option naming the response file, and
351
@code{*argcp} and @code{*argvp} will be updated.  If the value of
352
@code{*argvp} is modified by this function, then the new value has
353
been dynamically allocated and can be deallocated by the caller with
354
@code{freeargv}.  However, most callers will simply call
355
@code{expandargv} near the beginning of @code{main} and allow the
356
operating system to free the memory when the program exits.
357
 
358
@end deftypefn
359
 
360
*/
361
 
362
void
363
expandargv (int *argcp, char ***argvp)
364
{
365
  /* The argument we are currently processing.  */
366
  int i = 0;
367
  /* Non-zero if ***argvp has been dynamically allocated.  */
368
  int argv_dynamic = 0;
369
  /* Limit the number of response files that we parse in order
370
     to prevent infinite recursion.  */
371
  unsigned int iteration_limit = 2000;
372
  /* Loop over the arguments, handling response files.  We always skip
373
     ARGVP[0], as that is the name of the program being run.  */
374
  while (++i < *argcp)
375
    {
376
      /* The name of the response file.  */
377
      const char *filename;
378
      /* The response file.  */
379
      FILE *f;
380
      /* An upper bound on the number of characters in the response
381
	 file.  */
382
      long pos;
383
      /* The number of characters in the response file, when actually
384
	 read.  */
385
      size_t len;
386
      /* A dynamically allocated buffer used to hold options read from a
387
	 response file.  */
388
      char *buffer;
389
      /* Dynamically allocated storage for the options read from the
390
	 response file.  */
391
      char **file_argv;
392
      /* The number of options read from the response file, if any.  */
393
      size_t file_argc;
394
      /* We are only interested in options of the form "@file".  */
395
      filename = (*argvp)[i];
396
      if (filename[0] != '@')
397
	continue;
398
      /* If we have iterated too many times then stop.  */
399
      if (-- iteration_limit == 0)
400
	{
401
	  fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]);
402
	  xexit (1);
403
	}
404
      /* Read the contents of the file.  */
405
      f = fopen (++filename, "r");
406
      if (!f)
407
	continue;
408
      if (fseek (f, 0L, SEEK_END) == -1)
409
	goto error;
410
      pos = ftell (f);
411
      if (pos == -1)
412
	goto error;
413
      if (fseek (f, 0L, SEEK_SET) == -1)
414
	goto error;
415
      buffer = (char *) xmalloc (pos * sizeof (char) + 1);
416
      len = fread (buffer, sizeof (char), pos, f);
417
      if (len != (size_t) pos
418
	  /* On Windows, fread may return a value smaller than POS,
419
	     due to CR/LF->CR translation when reading text files.
420
	     That does not in-and-of itself indicate failure.  */
421
	  && ferror (f))
422
	goto error;
423
      /* Add a NUL terminator.  */
424
      buffer[len] = '\0';
425
      /* If the file is empty or contains only whitespace, buildargv would
426
	 return a single empty argument.  In this context we want no arguments,
427
	 instead.  */
428
      if (only_whitespace (buffer))
429
	{
430
	  file_argv = (char **) xmalloc (sizeof (char *));
431
	  file_argv[0] = NULL;
432
	}
433
      else
434
	/* Parse the string.  */
435
	file_argv = buildargv (buffer);
436
      /* If *ARGVP is not already dynamically allocated, copy it.  */
437
      if (!argv_dynamic)
438
	*argvp = dupargv (*argvp);
439
      /* Count the number of arguments.  */
440
      file_argc = 0;
441
      while (file_argv[file_argc])
442
	++file_argc;
443
      /* Now, insert FILE_ARGV into ARGV.  The "+1" below handles the
5199 serge 444
	 NULL terminator at the end of ARGV.  */
445
      *argvp = ((char **)
446
		xrealloc (*argvp,
5191 serge 447
			  (*argcp + file_argc + 1) * sizeof (char *)));
5199 serge 448
      memmove (*argvp + i + file_argc, *argvp + i + 1,
5191 serge 449
	       (*argcp - i) * sizeof (char *));
450
      memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
451
      /* The original option has been replaced by all the new
452
	 options.  */
453
      *argcp += file_argc - 1;
454
      /* Free up memory allocated to process the response file.  We do
455
	 not use freeargv because the individual options in FILE_ARGV
456
	 are now in the main ARGV.  */
457
      free (file_argv);
458
      free (buffer);
459
      /* Rescan all of the arguments just read to support response
460
	 files that include other response files.  */
461
      --i;
462
    error:
463
      /* We're all done with the file now.  */
464
      fclose (f);
465
    }
466
}
467
 
468
/*
469
 
470
@deftypefn Extension int countargv (char **@var{argv})
471
 
472
Return the number of elements in @var{argv}.
473
Returns zero if @var{argv} is NULL.
474
 
475
@end deftypefn
476
 
477
*/
478
 
479
int
480
countargv (char **argv)
481
{
482
  int argc;
483
 
484
  if (argv == NULL)
485
    return 0;
486
  for (argc = 0; argv[argc] != NULL; argc++)
487
    continue;
488
  return argc;
489
}
490
 
491
#ifdef MAIN
492
 
493
/* Simple little test driver. */
494
 
495
static const char *const tests[] =
496
{
497
  "a simple command line",
498
  "arg 'foo' is single quoted",
499
  "arg \"bar\" is double quoted",
500
  "arg \"foo bar\" has embedded whitespace",
501
  "arg 'Jack said \\'hi\\'' has single quotes",
502
  "arg 'Jack said \\\"hi\\\"' has double quotes",
503
  "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",
5199 serge 504
 
5191 serge 505
  /* This should be expanded into only one argument.  */
506
  "trailing-whitespace ",
507
 
508
  "",
509
  NULL
510
};
511
 
512
int
513
main (void)
514
{
515
  char **argv;
516
  const char *const *test;
517
  char **targs;
518
 
519
  for (test = tests; *test != NULL; test++)
520
    {
521
      printf ("buildargv(\"%s\")\n", *test);
522
      if ((argv = buildargv (*test)) == NULL)
523
	{
524
	  printf ("failed!\n\n");
525
	}
526
      else
527
	{
528
	  for (targs = argv; *targs != NULL; targs++)
529
	    {
530
	      printf ("\t\"%s\"\n", *targs);
531
	    }
532
	  printf ("\n");
533
	}
534
      freeargv (argv);
535
    }
536
 
537
  return 0;
538
}
539
 
540
#endif	/* MAIN */