From: Eric Andersen Date: Mon, 25 Sep 2000 20:23:21 +0000 (-0000) Subject: Final (I think) version of xargs. Throw away all that tedious string X-Git-Tag: 0_47~11 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=e081eae7a469e0ddeebedd51c3d83bcbaccb23e3;p=oweals%2Fbusybox.git Final (I think) version of xargs. Throw away all that tedious string scrubbing, and quit using system. Instead, use fork() and exec(), which yields and smaller, simpler, and cleaner design. -Erik --- diff --git a/findutils/xargs.c b/findutils/xargs.c index 21bfb6bbe..b8ac31aa0 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -28,68 +28,19 @@ #include #include #include - -/* get_sh_safe_line_from_file() - This function reads an entire line from a text file - * up to a newline. It returns a malloc'ed char * which must be stored and - * free'ed by the caller. */ -extern char *get_sh_safe_line_from_file(FILE *file) -{ - static const int GROWBY = 80; /* how large we will grow strings by */ - - char ch, last_ch = 0; - char tmp[]=" "; - int idx = 0; - char *linebuf = NULL; - int linebufsz = 0; - - while (1) { - ch = fgetc(file); - if (ch == EOF) - break; - - /* grow the line buffer as necessary */ - while (idx > linebufsz-4) - linebuf = xrealloc(linebuf, linebufsz += GROWBY); - - /* Remove any extra spaces */ - if (last_ch == ' ' && ch == ' ') - continue; - - /* Replace any tabs with spaces */ - if (ch == '\t') - ch=' '; - - /* Escape any characters that are treated specially by /bin/sh */ - *tmp=ch; - if (strpbrk(tmp, "\\~`!$^&*()=|{}[];\"'<>?#") != NULL && last_ch!='\\') { - linebuf[idx++] = '\\'; - } - - linebuf[idx++] = ch; - last_ch=ch; - - if (ch == '\n') - break; - } - if (idx == 0 && last_ch!=0) - linebuf[idx++]=' '; - - if (idx == 0) - return NULL; - - linebuf[idx] = 0; - return linebuf; -} - +#include +#include int xargs_main(int argc, char **argv) { char *in_from_stdin = NULL; - char *args_from_cmdline = NULL; + char *args = NULL; char *cmd_to_be_executed = NULL; char traceflag = 0; - int len_args_from_cmdline, len_cmd_to_be_executed, len, opt; + int len_args=10, len_cmd_to_be_executed, opt; + pid_t pid; + int wpid, status; /* Note that we do not use getopt here, since * we only want to interpret initial options, @@ -102,50 +53,45 @@ int xargs_main(int argc, char **argv) break; default: fatalError(xargs_usage); - } + } } } - /* Store the command and arguments to be executed (from the command line) */ + /* Store the command to be executed (taken from the command line) */ if (argc == 0) { - len_args_from_cmdline = 6; - args_from_cmdline = xmalloc(len_args_from_cmdline); - strcat(args_from_cmdline, "echo "); + len_cmd_to_be_executed=6; + cmd_to_be_executed = xmalloc(len_cmd_to_be_executed); + strcat(cmd_to_be_executed, "echo"); } else { opt=strlen(*argv); - len_args_from_cmdline = (opt > 10)? opt : 10; - args_from_cmdline = xcalloc(len_args_from_cmdline, sizeof(char)); - while (argc-- > 0) { - if (strlen(*argv) + strlen(args_from_cmdline) > - len_args_from_cmdline) { - len_args_from_cmdline += strlen(*argv); - args_from_cmdline = - xrealloc(args_from_cmdline, - len_args_from_cmdline+1); - } - strcat(args_from_cmdline, *argv); - strcat(args_from_cmdline, " "); - ++argv; - } + len_cmd_to_be_executed = (opt > 10)? opt : 10; + cmd_to_be_executed = xcalloc(len_cmd_to_be_executed, sizeof(char)); + strcat(cmd_to_be_executed, *argv); } - /* Set up some space for the command to be executed to be held in */ - len_cmd_to_be_executed=10; - cmd_to_be_executed = xcalloc(len_cmd_to_be_executed, sizeof(char)); - strcpy(cmd_to_be_executed, args_from_cmdline); - /* Now, read in one line at a time from stdin, and run command+args on it */ - in_from_stdin = get_sh_safe_line_from_file(stdin); + /* Now, read in one line at a time from stdin, and stroe this to be used later + * as an argument to the command we just stored */ + in_from_stdin = get_line_from_file(stdin); for (;in_from_stdin!=NULL;) { char *tmp; opt = strlen(in_from_stdin); - len = opt + len_args_from_cmdline; - len_cmd_to_be_executed+=len+3; - cmd_to_be_executed=xrealloc(cmd_to_be_executed, len_cmd_to_be_executed); + len_args += opt + 3; + args=xrealloc(args, len_args); /* Strip out the final \n */ in_from_stdin[opt-1]=' '; - + + /* Replace any tabs with spaces */ + while( (tmp = strchr(in_from_stdin, '\t')) != NULL ) + *tmp=' '; + + /* Strip out any extra intra-word spaces */ + while( (tmp = strstr(in_from_stdin, " ")) != NULL ) { + opt = strlen(in_from_stdin); + memmove(tmp, tmp+1, opt-(tmp-in_from_stdin)); + } + /* trim trailing whitespace */ opt = strlen(in_from_stdin) - 1; while (isspace(in_from_stdin[opt])) @@ -157,26 +103,49 @@ int xargs_main(int argc, char **argv) while(isspace(*tmp)) tmp++; - strcat(cmd_to_be_executed, tmp); - strcat(cmd_to_be_executed, " "); - + strcat(args, tmp); + strcat(args, " "); + free(in_from_stdin); - in_from_stdin = get_sh_safe_line_from_file(stdin); + in_from_stdin = get_line_from_file(stdin); } - if (traceflag==1) + if (traceflag==1) { fputs(cmd_to_be_executed, stderr); + fputs(args, stderr); + } - if ((system(cmd_to_be_executed) != 0) && (errno != 0)) - fatalError("%s", strerror(errno)); + if ((pid = fork()) == 0) { + char *cmd[255]; + int i=1; + + //printf("argv[0]='%s'\n", cmd_to_be_executed); + cmd[0] = cmd_to_be_executed; + while (--argc && ++argv && *argv ) { + //printf("argv[%d]='%s'\n", i, *argv); + cmd[i++]=*argv; + } + //printf("argv[%d]='%s'\n", i, args); + cmd[i++] = args; + cmd[i] = NULL; + execvp(cmd_to_be_executed, cmd); + + /* What? Still here? Exit with an error */ + fatalError("%s: %s\n", cmd_to_be_executed, strerror(errno)); + } + /* Wait for a child process to exit */ + wpid = wait(&status); #ifdef BB_FEATURE_CLEAN_UP - free(args_from_cmdline); + free(args); free(cmd_to_be_executed); #endif - return 0; + if (wpid > 0) + return (WEXITSTATUS(status)); + else + return EXIT_FAILURE; } /* Local Variables: @@ -185,4 +154,3 @@ c-basic-offset: 4 tab-width: 4 End: */ - diff --git a/xargs.c b/xargs.c index 21bfb6bbe..b8ac31aa0 100644 --- a/xargs.c +++ b/xargs.c @@ -28,68 +28,19 @@ #include #include #include - -/* get_sh_safe_line_from_file() - This function reads an entire line from a text file - * up to a newline. It returns a malloc'ed char * which must be stored and - * free'ed by the caller. */ -extern char *get_sh_safe_line_from_file(FILE *file) -{ - static const int GROWBY = 80; /* how large we will grow strings by */ - - char ch, last_ch = 0; - char tmp[]=" "; - int idx = 0; - char *linebuf = NULL; - int linebufsz = 0; - - while (1) { - ch = fgetc(file); - if (ch == EOF) - break; - - /* grow the line buffer as necessary */ - while (idx > linebufsz-4) - linebuf = xrealloc(linebuf, linebufsz += GROWBY); - - /* Remove any extra spaces */ - if (last_ch == ' ' && ch == ' ') - continue; - - /* Replace any tabs with spaces */ - if (ch == '\t') - ch=' '; - - /* Escape any characters that are treated specially by /bin/sh */ - *tmp=ch; - if (strpbrk(tmp, "\\~`!$^&*()=|{}[];\"'<>?#") != NULL && last_ch!='\\') { - linebuf[idx++] = '\\'; - } - - linebuf[idx++] = ch; - last_ch=ch; - - if (ch == '\n') - break; - } - if (idx == 0 && last_ch!=0) - linebuf[idx++]=' '; - - if (idx == 0) - return NULL; - - linebuf[idx] = 0; - return linebuf; -} - +#include +#include int xargs_main(int argc, char **argv) { char *in_from_stdin = NULL; - char *args_from_cmdline = NULL; + char *args = NULL; char *cmd_to_be_executed = NULL; char traceflag = 0; - int len_args_from_cmdline, len_cmd_to_be_executed, len, opt; + int len_args=10, len_cmd_to_be_executed, opt; + pid_t pid; + int wpid, status; /* Note that we do not use getopt here, since * we only want to interpret initial options, @@ -102,50 +53,45 @@ int xargs_main(int argc, char **argv) break; default: fatalError(xargs_usage); - } + } } } - /* Store the command and arguments to be executed (from the command line) */ + /* Store the command to be executed (taken from the command line) */ if (argc == 0) { - len_args_from_cmdline = 6; - args_from_cmdline = xmalloc(len_args_from_cmdline); - strcat(args_from_cmdline, "echo "); + len_cmd_to_be_executed=6; + cmd_to_be_executed = xmalloc(len_cmd_to_be_executed); + strcat(cmd_to_be_executed, "echo"); } else { opt=strlen(*argv); - len_args_from_cmdline = (opt > 10)? opt : 10; - args_from_cmdline = xcalloc(len_args_from_cmdline, sizeof(char)); - while (argc-- > 0) { - if (strlen(*argv) + strlen(args_from_cmdline) > - len_args_from_cmdline) { - len_args_from_cmdline += strlen(*argv); - args_from_cmdline = - xrealloc(args_from_cmdline, - len_args_from_cmdline+1); - } - strcat(args_from_cmdline, *argv); - strcat(args_from_cmdline, " "); - ++argv; - } + len_cmd_to_be_executed = (opt > 10)? opt : 10; + cmd_to_be_executed = xcalloc(len_cmd_to_be_executed, sizeof(char)); + strcat(cmd_to_be_executed, *argv); } - /* Set up some space for the command to be executed to be held in */ - len_cmd_to_be_executed=10; - cmd_to_be_executed = xcalloc(len_cmd_to_be_executed, sizeof(char)); - strcpy(cmd_to_be_executed, args_from_cmdline); - /* Now, read in one line at a time from stdin, and run command+args on it */ - in_from_stdin = get_sh_safe_line_from_file(stdin); + /* Now, read in one line at a time from stdin, and stroe this to be used later + * as an argument to the command we just stored */ + in_from_stdin = get_line_from_file(stdin); for (;in_from_stdin!=NULL;) { char *tmp; opt = strlen(in_from_stdin); - len = opt + len_args_from_cmdline; - len_cmd_to_be_executed+=len+3; - cmd_to_be_executed=xrealloc(cmd_to_be_executed, len_cmd_to_be_executed); + len_args += opt + 3; + args=xrealloc(args, len_args); /* Strip out the final \n */ in_from_stdin[opt-1]=' '; - + + /* Replace any tabs with spaces */ + while( (tmp = strchr(in_from_stdin, '\t')) != NULL ) + *tmp=' '; + + /* Strip out any extra intra-word spaces */ + while( (tmp = strstr(in_from_stdin, " ")) != NULL ) { + opt = strlen(in_from_stdin); + memmove(tmp, tmp+1, opt-(tmp-in_from_stdin)); + } + /* trim trailing whitespace */ opt = strlen(in_from_stdin) - 1; while (isspace(in_from_stdin[opt])) @@ -157,26 +103,49 @@ int xargs_main(int argc, char **argv) while(isspace(*tmp)) tmp++; - strcat(cmd_to_be_executed, tmp); - strcat(cmd_to_be_executed, " "); - + strcat(args, tmp); + strcat(args, " "); + free(in_from_stdin); - in_from_stdin = get_sh_safe_line_from_file(stdin); + in_from_stdin = get_line_from_file(stdin); } - if (traceflag==1) + if (traceflag==1) { fputs(cmd_to_be_executed, stderr); + fputs(args, stderr); + } - if ((system(cmd_to_be_executed) != 0) && (errno != 0)) - fatalError("%s", strerror(errno)); + if ((pid = fork()) == 0) { + char *cmd[255]; + int i=1; + + //printf("argv[0]='%s'\n", cmd_to_be_executed); + cmd[0] = cmd_to_be_executed; + while (--argc && ++argv && *argv ) { + //printf("argv[%d]='%s'\n", i, *argv); + cmd[i++]=*argv; + } + //printf("argv[%d]='%s'\n", i, args); + cmd[i++] = args; + cmd[i] = NULL; + execvp(cmd_to_be_executed, cmd); + + /* What? Still here? Exit with an error */ + fatalError("%s: %s\n", cmd_to_be_executed, strerror(errno)); + } + /* Wait for a child process to exit */ + wpid = wait(&status); #ifdef BB_FEATURE_CLEAN_UP - free(args_from_cmdline); + free(args); free(cmd_to_be_executed); #endif - return 0; + if (wpid > 0) + return (WEXITSTATUS(status)); + else + return EXIT_FAILURE; } /* Local Variables: @@ -185,4 +154,3 @@ c-basic-offset: 4 tab-width: 4 End: */ -