133965Sjdp/* Create and destroy argument vectors (argv's) 289857Sobrien Copyright (C) 1992, 2001 Free Software Foundation, Inc. 333965Sjdp Written by Fred Fish @ Cygnus Support 433965Sjdp 533965SjdpThis file is part of the libiberty library. 633965SjdpLibiberty is free software; you can redistribute it and/or 733965Sjdpmodify it under the terms of the GNU Library General Public 833965SjdpLicense as published by the Free Software Foundation; either 933965Sjdpversion 2 of the License, or (at your option) any later version. 1033965Sjdp 1133965SjdpLibiberty is distributed in the hope that it will be useful, 1233965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of 1333965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1433965SjdpLibrary General Public License for more details. 1533965Sjdp 1633965SjdpYou should have received a copy of the GNU Library General Public 1733965SjdpLicense along with libiberty; see the file COPYING.LIB. If 18218822Sdimnot, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 19218822SdimBoston, MA 02110-1301, USA. */ 2033965Sjdp 2133965Sjdp 2233965Sjdp/* Create and destroy argument vectors. An argument vector is simply an 2333965Sjdp array of string pointers, terminated by a NULL pointer. */ 2433965Sjdp 25218822Sdim#ifdef HAVE_CONFIG_H 26218822Sdim#include "config.h" 27218822Sdim#endif 2833965Sjdp#include "ansidecl.h" 2933965Sjdp#include "libiberty.h" 30218822Sdim#include "safe-ctype.h" 3133965Sjdp 3233965Sjdp/* Routines imported from standard C runtime libraries. */ 3333965Sjdp 3433965Sjdp#include <stddef.h> 3560484Sobrien#include <string.h> 3660484Sobrien#include <stdlib.h> 37218822Sdim#include <stdio.h> 3833965Sjdp 3933965Sjdp#ifndef NULL 4033965Sjdp#define NULL 0 4133965Sjdp#endif 4233965Sjdp 4333965Sjdp#ifndef EOS 4433965Sjdp#define EOS '\0' 4533965Sjdp#endif 4633965Sjdp 4733965Sjdp#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ 4833965Sjdp 4933965Sjdp 5033965Sjdp/* 5133965Sjdp 5289857Sobrien@deftypefn Extension char** dupargv (char **@var{vector}) 5333965Sjdp 5489857SobrienDuplicate an argument vector. Simply scans through @var{vector}, 5589857Sobrienduplicating each argument until the terminating @code{NULL} is found. 5689857SobrienReturns a pointer to the argument vector if successful. Returns 5789857Sobrien@code{NULL} if there is insufficient memory to complete building the 5889857Sobrienargument vector. 5938889Sjdp 6089857Sobrien@end deftypefn 6138889Sjdp 6238889Sjdp*/ 6338889Sjdp 6438889Sjdpchar ** 65218822Sdimdupargv (char **argv) 6638889Sjdp{ 6738889Sjdp int argc; 6838889Sjdp char **copy; 6938889Sjdp 7038889Sjdp if (argv == NULL) 7138889Sjdp return NULL; 7238889Sjdp 7338889Sjdp /* the vector */ 7438889Sjdp for (argc = 0; argv[argc] != NULL; argc++); 7538889Sjdp copy = (char **) malloc ((argc + 1) * sizeof (char *)); 7638889Sjdp if (copy == NULL) 7738889Sjdp return NULL; 7838889Sjdp 7938889Sjdp /* the strings */ 8038889Sjdp for (argc = 0; argv[argc] != NULL; argc++) 8138889Sjdp { 8238889Sjdp int len = strlen (argv[argc]); 83218822Sdim copy[argc] = (char *) malloc (len + 1); 8438889Sjdp if (copy[argc] == NULL) 8538889Sjdp { 8638889Sjdp freeargv (copy); 8738889Sjdp return NULL; 8838889Sjdp } 8938889Sjdp strcpy (copy[argc], argv[argc]); 9038889Sjdp } 9138889Sjdp copy[argc] = NULL; 9238889Sjdp return copy; 9338889Sjdp} 9438889Sjdp 9538889Sjdp/* 9638889Sjdp 9789857Sobrien@deftypefn Extension void freeargv (char **@var{vector}) 9838889Sjdp 9989857SobrienFree an argument vector that was built using @code{buildargv}. Simply 10089857Sobrienscans through @var{vector}, freeing the memory for each argument until 10189857Sobrienthe terminating @code{NULL} is found, and then frees @var{vector} 10289857Sobrienitself. 10333965Sjdp 10489857Sobrien@end deftypefn 10533965Sjdp 10633965Sjdp*/ 10733965Sjdp 108218822Sdimvoid freeargv (char **vector) 10933965Sjdp{ 11033965Sjdp register char **scan; 11133965Sjdp 11233965Sjdp if (vector != NULL) 11333965Sjdp { 11433965Sjdp for (scan = vector; *scan != NULL; scan++) 11533965Sjdp { 11633965Sjdp free (*scan); 11733965Sjdp } 11833965Sjdp free (vector); 11933965Sjdp } 12033965Sjdp} 12133965Sjdp 12233965Sjdp/* 12333965Sjdp 12489857Sobrien@deftypefn Extension char** buildargv (char *@var{sp}) 12533965Sjdp 12689857SobrienGiven a pointer to a string, parse the string extracting fields 12789857Sobrienseparated by whitespace and optionally enclosed within either single 12889857Sobrienor double quotes (which are stripped off), and build a vector of 12989857Sobrienpointers to copies of the string for each field. The input string 13089857Sobrienremains unchanged. The last element of the vector is followed by a 13189857Sobrien@code{NULL} element. 13233965Sjdp 13389857SobrienAll of the memory for the pointer array and copies of the string 13489857Sobrienis obtained from @code{malloc}. All of the memory can be returned to the 13589857Sobriensystem with the single function call @code{freeargv}, which takes the 13689857Sobrienreturned result of @code{buildargv}, as it's argument. 13733965Sjdp 13889857SobrienReturns a pointer to the argument vector if successful. Returns 13989857Sobrien@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient 14089857Sobrienmemory to complete building the argument vector. 14133965Sjdp 14289857SobrienIf the input is a null string (as opposed to a @code{NULL} pointer), 14389857Sobrienthen buildarg returns an argument vector that has one arg, a null 14489857Sobrienstring. 14533965Sjdp 14689857Sobrien@end deftypefn 14733965Sjdp 14889857SobrienThe memory for the argv array is dynamically expanded as necessary. 14933965Sjdp 15089857SobrienIn order to provide a working buffer for extracting arguments into, 15189857Sobrienwith appropriate stripping of quotes and translation of backslash 15289857Sobriensequences, we allocate a working buffer at least as long as the input 15389857Sobrienstring. This ensures that we always have enough space in which to 15489857Sobrienwork, since the extracted arg is never larger than the input string. 15533965Sjdp 15689857SobrienThe argument vector is always kept terminated with a @code{NULL} arg 15789857Sobrienpointer, so it can be passed to @code{freeargv} at any time, or 15889857Sobrienreturned, as appropriate. 15933965Sjdp 16033965Sjdp*/ 16133965Sjdp 162218822Sdimchar **buildargv (const char *input) 16333965Sjdp{ 16433965Sjdp char *arg; 16533965Sjdp char *copybuf; 16633965Sjdp int squote = 0; 16733965Sjdp int dquote = 0; 16833965Sjdp int bsquote = 0; 16933965Sjdp int argc = 0; 17033965Sjdp int maxargc = 0; 17133965Sjdp char **argv = NULL; 17233965Sjdp char **nargv; 17333965Sjdp 17433965Sjdp if (input != NULL) 17533965Sjdp { 17660484Sobrien copybuf = (char *) alloca (strlen (input) + 1); 17733965Sjdp /* Is a do{}while to always execute the loop once. Always return an 17833965Sjdp argv, even for null strings. See NOTES above, test case below. */ 17933965Sjdp do 18033965Sjdp { 18133965Sjdp /* Pick off argv[argc] */ 18277298Sobrien while (ISBLANK (*input)) 18333965Sjdp { 18433965Sjdp input++; 18533965Sjdp } 18633965Sjdp if ((maxargc == 0) || (argc >= (maxargc - 1))) 18733965Sjdp { 18833965Sjdp /* argv needs initialization, or expansion */ 18933965Sjdp if (argv == NULL) 19033965Sjdp { 19133965Sjdp maxargc = INITIAL_MAXARGC; 19233965Sjdp nargv = (char **) malloc (maxargc * sizeof (char *)); 19333965Sjdp } 19433965Sjdp else 19533965Sjdp { 19633965Sjdp maxargc *= 2; 19733965Sjdp nargv = (char **) realloc (argv, maxargc * sizeof (char *)); 19833965Sjdp } 19933965Sjdp if (nargv == NULL) 20033965Sjdp { 20133965Sjdp if (argv != NULL) 20233965Sjdp { 20333965Sjdp freeargv (argv); 20433965Sjdp argv = NULL; 20533965Sjdp } 20633965Sjdp break; 20733965Sjdp } 20833965Sjdp argv = nargv; 20933965Sjdp argv[argc] = NULL; 21033965Sjdp } 21133965Sjdp /* Begin scanning arg */ 21233965Sjdp arg = copybuf; 21333965Sjdp while (*input != EOS) 21433965Sjdp { 215218822Sdim if (ISSPACE (*input) && !squote && !dquote && !bsquote) 21633965Sjdp { 21733965Sjdp break; 21833965Sjdp } 21933965Sjdp else 22033965Sjdp { 22133965Sjdp if (bsquote) 22233965Sjdp { 22333965Sjdp bsquote = 0; 22433965Sjdp *arg++ = *input; 22533965Sjdp } 22633965Sjdp else if (*input == '\\') 22733965Sjdp { 22833965Sjdp bsquote = 1; 22933965Sjdp } 23033965Sjdp else if (squote) 23133965Sjdp { 23233965Sjdp if (*input == '\'') 23333965Sjdp { 23433965Sjdp squote = 0; 23533965Sjdp } 23633965Sjdp else 23733965Sjdp { 23833965Sjdp *arg++ = *input; 23933965Sjdp } 24033965Sjdp } 24133965Sjdp else if (dquote) 24233965Sjdp { 24333965Sjdp if (*input == '"') 24433965Sjdp { 24533965Sjdp dquote = 0; 24633965Sjdp } 24733965Sjdp else 24833965Sjdp { 24933965Sjdp *arg++ = *input; 25033965Sjdp } 25133965Sjdp } 25233965Sjdp else 25333965Sjdp { 25433965Sjdp if (*input == '\'') 25533965Sjdp { 25633965Sjdp squote = 1; 25733965Sjdp } 25833965Sjdp else if (*input == '"') 25933965Sjdp { 26033965Sjdp dquote = 1; 26133965Sjdp } 26233965Sjdp else 26333965Sjdp { 26433965Sjdp *arg++ = *input; 26533965Sjdp } 26633965Sjdp } 26733965Sjdp input++; 26833965Sjdp } 26933965Sjdp } 27033965Sjdp *arg = EOS; 27133965Sjdp argv[argc] = strdup (copybuf); 27233965Sjdp if (argv[argc] == NULL) 27333965Sjdp { 27433965Sjdp freeargv (argv); 27533965Sjdp argv = NULL; 27633965Sjdp break; 27733965Sjdp } 27833965Sjdp argc++; 27933965Sjdp argv[argc] = NULL; 28033965Sjdp 281218822Sdim while (ISSPACE (*input)) 28233965Sjdp { 28333965Sjdp input++; 28433965Sjdp } 28533965Sjdp } 28633965Sjdp while (*input != EOS); 28733965Sjdp } 28833965Sjdp return (argv); 28933965Sjdp} 29033965Sjdp 291218822Sdim/* 292218822Sdim 293218822Sdim@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@{file}) 294218822Sdim 295218822SdimWrite each member of ARGV, handling all necessary quoting, to the file 296218822Sdimnamed by FILE, separated by whitespace. Return 0 on success, non-zero 297218822Sdimif an error occurred while writing to FILE. 298218822Sdim 299218822Sdim@end deftypefn 300218822Sdim 301218822Sdim*/ 302218822Sdim 303218822Sdimint 304218822Sdimwriteargv (char **argv, FILE *f) 305218822Sdim{ 306218822Sdim int status = 0; 307218822Sdim 308218822Sdim if (f == NULL) 309218822Sdim return 1; 310218822Sdim 311218822Sdim while (*argv != NULL) 312218822Sdim { 313218822Sdim const char *arg = *argv; 314218822Sdim 315218822Sdim while (*arg != EOS) 316218822Sdim { 317218822Sdim char c = *arg; 318218822Sdim 319218822Sdim if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') 320218822Sdim if (EOF == fputc ('\\', f)) 321218822Sdim { 322218822Sdim status = 1; 323218822Sdim goto done; 324218822Sdim } 325218822Sdim 326218822Sdim if (EOF == fputc (c, f)) 327218822Sdim { 328218822Sdim status = 1; 329218822Sdim goto done; 330218822Sdim } 331218822Sdim arg++; 332218822Sdim } 333218822Sdim 334218822Sdim if (EOF == fputc ('\n', f)) 335218822Sdim { 336218822Sdim status = 1; 337218822Sdim goto done; 338218822Sdim } 339218822Sdim argv++; 340218822Sdim } 341218822Sdim 342218822Sdim done: 343218822Sdim return status; 344218822Sdim} 345218822Sdim 346218822Sdim/* 347218822Sdim 348218822Sdim@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) 349218822Sdim 350218822SdimThe @var{argcp} and @code{argvp} arguments are pointers to the usual 351218822Sdim@code{argc} and @code{argv} arguments to @code{main}. This function 352218822Sdimlooks for arguments that begin with the character @samp{@@}. Any such 353218822Sdimarguments are interpreted as ``response files''. The contents of the 354218822Sdimresponse file are interpreted as additional command line options. In 355218822Sdimparticular, the file is separated into whitespace-separated strings; 356218822Sdimeach such string is taken as a command-line option. The new options 357218822Sdimare inserted in place of the option naming the response file, and 358218822Sdim@code{*argcp} and @code{*argvp} will be updated. If the value of 359218822Sdim@code{*argvp} is modified by this function, then the new value has 360218822Sdimbeen dynamically allocated and can be deallocated by the caller with 361218822Sdim@code{freeargv}. However, most callers will simply call 362218822Sdim@code{expandargv} near the beginning of @code{main} and allow the 363218822Sdimoperating system to free the memory when the program exits. 364218822Sdim 365218822Sdim@end deftypefn 366218822Sdim 367218822Sdim*/ 368218822Sdim 369218822Sdimvoid 370218822Sdimexpandargv (int *argcp, char ***argvp) 371218822Sdim{ 372218822Sdim /* The argument we are currently processing. */ 373218822Sdim int i = 0; 374218822Sdim /* Non-zero if ***argvp has been dynamically allocated. */ 375218822Sdim int argv_dynamic = 0; 376218822Sdim /* Loop over the arguments, handling response files. We always skip 377218822Sdim ARGVP[0], as that is the name of the program being run. */ 378218822Sdim while (++i < *argcp) 379218822Sdim { 380218822Sdim /* The name of the response file. */ 381218822Sdim const char *filename; 382218822Sdim /* The response file. */ 383218822Sdim FILE *f; 384218822Sdim /* An upper bound on the number of characters in the response 385218822Sdim file. */ 386218822Sdim long pos; 387218822Sdim /* The number of characters in the response file, when actually 388218822Sdim read. */ 389218822Sdim size_t len; 390218822Sdim /* A dynamically allocated buffer used to hold options read from a 391218822Sdim response file. */ 392218822Sdim char *buffer; 393218822Sdim /* Dynamically allocated storage for the options read from the 394218822Sdim response file. */ 395218822Sdim char **file_argv; 396218822Sdim /* The number of options read from the response file, if any. */ 397218822Sdim size_t file_argc; 398218822Sdim /* We are only interested in options of the form "@file". */ 399218822Sdim filename = (*argvp)[i]; 400218822Sdim if (filename[0] != '@') 401218822Sdim continue; 402218822Sdim /* Read the contents of the file. */ 403218822Sdim f = fopen (++filename, "r"); 404218822Sdim if (!f) 405218822Sdim continue; 406218822Sdim if (fseek (f, 0L, SEEK_END) == -1) 407218822Sdim goto error; 408218822Sdim pos = ftell (f); 409218822Sdim if (pos == -1) 410218822Sdim goto error; 411218822Sdim if (fseek (f, 0L, SEEK_SET) == -1) 412218822Sdim goto error; 413218822Sdim buffer = (char *) xmalloc (pos * sizeof (char) + 1); 414218822Sdim len = fread (buffer, sizeof (char), pos, f); 415218822Sdim if (len != (size_t) pos 416218822Sdim /* On Windows, fread may return a value smaller than POS, 417218822Sdim due to CR/LF->CR translation when reading text files. 418218822Sdim That does not in-and-of itself indicate failure. */ 419218822Sdim && ferror (f)) 420218822Sdim goto error; 421218822Sdim /* Add a NUL terminator. */ 422218822Sdim buffer[len] = '\0'; 423218822Sdim /* Parse the string. */ 424218822Sdim file_argv = buildargv (buffer); 425218822Sdim /* If *ARGVP is not already dynamically allocated, copy it. */ 426218822Sdim if (!argv_dynamic) 427218822Sdim { 428218822Sdim *argvp = dupargv (*argvp); 429218822Sdim if (!*argvp) 430218822Sdim { 431218822Sdim fputs ("\nout of memory\n", stderr); 432218822Sdim xexit (1); 433218822Sdim } 434218822Sdim } 435218822Sdim /* Count the number of arguments. */ 436218822Sdim file_argc = 0; 437218822Sdim while (file_argv[file_argc] && *file_argv[file_argc]) 438218822Sdim ++file_argc; 439218822Sdim /* Now, insert FILE_ARGV into ARGV. The "+1" below handles the 440218822Sdim NULL terminator at the end of ARGV. */ 441218822Sdim *argvp = ((char **) 442218822Sdim xrealloc (*argvp, 443218822Sdim (*argcp + file_argc + 1) * sizeof (char *))); 444218822Sdim memmove (*argvp + i + file_argc, *argvp + i + 1, 445218822Sdim (*argcp - i) * sizeof (char *)); 446218822Sdim memcpy (*argvp + i, file_argv, file_argc * sizeof (char *)); 447218822Sdim /* The original option has been replaced by all the new 448218822Sdim options. */ 449218822Sdim *argcp += file_argc - 1; 450218822Sdim /* Free up memory allocated to process the response file. We do 451218822Sdim not use freeargv because the individual options in FILE_ARGV 452218822Sdim are now in the main ARGV. */ 453218822Sdim free (file_argv); 454218822Sdim free (buffer); 455218822Sdim /* Rescan all of the arguments just read to support response 456218822Sdim files that include other response files. */ 457218822Sdim --i; 458218822Sdim error: 459218822Sdim /* We're all done with the file now. */ 460218822Sdim fclose (f); 461218822Sdim } 462218822Sdim} 463218822Sdim 46433965Sjdp#ifdef MAIN 46533965Sjdp 46633965Sjdp/* Simple little test driver. */ 46733965Sjdp 46889857Sobrienstatic const char *const tests[] = 46933965Sjdp{ 47033965Sjdp "a simple command line", 47133965Sjdp "arg 'foo' is single quoted", 47233965Sjdp "arg \"bar\" is double quoted", 47333965Sjdp "arg \"foo bar\" has embedded whitespace", 47433965Sjdp "arg 'Jack said \\'hi\\'' has single quotes", 47533965Sjdp "arg 'Jack said \\\"hi\\\"' has double quotes", 47633965Sjdp "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", 47733965Sjdp 47833965Sjdp /* This should be expanded into only one argument. */ 47933965Sjdp "trailing-whitespace ", 48033965Sjdp 48133965Sjdp "", 48233965Sjdp NULL 48333965Sjdp}; 48433965Sjdp 485218822Sdimint 486218822Sdimmain (void) 48733965Sjdp{ 48833965Sjdp char **argv; 48989857Sobrien const char *const *test; 49033965Sjdp char **targs; 49133965Sjdp 49233965Sjdp for (test = tests; *test != NULL; test++) 49333965Sjdp { 49433965Sjdp printf ("buildargv(\"%s\")\n", *test); 49533965Sjdp if ((argv = buildargv (*test)) == NULL) 49633965Sjdp { 49733965Sjdp printf ("failed!\n\n"); 49833965Sjdp } 49933965Sjdp else 50033965Sjdp { 50133965Sjdp for (targs = argv; *targs != NULL; targs++) 50233965Sjdp { 50333965Sjdp printf ("\t\"%s\"\n", *targs); 50433965Sjdp } 50533965Sjdp printf ("\n"); 50633965Sjdp } 50733965Sjdp freeargv (argv); 50833965Sjdp } 50933965Sjdp 51089857Sobrien return 0; 51133965Sjdp} 51233965Sjdp 51333965Sjdp#endif /* MAIN */ 514