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