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