1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* 3 * Copyright 1999 by Theodore Ts'o. 4 * 5 * Permission to use, copy, modify, and distribute this software for 6 * any purpose with or without fee is hereby granted, provided that 7 * the above copyright notice and this permission notice appear in all 8 * copies. THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE 9 * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 10 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 11 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 13 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 14 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. (Isn't 16 * it sick that the U.S. culture of lawsuit-happy lawyers requires 17 * this kind of disclaimer?) 18 */ 19 20 /* 21 * Version 1.1, modified 2/27/1999 22 * 23 * argv_parse.c --- utility function for parsing a string into a 24 * argc, argv array. 25 * 26 * This file defines a function argv_parse() which parsing a 27 * passed-in string, handling double quotes and backslashes, and 28 * creates an allocated argv vector which can be freed using the 29 * argv_free() function. 30 * 31 * See argv_parse.h for the formal definition of the functions. 32 */ 33 34 #include "prof_int.h" 35 36 #ifdef HAVE_STDLIB_H 37 #include <stdlib.h> 38 #endif 39 #include <ctype.h> 40 #include <string.h> 41 #include "argv_parse.h" 42 43 #define STATE_WHITESPACE 1 44 #define STATE_TOKEN 2 45 #define STATE_QUOTED 3 46 47 /* 48 * Returns 0 on success, -1 on failure. 49 */ 50 int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv) 51 { 52 int argc = 0, max_argc = 0; 53 char **argv, **new_argv, *buf, ch; 54 char *cp = 0, *outcp = 0; 55 int state = STATE_WHITESPACE; 56 57 buf = malloc(strlen(in_buf)+1); 58 if (!buf) 59 return -1; 60 61 max_argc = 0; argc = 0; argv = 0; 62 outcp = buf; 63 for (cp = in_buf; (ch = *cp); cp++) { 64 if (state == STATE_WHITESPACE) { 65 if (isspace((int) ch)) 66 continue; 67 /* Not whitespace, so start a new token */ 68 state = STATE_TOKEN; 69 if (argc >= max_argc) { 70 max_argc += 3; 71 new_argv = realloc(argv, 72 (max_argc+1)*sizeof(char *)); 73 if (!new_argv) { 74 if (argv) free(argv); 75 free(buf); 76 return -1; 77 } 78 argv = new_argv; 79 } 80 argv[argc++] = outcp; 81 } 82 if (state == STATE_QUOTED) { 83 if (ch == '"') 84 state = STATE_TOKEN; 85 else 86 *outcp++ = ch; 87 continue; 88 } 89 /* Must be processing characters in a word */ 90 if (isspace((int) ch)) { 91 /* 92 * Terminate the current word and start 93 * looking for the beginning of the next word. 94 */ 95 *outcp++ = 0; 96 state = STATE_WHITESPACE; 97 continue; 98 } 99 if (ch == '"') { 100 state = STATE_QUOTED; 101 continue; 102 } 103 if (ch == '\\') { 104 ch = *++cp; 105 switch (ch) { 106 case '\0': 107 ch = '\\'; cp--; break; 108 case 'n': 109 ch = '\n'; break; 110 case 't': 111 ch = '\t'; break; 112 case 'b': 113 ch = '\b'; break; 114 } 115 } 116 *outcp++ = ch; 117 } 118 if (state != STATE_WHITESPACE) 119 *outcp++ = '\0'; 120 if (argv == 0) { 121 argv = malloc(sizeof(char *)); 122 free(buf); 123 } 124 argv[argc] = 0; 125 if (ret_argc) 126 *ret_argc = argc; 127 if (ret_argv) 128 *ret_argv = argv; 129 return 0; 130 } 131 132 void argv_free(char **argv) 133 { 134 if (*argv) 135 free(*argv); 136 free(argv); 137 } 138 139 #ifdef DEBUG 140 /* 141 * For debugging 142 */ 143 144 #include <stdio.h> 145 146 int main(int argc, char **argv) 147 { 148 int ac, ret; 149 char **av, **cpp; 150 char buf[256]; 151 152 while (!feof(stdin)) { 153 if (fgets(buf, sizeof(buf), stdin) == NULL) 154 break; 155 ret = argv_parse(buf, &ac, &av); 156 if (ret != 0) { 157 printf("Argv_parse returned %d!\n", ret); 158 continue; 159 } 160 printf("Argv_parse returned %d arguments...\n", ac); 161 for (cpp = av; *cpp; cpp++) { 162 if (cpp != av) 163 printf(", "); 164 printf("'%s'", *cpp); 165 } 166 printf("\n"); 167 argv_free(av); 168 } 169 exit(0); 170 } 171 #endif /* DEBUG */ 172