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