diff options
author | Eric Andersen <andersen@codepoet.org> | 2000-09-25 20:23:21 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2000-09-25 20:23:21 +0000 |
commit | e081eae7a469e0ddeebedd51c3d83bcbaccb23e3 (patch) | |
tree | 0a3c6b650ee7f45d101bd6c7c289eaf63f3d6607 /findutils/xargs.c | |
parent | bf73909f23a00bdcc4f4e12459c64b99b2ebcddb (diff) | |
download | busybox-w32-e081eae7a469e0ddeebedd51c3d83bcbaccb23e3.tar.gz busybox-w32-e081eae7a469e0ddeebedd51c3d83bcbaccb23e3.tar.bz2 busybox-w32-e081eae7a469e0ddeebedd51c3d83bcbaccb23e3.zip |
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
Diffstat (limited to 'findutils/xargs.c')
-rw-r--r-- | findutils/xargs.c | 156 |
1 files changed, 62 insertions, 94 deletions
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 @@ | |||
28 | #include <errno.h> | 28 | #include <errno.h> |
29 | #include <getopt.h> | 29 | #include <getopt.h> |
30 | #include <ctype.h> | 30 | #include <ctype.h> |
31 | 31 | #include <sys/types.h> | |
32 | /* get_sh_safe_line_from_file() - This function reads an entire line from a text file | 32 | #include <sys/wait.h> |
33 | * up to a newline. It returns a malloc'ed char * which must be stored and | ||
34 | * free'ed by the caller. */ | ||
35 | extern char *get_sh_safe_line_from_file(FILE *file) | ||
36 | { | ||
37 | static const int GROWBY = 80; /* how large we will grow strings by */ | ||
38 | |||
39 | char ch, last_ch = 0; | ||
40 | char tmp[]=" "; | ||
41 | int idx = 0; | ||
42 | char *linebuf = NULL; | ||
43 | int linebufsz = 0; | ||
44 | |||
45 | while (1) { | ||
46 | ch = fgetc(file); | ||
47 | if (ch == EOF) | ||
48 | break; | ||
49 | |||
50 | /* grow the line buffer as necessary */ | ||
51 | while (idx > linebufsz-4) | ||
52 | linebuf = xrealloc(linebuf, linebufsz += GROWBY); | ||
53 | |||
54 | /* Remove any extra spaces */ | ||
55 | if (last_ch == ' ' && ch == ' ') | ||
56 | continue; | ||
57 | |||
58 | /* Replace any tabs with spaces */ | ||
59 | if (ch == '\t') | ||
60 | ch=' '; | ||
61 | |||
62 | /* Escape any characters that are treated specially by /bin/sh */ | ||
63 | *tmp=ch; | ||
64 | if (strpbrk(tmp, "\\~`!$^&*()=|{}[];\"'<>?#") != NULL && last_ch!='\\') { | ||
65 | linebuf[idx++] = '\\'; | ||
66 | } | ||
67 | |||
68 | linebuf[idx++] = ch; | ||
69 | last_ch=ch; | ||
70 | |||
71 | if (ch == '\n') | ||
72 | break; | ||
73 | } | ||
74 | if (idx == 0 && last_ch!=0) | ||
75 | linebuf[idx++]=' '; | ||
76 | |||
77 | if (idx == 0) | ||
78 | return NULL; | ||
79 | |||
80 | linebuf[idx] = 0; | ||
81 | return linebuf; | ||
82 | } | ||
83 | |||
84 | 33 | ||
85 | 34 | ||
86 | int xargs_main(int argc, char **argv) | 35 | int xargs_main(int argc, char **argv) |
87 | { | 36 | { |
88 | char *in_from_stdin = NULL; | 37 | char *in_from_stdin = NULL; |
89 | char *args_from_cmdline = NULL; | 38 | char *args = NULL; |
90 | char *cmd_to_be_executed = NULL; | 39 | char *cmd_to_be_executed = NULL; |
91 | char traceflag = 0; | 40 | char traceflag = 0; |
92 | int len_args_from_cmdline, len_cmd_to_be_executed, len, opt; | 41 | int len_args=10, len_cmd_to_be_executed, opt; |
42 | pid_t pid; | ||
43 | int wpid, status; | ||
93 | 44 | ||
94 | /* Note that we do not use getopt here, since | 45 | /* Note that we do not use getopt here, since |
95 | * we only want to interpret initial options, | 46 | * we only want to interpret initial options, |
@@ -102,50 +53,45 @@ int xargs_main(int argc, char **argv) | |||
102 | break; | 53 | break; |
103 | default: | 54 | default: |
104 | fatalError(xargs_usage); | 55 | fatalError(xargs_usage); |
105 | } | 56 | } |
106 | } | 57 | } |
107 | } | 58 | } |
108 | 59 | ||
109 | /* Store the command and arguments to be executed (from the command line) */ | 60 | /* Store the command to be executed (taken from the command line) */ |
110 | if (argc == 0) { | 61 | if (argc == 0) { |
111 | len_args_from_cmdline = 6; | 62 | len_cmd_to_be_executed=6; |
112 | args_from_cmdline = xmalloc(len_args_from_cmdline); | 63 | cmd_to_be_executed = xmalloc(len_cmd_to_be_executed); |
113 | strcat(args_from_cmdline, "echo "); | 64 | strcat(cmd_to_be_executed, "echo"); |
114 | } else { | 65 | } else { |
115 | opt=strlen(*argv); | 66 | opt=strlen(*argv); |
116 | len_args_from_cmdline = (opt > 10)? opt : 10; | 67 | len_cmd_to_be_executed = (opt > 10)? opt : 10; |
117 | args_from_cmdline = xcalloc(len_args_from_cmdline, sizeof(char)); | 68 | cmd_to_be_executed = xcalloc(len_cmd_to_be_executed, sizeof(char)); |
118 | while (argc-- > 0) { | 69 | strcat(cmd_to_be_executed, *argv); |
119 | if (strlen(*argv) + strlen(args_from_cmdline) > | ||
120 | len_args_from_cmdline) { | ||
121 | len_args_from_cmdline += strlen(*argv); | ||
122 | args_from_cmdline = | ||
123 | xrealloc(args_from_cmdline, | ||
124 | len_args_from_cmdline+1); | ||
125 | } | ||
126 | strcat(args_from_cmdline, *argv); | ||
127 | strcat(args_from_cmdline, " "); | ||
128 | ++argv; | ||
129 | } | ||
130 | } | 70 | } |
131 | 71 | ||
132 | /* Set up some space for the command to be executed to be held in */ | ||
133 | len_cmd_to_be_executed=10; | ||
134 | cmd_to_be_executed = xcalloc(len_cmd_to_be_executed, sizeof(char)); | ||
135 | strcpy(cmd_to_be_executed, args_from_cmdline); | ||
136 | 72 | ||
137 | /* Now, read in one line at a time from stdin, and run command+args on it */ | 73 | /* Now, read in one line at a time from stdin, and stroe this to be used later |
138 | in_from_stdin = get_sh_safe_line_from_file(stdin); | 74 | * as an argument to the command we just stored */ |
75 | in_from_stdin = get_line_from_file(stdin); | ||
139 | for (;in_from_stdin!=NULL;) { | 76 | for (;in_from_stdin!=NULL;) { |
140 | char *tmp; | 77 | char *tmp; |
141 | opt = strlen(in_from_stdin); | 78 | opt = strlen(in_from_stdin); |
142 | len = opt + len_args_from_cmdline; | 79 | len_args += opt + 3; |
143 | len_cmd_to_be_executed+=len+3; | 80 | args=xrealloc(args, len_args); |
144 | cmd_to_be_executed=xrealloc(cmd_to_be_executed, len_cmd_to_be_executed); | ||
145 | 81 | ||
146 | /* Strip out the final \n */ | 82 | /* Strip out the final \n */ |
147 | in_from_stdin[opt-1]=' '; | 83 | in_from_stdin[opt-1]=' '; |
148 | 84 | ||
85 | /* Replace any tabs with spaces */ | ||
86 | while( (tmp = strchr(in_from_stdin, '\t')) != NULL ) | ||
87 | *tmp=' '; | ||
88 | |||
89 | /* Strip out any extra intra-word spaces */ | ||
90 | while( (tmp = strstr(in_from_stdin, " ")) != NULL ) { | ||
91 | opt = strlen(in_from_stdin); | ||
92 | memmove(tmp, tmp+1, opt-(tmp-in_from_stdin)); | ||
93 | } | ||
94 | |||
149 | /* trim trailing whitespace */ | 95 | /* trim trailing whitespace */ |
150 | opt = strlen(in_from_stdin) - 1; | 96 | opt = strlen(in_from_stdin) - 1; |
151 | while (isspace(in_from_stdin[opt])) | 97 | while (isspace(in_from_stdin[opt])) |
@@ -157,26 +103,49 @@ int xargs_main(int argc, char **argv) | |||
157 | while(isspace(*tmp)) | 103 | while(isspace(*tmp)) |
158 | tmp++; | 104 | tmp++; |
159 | 105 | ||
160 | strcat(cmd_to_be_executed, tmp); | 106 | strcat(args, tmp); |
161 | strcat(cmd_to_be_executed, " "); | 107 | strcat(args, " "); |
162 | 108 | ||
163 | free(in_from_stdin); | 109 | free(in_from_stdin); |
164 | in_from_stdin = get_sh_safe_line_from_file(stdin); | 110 | in_from_stdin = get_line_from_file(stdin); |
165 | } | 111 | } |
166 | 112 | ||
167 | if (traceflag==1) | 113 | if (traceflag==1) { |
168 | fputs(cmd_to_be_executed, stderr); | 114 | fputs(cmd_to_be_executed, stderr); |
115 | fputs(args, stderr); | ||
116 | } | ||
169 | 117 | ||
170 | if ((system(cmd_to_be_executed) != 0) && (errno != 0)) | 118 | if ((pid = fork()) == 0) { |
171 | fatalError("%s", strerror(errno)); | 119 | char *cmd[255]; |
120 | int i=1; | ||
121 | |||
122 | //printf("argv[0]='%s'\n", cmd_to_be_executed); | ||
123 | cmd[0] = cmd_to_be_executed; | ||
124 | while (--argc && ++argv && *argv ) { | ||
125 | //printf("argv[%d]='%s'\n", i, *argv); | ||
126 | cmd[i++]=*argv; | ||
127 | } | ||
128 | //printf("argv[%d]='%s'\n", i, args); | ||
129 | cmd[i++] = args; | ||
130 | cmd[i] = NULL; | ||
131 | execvp(cmd_to_be_executed, cmd); | ||
132 | |||
133 | /* What? Still here? Exit with an error */ | ||
134 | fatalError("%s: %s\n", cmd_to_be_executed, strerror(errno)); | ||
135 | } | ||
136 | /* Wait for a child process to exit */ | ||
137 | wpid = wait(&status); | ||
172 | 138 | ||
173 | 139 | ||
174 | #ifdef BB_FEATURE_CLEAN_UP | 140 | #ifdef BB_FEATURE_CLEAN_UP |
175 | free(args_from_cmdline); | 141 | free(args); |
176 | free(cmd_to_be_executed); | 142 | free(cmd_to_be_executed); |
177 | #endif | 143 | #endif |
178 | 144 | ||
179 | return 0; | 145 | if (wpid > 0) |
146 | return (WEXITSTATUS(status)); | ||
147 | else | ||
148 | return EXIT_FAILURE; | ||
180 | } | 149 | } |
181 | /* | 150 | /* |
182 | Local Variables: | 151 | Local Variables: |
@@ -185,4 +154,3 @@ c-basic-offset: 4 | |||
185 | tab-width: 4 | 154 | tab-width: 4 |
186 | End: | 155 | End: |
187 | */ | 156 | */ |
188 | |||