xargs: code shrink -15 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		| @@ -122,11 +122,10 @@ typedef struct xlist_t { | |||||||
| 	char xstr[1]; | 	char xstr[1]; | ||||||
| } xlist_t; | } xlist_t; | ||||||
|  |  | ||||||
| static smallint eof_stdin_detected; | /* In POSIX/C locale isspace is only these chars: "\t\n\v\f\r" and space. | ||||||
|  |  * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13. | ||||||
| #define ISBLANK(c) ((c) == ' ' || (c) == '\t') |  */ | ||||||
| #define ISSPACE(c) (ISBLANK(c) || (c) == '\n' || (c) == '\r' \ | #define ISSPACE(a) ({ unsigned char xargs__isspace = (a) - 9; xargs__isspace == (' ' - 9) || xargs__isspace <= (13 - 9); }) | ||||||
| 		    || (c) == '\f' || (c) == '\v') |  | ||||||
|  |  | ||||||
| #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES | #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES | ||||||
| static xlist_t* process_stdin(xlist_t *list_arg, | static xlist_t* process_stdin(xlist_t *list_arg, | ||||||
| @@ -136,39 +135,36 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||||||
| #define QUOTE     1 | #define QUOTE     1 | ||||||
| #define BACKSLASH 2 | #define BACKSLASH 2 | ||||||
| #define SPACE     4 | #define SPACE     4 | ||||||
|  | 	char *s = NULL;         /* start of the word */ | ||||||
| 	char *s = NULL;         /* start word */ | 	char *p = NULL;         /* pointer to end of the word */ | ||||||
| 	char *p = NULL;         /* pointer to end word */ |  | ||||||
| 	char q = '\0';          /* quote char */ | 	char q = '\0';          /* quote char */ | ||||||
| 	char state = NORM; | 	char state = NORM; | ||||||
| 	char eof_str_detected = 0; | 	char eof_str_detected = 0; | ||||||
| 	size_t line_l = 0;      /* size loaded args line */ | 	size_t line_l = 0;      /* size of loaded args */ | ||||||
| 	int c;                  /* current char */ |  | ||||||
| 	xlist_t *cur; | 	xlist_t *cur; | ||||||
| 	xlist_t *prev; | 	xlist_t *prev; | ||||||
|  |  | ||||||
| 	prev = cur = list_arg; | 	prev = cur = list_arg; | ||||||
| 	while (1) { | 	while (cur) { | ||||||
| 		if (!cur) break; |  | ||||||
| 		prev = cur; | 		prev = cur; | ||||||
| 		line_l += cur->length; | 		line_l += cur->length; | ||||||
| 		cur = cur->link; | 		cur = cur->link; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while (!eof_stdin_detected) { | 	while (1) { | ||||||
| 		c = getchar(); | 		int c = getchar(); | ||||||
| 		if (c == EOF) { | 		if (c == EOF) { | ||||||
| 			eof_stdin_detected = 1; |  | ||||||
| 			if (s) | 			if (s) | ||||||
| 				goto unexpected_eof; | 				goto unexpected_eof; | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 		if (eof_str_detected) | 		if (eof_str_detected) /* skip till EOF */ | ||||||
| 			continue; | 			continue; | ||||||
| 		if (state == BACKSLASH) { | 		if (state == BACKSLASH) { | ||||||
| 			state = NORM; | 			state = NORM; | ||||||
| 			goto set; | 			goto set; | ||||||
| 		} else if (state == QUOTE) { | 		} | ||||||
|  | 		if (state == QUOTE) { | ||||||
| 			if (c != q) | 			if (c != q) | ||||||
| 				goto set; | 				goto set; | ||||||
| 			q = '\0'; | 			q = '\0'; | ||||||
| @@ -202,7 +198,7 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||||||
| 				bb_error_msg_and_die("unmatched %s quote", | 				bb_error_msg_and_die("unmatched %s quote", | ||||||
| 					q == '\'' ? "single" : "double"); | 					q == '\'' ? "single" : "double"); | ||||||
| 			} | 			} | ||||||
| 			/* word loaded */ | 			/* A full word is loaded */ | ||||||
| 			if (eof_str) { | 			if (eof_str) { | ||||||
| 				eof_str_detected = (strcmp(s, eof_str) == 0); | 				eof_str_detected = (strcmp(s, eof_str) == 0); | ||||||
| 			} | 			} | ||||||
| @@ -220,11 +216,9 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||||||
| 				} | 				} | ||||||
| 				prev = cur; | 				prev = cur; | ||||||
| 				line_l += length; | 				line_l += length; | ||||||
| 				if (line_l > mc) { | 				if (line_l > mc) /* limit stop memory usage */ | ||||||
| 					/* stop memory usage :-) */ |  | ||||||
| 					break; | 					break; | ||||||
| 			} | 			} | ||||||
| 			} |  | ||||||
| 			s = NULL; | 			s = NULL; | ||||||
| 			state = NORM; | 			state = NORM; | ||||||
| 		} | 		} | ||||||
| @@ -236,30 +230,29 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||||||
| static xlist_t* process_stdin(xlist_t *list_arg, | static xlist_t* process_stdin(xlist_t *list_arg, | ||||||
| 		const char *eof_str, size_t mc, char *buf) | 		const char *eof_str, size_t mc, char *buf) | ||||||
| { | { | ||||||
|  |  | ||||||
| 	int c;                  /* current char */ |  | ||||||
| 	char eof_str_detected = 0; | 	char eof_str_detected = 0; | ||||||
| 	char *s = NULL;         /* start word */ | 	char *s = NULL;         /* start of the word */ | ||||||
| 	char *p = NULL;         /* pointer to end word */ | 	char *p = NULL;         /* pointer to end of the word */ | ||||||
| 	size_t line_l = 0;      /* size loaded args line */ | 	size_t line_l = 0;      /* size of loaded args */ | ||||||
| 	xlist_t *cur; | 	xlist_t *cur; | ||||||
| 	xlist_t *prev; | 	xlist_t *prev; | ||||||
|  |  | ||||||
| 	prev = cur = list_arg; | 	prev = cur = list_arg; | ||||||
| 	while (1) { | 	while (cur) { | ||||||
| 		if (!cur) break; |  | ||||||
| 		prev = cur; | 		prev = cur; | ||||||
| 		line_l += cur->length; | 		line_l += cur->length; | ||||||
| 		cur = cur->link; | 		cur = cur->link; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while (!eof_stdin_detected) { | 	while (1) { | ||||||
| 		c = getchar(); | 		int c = getchar(); | ||||||
| 		if (c == EOF) { | 		if (c == EOF) { | ||||||
| 			eof_stdin_detected = 1; | 			if (s == NULL) | ||||||
|  | 				break; | ||||||
| 		} | 		} | ||||||
| 		if (eof_str_detected) | 		if (eof_str_detected) { /* skip till EOF */ | ||||||
| 			continue; | 			continue; | ||||||
|  | 		} | ||||||
| 		if (c == EOF || ISSPACE(c)) { | 		if (c == EOF || ISSPACE(c)) { | ||||||
| 			if (s == NULL) | 			if (s == NULL) | ||||||
| 				continue; | 				continue; | ||||||
| @@ -271,7 +264,7 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||||||
| 			bb_error_msg_and_die("argument line too long"); | 			bb_error_msg_and_die("argument line too long"); | ||||||
| 		*p++ = (c == EOF ? '\0' : c); | 		*p++ = (c == EOF ? '\0' : c); | ||||||
| 		if (c == EOF) { /* word's delimiter or EOF detected */ | 		if (c == EOF) { /* word's delimiter or EOF detected */ | ||||||
| 			/* word loaded */ | 			/* A full word is loaded */ | ||||||
| 			if (eof_str) { | 			if (eof_str) { | ||||||
| 				eof_str_detected = (strcmp(s, eof_str) == 0); | 				eof_str_detected = (strcmp(s, eof_str) == 0); | ||||||
| 			} | 			} | ||||||
| @@ -289,14 +282,12 @@ static xlist_t *process_stdin(xlist_t *list_arg, | |||||||
| 				} | 				} | ||||||
| 				prev = cur; | 				prev = cur; | ||||||
| 				line_l += length; | 				line_l += length; | ||||||
| 				if (line_l > mc) { | 				if (line_l > mc) /* limit stop memory usage */ | ||||||
| 					/* stop memory usage :-) */ |  | ||||||
| 					break; | 					break; | ||||||
| 			} | 			} | ||||||
| 			s = NULL; | 			s = NULL; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	} |  | ||||||
| 	return list_arg; | 	return list_arg; | ||||||
| } | } | ||||||
| #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ | #endif /* FEATURE_XARGS_SUPPORT_QUOTES */ | ||||||
| @@ -328,25 +319,22 @@ static int xargs_ask_confirmation(void) | |||||||
| static xlist_t* process0_stdin(xlist_t *list_arg, | static xlist_t* process0_stdin(xlist_t *list_arg, | ||||||
| 		const char *eof_str UNUSED_PARAM, size_t mc, char *buf) | 		const char *eof_str UNUSED_PARAM, size_t mc, char *buf) | ||||||
| { | { | ||||||
| 	int c;                  /* current char */ | 	char *s = NULL;         /* start of the word */ | ||||||
| 	char *s = NULL;         /* start word */ | 	char *p = NULL;         /* pointer to end of the word */ | ||||||
| 	char *p = NULL;         /* pointer to end word */ | 	size_t line_l = 0;      /* size of loaded args */ | ||||||
| 	size_t line_l = 0;      /* size loaded args line */ |  | ||||||
| 	xlist_t *cur; | 	xlist_t *cur; | ||||||
| 	xlist_t *prev; | 	xlist_t *prev; | ||||||
|  |  | ||||||
| 	prev = cur = list_arg; | 	prev = cur = list_arg; | ||||||
| 	while (1) { | 	while (cur) { | ||||||
| 		if (!cur) break; |  | ||||||
| 		prev = cur; | 		prev = cur; | ||||||
| 		line_l += cur->length; | 		line_l += cur->length; | ||||||
| 		cur = cur->link; | 		cur = cur->link; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while (!eof_stdin_detected) { | 	while (1) { | ||||||
| 		c = getchar(); | 		int c = getchar(); | ||||||
| 		if (c == EOF) { | 		if (c == EOF) { | ||||||
| 			eof_stdin_detected = 1; |  | ||||||
| 			if (s == NULL) | 			if (s == NULL) | ||||||
| 				break; | 				break; | ||||||
| 			c = '\0'; | 			c = '\0'; | ||||||
| @@ -357,7 +345,7 @@ static xlist_t *process0_stdin(xlist_t *list_arg, | |||||||
| 			bb_error_msg_and_die("argument line too long"); | 			bb_error_msg_and_die("argument line too long"); | ||||||
| 		*p++ = c; | 		*p++ = c; | ||||||
| 		if (c == '\0') {   /* word's delimiter or EOF detected */ | 		if (c == '\0') {   /* word's delimiter or EOF detected */ | ||||||
| 			/* word loaded */ | 			/* A full word is loaded */ | ||||||
| 			size_t length = (p - buf); | 			size_t length = (p - buf); | ||||||
| 			/* Dont xzalloc - it can be quite big */ | 			/* Dont xzalloc - it can be quite big */ | ||||||
| 			cur = xmalloc(offsetof(xlist_t, xstr) + length); | 			cur = xmalloc(offsetof(xlist_t, xstr) + length); | ||||||
| @@ -371,10 +359,8 @@ static xlist_t *process0_stdin(xlist_t *list_arg, | |||||||
| 			} | 			} | ||||||
| 			prev = cur; | 			prev = cur; | ||||||
| 			line_l += length; | 			line_l += length; | ||||||
| 			if (line_l > mc) { | 			if (line_l > mc) /* limit stop memory usage */ | ||||||
| 				/* stop memory usage :-) */ |  | ||||||
| 				break; | 				break; | ||||||
| 			} |  | ||||||
| 			s = NULL; | 			s = NULL; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @@ -412,12 +398,11 @@ enum { | |||||||
| int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||||||
| int xargs_main(int argc, char **argv) | int xargs_main(int argc, char **argv) | ||||||
| { | { | ||||||
| 	char **args; |  | ||||||
| 	int i, n; |  | ||||||
| 	xlist_t *list = NULL; | 	xlist_t *list = NULL; | ||||||
| 	xlist_t *cur; |  | ||||||
| 	int child_error = 0; | 	int child_error = 0; | ||||||
| 	char *max_args, *max_chars; | 	char *max_args; | ||||||
|  | 	char *max_chars; | ||||||
|  | 	char *buf; | ||||||
| 	int n_max_arg; | 	int n_max_arg; | ||||||
| 	const char *eof_str = NULL; | 	const char *eof_str = NULL; | ||||||
| 	unsigned opt; | 	unsigned opt; | ||||||
| @@ -441,15 +426,12 @@ int xargs_main(int argc, char **argv) | |||||||
|  |  | ||||||
| 	argv += optind; | 	argv += optind; | ||||||
| 	argc -= optind; | 	argc -= optind; | ||||||
| 	if (!argc) { | 	if (!argv[0]) { | ||||||
| 		/* default behavior is to echo all the filenames */ | 		/* default behavior is to echo all the filenames */ | ||||||
| 		*argv = (char*)"echo"; | 		*--argv = (char*)"echo"; | ||||||
| 		argc++; | 		argc++; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ |  | ||||||
| 	if (n_max_chars < 4*1024); /* paranoia */ |  | ||||||
| 		n_max_chars = LONG_MAX; |  | ||||||
| 	/* The Open Group Base Specifications Issue 6: | 	/* The Open Group Base Specifications Issue 6: | ||||||
| 	 * "The xargs utility shall limit the command line length such that | 	 * "The xargs utility shall limit the command line length such that | ||||||
| 	 * when the command line is invoked, the combined argument | 	 * when the command line is invoked, the combined argument | ||||||
| @@ -457,27 +439,32 @@ int xargs_main(int argc, char **argv) | |||||||
| 	 * in the System Interfaces volume of IEEE Std 1003.1-2001) | 	 * in the System Interfaces volume of IEEE Std 1003.1-2001) | ||||||
| 	 * shall not exceed {ARG_MAX}-2048 bytes". | 	 * shall not exceed {ARG_MAX}-2048 bytes". | ||||||
| 	 */ | 	 */ | ||||||
|  | 	n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ | ||||||
|  | 	if (n_max_chars < 4*1024); /* paranoia */ | ||||||
|  | 		n_max_chars = 4*1024; | ||||||
| 	n_max_chars -= 2048; | 	n_max_chars -= 2048; | ||||||
| 	/* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which | 	/* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which | ||||||
| 	 * have it at 1 meg).  Things will work fine with a large ARG_MAX but it | 	 * have it at 1 meg).  Things will work fine with a large ARG_MAX | ||||||
| 	 * will probably hurt the system more than it needs to; an array of this | 	 * but it will probably hurt the system more than it needs to; | ||||||
| 	 * size is allocated. | 	 * an array of this size is allocated. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (n_max_chars > 20 * 1024) | 	if (n_max_chars > 20 * 1024) | ||||||
| 		n_max_chars = 20 * 1024; | 		n_max_chars = 20 * 1024; | ||||||
|  |  | ||||||
| 	if (opt & OPT_UPTO_SIZE) { | 	if (opt & OPT_UPTO_SIZE) { | ||||||
|  | 		int i; | ||||||
| 		size_t n_chars = 0; | 		size_t n_chars = 0; | ||||||
| 		n_max_chars = xatoul_range(max_chars, 1, n_max_chars); | 		n_max_chars = xatoul_range(max_chars, 1, n_max_chars); | ||||||
| 		for (i = 0; i < argc; i++) { | 		for (i = 0; argv[i]; i++) { | ||||||
| 			n_chars += strlen(*argv) + 1; | 			n_chars += strlen(argv[i]) + 1; | ||||||
| 		} |  | ||||||
| 		if (n_max_chars <= n_chars) { |  | ||||||
| 			bb_error_msg_and_die("can't fit single argument within argument list size limit"); |  | ||||||
| 		} | 		} | ||||||
| 		n_max_chars -= n_chars; | 		n_max_chars -= n_chars; | ||||||
|  | 		if ((ssize_t)n_max_chars <= 0) { | ||||||
|  | 			bb_error_msg_and_die("can't fit single argument within argument list size limit"); | ||||||
| 		} | 		} | ||||||
| 	max_chars = xmalloc(n_max_chars); | 	} | ||||||
|  |  | ||||||
|  | 	buf = xmalloc(n_max_chars); | ||||||
|  |  | ||||||
| 	if (opt & OPT_UPTO_NUMBER) { | 	if (opt & OPT_UPTO_NUMBER) { | ||||||
| 		n_max_arg = xatoul_range(max_args, 1, INT_MAX); | 		n_max_arg = xatoul_range(max_args, 1, INT_MAX); | ||||||
| @@ -485,10 +472,14 @@ int xargs_main(int argc, char **argv) | |||||||
| 		n_max_arg = n_max_chars; | 		n_max_arg = n_max_chars; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	while ((list = read_args(list, eof_str, n_max_chars, max_chars)) != NULL || | 	while ((list = read_args(list, eof_str, n_max_chars, buf)) != NULL | ||||||
| 		!(opt & OPT_NO_EMPTY)) | 	 ||    !(opt & OPT_NO_EMPTY) | ||||||
| 	{ | 	) { | ||||||
|  | 		char **args; | ||||||
|  | 		xlist_t *cur; | ||||||
|  | 		int i, n; | ||||||
| 		size_t n_chars = 0; | 		size_t n_chars = 0; | ||||||
|  |  | ||||||
| 		opt |= OPT_NO_EMPTY; | 		opt |= OPT_NO_EMPTY; | ||||||
| 		n = 0; | 		n = 0; | ||||||
| #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT | #if ENABLE_FEATURE_XARGS_SUPPORT_TERMOPT | ||||||
| @@ -510,15 +501,14 @@ int xargs_main(int argc, char **argv) | |||||||
| 				break; | 				break; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| #endif /* FEATURE_XARGS_SUPPORT_TERMOPT */ | #endif | ||||||
|  |  | ||||||
| 		/* allocate pointers for execvp: | 		/* allocate pointers for execvp */ | ||||||
| 		   argc*arg, n*arg from stdin, NULL */ | 		args = xzalloc(sizeof(args[0]) * (argc + n + 1)); | ||||||
| 		args = xzalloc((n + argc + 1) * sizeof(char *)); |  | ||||||
|  |  | ||||||
| 		/* store the command to be executed | 		/* store the command to be executed | ||||||
| 		   (taken from the command line) */ | 		 * (taken from the command line) */ | ||||||
| 		for (i = 0; i < argc; i++) | 		for (i = 0; argv[i]; i++) | ||||||
| 			args[i] = argv[i]; | 			args[i] = argv[i]; | ||||||
| 		/* (taken from stdin) */ | 		/* (taken from stdin) */ | ||||||
| 		for (cur = list; n; cur = cur->link) { | 		for (cur = list; n; cur = cur->link) { | ||||||
| @@ -535,6 +525,7 @@ int xargs_main(int argc, char **argv) | |||||||
| 			if (!(opt & OPT_INTERACTIVE)) | 			if (!(opt & OPT_INTERACTIVE)) | ||||||
| 				bb_putchar_stderr('\n'); | 				bb_putchar_stderr('\n'); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { | 		if (!(opt & OPT_INTERACTIVE) || xargs_ask_confirmation()) { | ||||||
| 			child_error = xargs_exec(args); | 			child_error = xargs_exec(args); | ||||||
| 		} | 		} | ||||||
| @@ -546,12 +537,15 @@ int xargs_main(int argc, char **argv) | |||||||
| 			free(cur); | 			free(cur); | ||||||
| 		} | 		} | ||||||
| 		free(args); | 		free(args); | ||||||
|  |  | ||||||
| 		if (child_error > 0 && child_error != 123) { | 		if (child_error > 0 && child_error != 123) { | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 	} /* while */ | 	} /* while */ | ||||||
|  |  | ||||||
| 	if (ENABLE_FEATURE_CLEAN_UP) | 	if (ENABLE_FEATURE_CLEAN_UP) | ||||||
| 		free(max_chars); | 		free(buf); | ||||||
|  |  | ||||||
| 	return child_error; | 	return child_error; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -26,4 +26,9 @@ testing "xargs does not stop on underscore ('new' GNU behavior)" \ | |||||||
| 	"a _ b\n" \ | 	"a _ b\n" \ | ||||||
| 	"" "a\n_\nb\n" | 	"" "a\n_\nb\n" | ||||||
|  |  | ||||||
|  | testing "xargs -s7 can take one-char input" \ | ||||||
|  | 	"xargs -s7" \ | ||||||
|  | 	"a\n" \ | ||||||
|  | 	"" "a\n" | ||||||
|  |  | ||||||
| exit $FAILCOUNT | exit $FAILCOUNT | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user