L4Re/departure

libext2fs/lib/libsupport/argv_parse.c

617:2733e5770ee9
9 months ago Paul Boddie Made the run command wait for completion, introducing the spawn command to run programs in the background. Introduced conveniences for waiting for the last job to be initiated and for piping from the last job, also subscribing to signals from pipe-supplying jobs so that they may be transparently removed from the job list upon completion. Augmented the job listing with the "+" notation familiar from Unix. Prevented new jobs from being started when no job slots are available.
     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 #include "config.h"    32 #ifdef HAVE_STDLIB_H    33 #include <stdlib.h>    34 #endif    35 #include <ctype.h>    36 #include <string.h>    37 #include "argv_parse.h"    38     39 #define STATE_WHITESPACE	1    40 #define STATE_TOKEN		2    41 #define STATE_QUOTED		3    42     43 /*    44  * Returns 0 on success, -1 on failure.    45  */    46 int argv_parse(char *in_buf, int *ret_argc, char ***ret_argv)    47 {    48 	int	argc = 0, max_argc = 0;    49 	char 	**argv, **new_argv, *buf, ch;    50 	char	*cp = 0, *outcp = 0;    51 	int	state = STATE_WHITESPACE;    52     53 	buf = malloc(strlen(in_buf)+1);    54 	if (!buf)    55 		return -1;    56     57 	max_argc = 0; argc = 0; argv = 0;    58 	outcp = buf;    59 	for (cp = in_buf; (ch = *cp); cp++) {    60 		if (state == STATE_WHITESPACE) {    61 			if (isspace((int) ch))    62 				continue;    63 			/* Not whitespace, so start a new token */    64 			state = STATE_TOKEN;    65 			if (argc >= max_argc) {    66 				max_argc += 3;    67 				new_argv = realloc(argv,    68 						  (max_argc+1)*sizeof(char *));    69 				if (!new_argv) {    70 					free(argv);    71 					free(buf);    72 					return -1;    73 				}    74 				argv = new_argv;    75 			}    76 			argv[argc++] = outcp;    77 		}    78 		if (state == STATE_QUOTED) {    79 			if (ch == '"')    80 				state = STATE_TOKEN;    81 			else    82 				*outcp++ = ch;    83 			continue;    84 		}    85 		/* Must be processing characters in a word */    86 		if (isspace((int) ch)) {    87 			/*    88 			 * Terminate the current word and start    89 			 * looking for the beginning of the next word.    90 			 */    91 			*outcp++ = 0;    92 			state = STATE_WHITESPACE;    93 			continue;    94 		}    95 		if (ch == '"') {    96 			state = STATE_QUOTED;    97 			continue;    98 		}    99 		if (ch == '\\') {   100 			ch = *++cp;   101 			switch (ch) {   102 			case '\0':   103 				ch = '\\'; cp--; break;   104 			case 'n':   105 				ch = '\n'; break;   106 			case 't':   107 				ch = '\t'; break;   108 			case 'b':   109 				ch = '\b'; break;   110 			}   111 		}   112 		*outcp++ = ch;   113 	}   114 	if (state != STATE_WHITESPACE)   115 		*outcp++ = '\0';   116 	if (argv == 0) {   117 		argv = malloc(sizeof(char *));   118 		free(buf);   119 	}   120 	argv[argc] = 0;   121 	if (ret_argc)   122 		*ret_argc = argc;   123 	if (ret_argv)   124 		*ret_argv = argv;   125 	return 0;   126 }   127    128 void argv_free(char **argv)   129 {   130 	free(*argv);   131 	free(argv);   132 }   133    134 #ifdef DEBUG   135 /*   136  * For debugging   137  */   138    139 #include <stdio.h>   140    141 int main(int argc, char **argv)   142 {   143 	int	ac, ret;   144 	char	**av, **cpp;   145 	char	buf[256];   146    147 	while (!feof(stdin)) {   148 		if (fgets(buf, sizeof(buf), stdin) == NULL)   149 			break;   150 		ret = argv_parse(buf, &ac, &av);   151 		if (ret != 0) {   152 			printf("Argv_parse returned %d!\n", ret);   153 			continue;   154 		}   155 		printf("Argv_parse returned %d arguments...\n", ac);   156 		for (cpp = av; *cpp; cpp++) {   157 			if (cpp != av)   158 				printf(", ");   159 			printf("'%s'", *cpp);   160 		}   161 		printf("\n");   162 		argv_free(av);   163 	}   164 	exit(0);   165 }   166 #endif /* DEBUG */