Support for tar -z option for uncompressing only
[oweals/busybox.git] / xargs.c
diff --git a/xargs.c b/xargs.c
index be1fada78ba458c79ac1476fe577bf114345e5e7..c5f7b208c425cb2cebc7c168a5c7cca045779655 100644 (file)
--- a/xargs.c
+++ b/xargs.c
-/* minix xargs - Make and execute commands          
- * Author: Ian Nicholls:  1 Mar 90 */
-
 /*
- * xargs  - Accept words from stdin until, combined with the arguments
- *         given on the command line, just fit into the command line limit.
- *         Then, execute the result.
- *             e.g.    ls | xargs compress
- *                     find . -name '*.s' -print | xargs ar qv libc.a
+ * Mini xargs implementation for busybox
+ *
+ * Copyright (C) 2000 by Lineo, inc.
+ * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
+ * Remixed by Mark Whitley <markw@lineo.com>, <markw@enol.com>
  *
- * flags: -t           Print the command just before it is run
- *       -l len        Use len as maximum line length (default 490, max 1023)
- *       -e ending     Append ending to the command before executing it.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * Exits with: 0  No errors.
- *             1  If any system(3) call returns a nonzero status.
- *             2  Usage error
- *             3  Line length too short to contain some single argument.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
  *
- * Examples:   xargs ar qv libc.a < liborder           # Create a new libc.a
- *             find . -name '*.s' -print | xargs rm    # Remove all .s files
- *             find . -type f ! -name '*.Z' \          # Compress old files.
- *                    -atime +60 -print  | xargs compress -v
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
- * Bugs:  If the command contains unquoted wildflags, then the system(3) call
- *             call may expand this to larger than the maximum line size.
- *       The command is not executed if nothing was read from stdin.
- *       xargs may give up too easily when the command returns nonzero.
  */
-#define USAGE "usage: xargs [-t] [-l len] [-e endargs] command [args...]\n"
 
-#include <errno.h>
+#include "busybox.h"
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <stdio.h>
-#include <getopt.h>
 
-#ifndef MAX_ARGLINE
-# define MAX_ARGLINE 1023
-#endif
-#ifndef min
-# define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
+int xargs_main(int argc, char **argv)
+{
+       char *cmd_to_be_executed = NULL;
+       char *file_to_act_on = NULL;
 
-char outlin[MAX_ARGLINE];
-char inlin[MAX_ARGLINE];
-char startlin[MAX_ARGLINE];
-char *ending = NULL;
-char traceflag = 0;
+       /*
+        * No options are supported in this version of xargs; no getopt.
+        *
+        * Re: The missing -t flag: Most programs that produce output also print
+        * the filename, so xargs doesn't really need to do it again. Supporting
+        * the -t flag =greatly= bloats up the size of this app and the memory it
+        * uses because you have to buffer all the input file strings in memory. If
+        * you really want to see the filenames that xargs will act on, just run it
+        * once with no args and xargs will echo the filename. Simple.
+        */
 
-int xargs_main(int ac, char **av)
-{
-   int outlen, inlen, startlen, endlen=0, i;
-   char errflg = 0;
-   int maxlin = MAX_ARGLINE;
+       /* Store the command to be executed (taken from the command line) */
+       if (argc == 1) {
+               /* default behavior is to echo all the filenames */
+               cmd_to_be_executed = strdup("/bin/echo ");
+       } else {
+               /* concatenate all the arguments passed to xargs together */
+               int i;
+               int len = 1; /* for the '\0' */
+               for (i = 1; i < argc; i++) {
+                       len += strlen(argv[i]);
+                       len += 1;  /* for the space between the args */
+                       cmd_to_be_executed = xrealloc(cmd_to_be_executed, len);
+                       strcat(cmd_to_be_executed, argv[i]);
+                       strcat(cmd_to_be_executed, " ");
+               }
+       }
 
-   while ((i = getopt(ac, av, "tl:e:")) != EOF)
-       switch (i) {
-          case 't': traceflag = 1;       break;
-          case 'l': maxlin = min(MAX_ARGLINE, atoi(optarg)); break;
-          case 'e': ending = optarg;     break;
-          case '?': errflg++;            break;
-       }
-   if (errflg) {
-       fprintf(stderr, USAGE);
-       exit(2);
-   }
+       /* Now, read in one line at a time from stdin, and store this 
+        * line to be used later as an argument to the command */
+       while ((file_to_act_on = get_line_from_file(stdin)) !=NULL) {
 
-   startlin[0] = 0;
-   if (optind == ac) {
-       strcat(startlin, "echo ");
-   }
-   else for ( ; optind < ac; optind++) {
-       strcat(startlin, av[optind]);
-       strcat(startlin, " ");
-   }
-   startlen = strlen(startlin);
-   if (ending) endlen = strlen(ending);
-   maxlin = maxlin - 1 - endlen;       /* Pre-compute */
+               FILE *cmd_output = NULL;
+               char *output_line = NULL;
+               char *execstr = NULL;
 
-   strcpy(outlin, startlin);
-   outlen = startlen;
+               /* eat the newline off the filename. */
+               if (file_to_act_on[strlen(file_to_act_on)-1] == '\n')
+                       file_to_act_on[strlen(file_to_act_on)-1] = '\0';
 
-   while (gets(inlin) != NULL) {
-       inlen = strlen(inlin);
-       if (maxlin <= (outlen + inlen)) {
-          if (outlen == startlen) {
-              fprintf(stderr, "%s: Line length too short to process '%s'\n",
-                      av[0], inlin);
-              exit(3);
-          }
-          if (ending) strcat(outlin, ending);
-          if (traceflag) fputs(outlin,stderr);
-          errno = 0;
-          if (0 != system(outlin)) {
-              if (errno != 0) perror("xargs");
-              exit(1);
-          }
-          strcpy(outlin, startlin);
-          outlen = startlen;
-       }
-       strcat(outlin, inlin);
-       strcat(outlin, " ");
-       outlen = outlen + inlen + 1;
-   }
-   if (outlen != startlen) {
-       if (ending) strcat(outlin, ending);
-       if (traceflag) fputs(outlin,stderr);
-       errno = 0;
-       if (0 != system(outlin)) {
-          if (errno != 0) perror("xargs");
-          exit(1);
-       }
-   }    
-   return 0;
+               /* eat blank lines */
+               if (strlen(file_to_act_on) == 0)
+                       continue;
+
+               /* assemble the command and execute it */
+               execstr = xcalloc(strlen(cmd_to_be_executed) +
+                               strlen(file_to_act_on) + 1, sizeof(char));
+               strcat(execstr, cmd_to_be_executed);
+               strcat(execstr, file_to_act_on);
+               cmd_output = popen(execstr, "r");
+               if (cmd_output == NULL) {
+                       perror("popen");
+                       exit(1);
+               }
+
+               /* harvest the output */
+               while ((output_line = get_line_from_file(cmd_output)) != NULL) {
+                       fputs(output_line, stdout);
+                       free(output_line);
+               }
+
+               /* clean up */
+               pclose(cmd_output);
+               free(execstr);
+               free(file_to_act_on);
+       }
+
+#ifdef BB_FEATURE_CLEAN_UP
+       free(cmd_to_be_executed);
+#endif
+
+       return 0;
 }
+
+/* vi: set sw=4 ts=4: */