12fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o/*
22fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * argv_parse.c --- utility function for parsing a string into a
32fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * 	argc, argv array.
4efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
52fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * This file defines a function argv_parse() which parsing a
62fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * passed-in string, handling double quotes and backslashes, and
72fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * creates an allocated argv vector which can be freed using the
82fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * argv_free() function.
92fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o *
102fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * See argv_parse.h for the formal definition of the functions.
112fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o *
122fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * Copyright 1999 by Theodore Ts'o.
13efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o *
142fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * Permission to use, copy, modify, and distribute this software for
152fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * any purpose with or without fee is hereby granted, provided that
162fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * the above copyright notice and this permission notice appear in all
172fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * copies.  THE SOFTWARE IS PROVIDED "AS IS" AND THEODORE TS'O (THE
182fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * AUTHOR) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
192fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
202fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
212fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
222fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
232fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
242fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  (Isn't
252fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * it sick that the U.S. culture of lawsuit-happy lawyers requires
262fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * this kind of disclaimer?)
272fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o *
282fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * Version 1.1, modified 2/27/1999
292fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o */
302fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
312fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#ifdef HAVE_STDLIB_H
322fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#include <stdlib.h>
332fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#endif
342fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#include <ctype.h>
352fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#include <string.h>
362fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#include "argv_parse.h"
372fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
382fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#define STATE_WHITESPACE	1
392fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#define STATE_TOKEN		2
402fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#define STATE_QUOTED		3
412fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
422fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o/*
432fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * Returns 0 on success, -1 on failure.
442fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o */
452fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'oint argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)
462fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o{
472fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	int	argc = 0, max_argc = 0;
482fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	char 	**argv, **new_argv, *buf, ch;
492fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	char	*cp = 0, *outcp = 0;
502fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	int	state = STATE_WHITESPACE;
512fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
522fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	buf = malloc(strlen(in_buf)+1);
532fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	if (!buf)
542fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		return -1;
552fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
562fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	max_argc = 0; argc = 0; argv = 0;
572fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	outcp = buf;
582fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	for (cp = in_buf; (ch = *cp); cp++) {
592fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (state == STATE_WHITESPACE) {
602fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			if (isspace((int) ch))
612fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				continue;
622fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			/* Not whitespace, so start a new token */
632fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			state = STATE_TOKEN;
642fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			if (argc >= max_argc) {
652fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				max_argc += 3;
662fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				new_argv = realloc(argv,
672fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o						  (max_argc+1)*sizeof(char *));
682fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				if (!new_argv) {
6945e338f5332a54295893dba2e32cc093d1316f60Jim Meyering					free(argv);
702fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o					free(buf);
712fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o					return -1;
722fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				}
732fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				argv = new_argv;
742fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			}
752fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			argv[argc++] = outcp;
762fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
772fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (state == STATE_QUOTED) {
782fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			if (ch == '"')
792fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				state = STATE_TOKEN;
802fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			else
812fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				*outcp++ = ch;
822fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			continue;
832fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
842fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		/* Must be processing characters in a word */
852fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (isspace((int) ch)) {
862fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			/*
872fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			 * Terminate the current word and start
882fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			 * looking for the beginning of the next word.
892fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			 */
902fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			*outcp++ = 0;
912fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			state = STATE_WHITESPACE;
922fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			continue;
932fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
942fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (ch == '"') {
952fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			state = STATE_QUOTED;
962fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			continue;
972fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
982fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (ch == '\\') {
992fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			ch = *++cp;
1002fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			switch (ch) {
1012fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			case '\0':
1022fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				ch = '\\'; cp--; break;
1032fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			case 'n':
1042fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				ch = '\n'; break;
1052fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			case 't':
1062fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				ch = '\t'; break;
1072fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			case 'b':
1082fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				ch = '\b'; break;
1092fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			}
1102fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
1112fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		*outcp++ = ch;
1122fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	}
1132fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	if (state != STATE_WHITESPACE)
1142fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		*outcp++ = '\0';
1152fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	if (argv == 0) {
1162fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		argv = malloc(sizeof(char *));
1172fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		free(buf);
1182fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	}
1192fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	argv[argc] = 0;
1202fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	if (ret_argc)
1212fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		*ret_argc = argc;
1222fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	if (ret_argv)
1232fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		*ret_argv = argv;
1242fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	return 0;
1252fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o}
1262fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
1272fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'ovoid argv_free(char **argv)
1282fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o{
12945e338f5332a54295893dba2e32cc093d1316f60Jim Meyering	free(*argv);
1302fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	free(argv);
1312fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o}
1322fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
1332fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#ifdef DEBUG
1342fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o/*
1352fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o * For debugging
1362fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o */
1372fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
1382fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#include <stdio.h>
1392fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
1402fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'oint main(int argc, char **argv)
1412fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o{
1422fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	int	ac, ret;
1432fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	char	**av, **cpp;
1442fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	char	buf[256];
1452fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o
1462fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	while (!feof(stdin)) {
1472fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (fgets(buf, sizeof(buf), stdin) == NULL)
1482fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			break;
1492fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		ret = argv_parse(buf, &ac, &av);
1502fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		if (ret != 0) {
1512fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			printf("Argv_parse returned %d!\n", ret);
1522fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			continue;
1532fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
1542fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		printf("Argv_parse returned %d arguments...\n", ac);
1552fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		for (cpp = av; *cpp; cpp++) {
1562fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			if (cpp != av)
1572fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o				printf(", ");
1582fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o			printf("'%s'", *cpp);
1592fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		}
1602fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		printf("\n");
1612fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o		argv_free(av);
1622fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	}
1632fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o	exit(0);
1642fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o}
1652fa9ba98337b07d6acfac52b5ee5dc8116dda866Theodore Ts'o#endif /* DEBUG */
166