home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / f / find37.zip / find-3.7 / xargs / xargs.c < prev   
C/C++ Source or Header  |  1992-07-03  |  22KB  |  927 lines

  1. /* xargs -- build and execute command lines from standard input
  2.    Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Author:
  19.     Mike Rendell            Department of Computer Science
  20.     michael@garfield.mun.edu    Memorial University of Newfoundland
  21.     ..!uunet!garfield!michael    St. John's, Nfld., Canada
  22.     (709) 737-4550            A1C 5S7
  23.  
  24. Usage: xargs [-0ptx] [-e[eof-str]] [-i[replace-str]] [-l[max-lines]]
  25.        [-n max-args] [-s max-chars] [-P max-procs] [--null] [--eof[=eof-str]
  26.        [--replace[=replace-str] [--max-lines[=max-lines] [--interactive]
  27.        [--max-chars max-chars] [--verbose] [--exit] [--max-procs max-procs]
  28.        [command [initial-arguments]]
  29.  
  30.    Read arguments from stdin, delimited by blanks (which can be quoted
  31.    or escaped) or newlines, and execute the COMMAND (default is echo)
  32.    one or more times with any INITIAL-ARGUMENTS plus arguments read
  33.    from stdin.  Blank lines on stdin are ignored.
  34.  
  35.    Options:
  36.    --null
  37.    -0            Input filenames are terminated by a '\0' instead
  38.             of by whitespace and no quoting characters
  39.             are special (every character is taken literally).
  40.             However, any eof string is still recognized.
  41.             Useful with GNU find -print0 when filenames might
  42.             contain newlines or quote marks or backslashes.
  43.  
  44.    --eof[=eof-str]
  45.    -e[eof-str]        Set the eof string to EOF-STR.  If EOF-STR is
  46.             omitted, there is no eof string.  If this option
  47.             is not given, the eof string defaults to "_".
  48.  
  49.    --replace[=replace-str]
  50.    -i[replace-str]    Replace occurences of REPLACE-STR in initial
  51.             args with argument.  If REPLACE-STR is omitted, it
  52.             defaults to "{}" (like for `find -exec').  Implies -x.
  53.             Execute the command once per line of input.
  54.  
  55.    --max-lines[=max-lines]
  56.    -l[max-lines]    Use at most MAX-LINES nonblank input lines per command
  57.             line; MAX-LINES defaults to 1 if omitted.  Implies -x.
  58.             Trailing blanks cause an input line to be logically
  59.             continued on the next input line.
  60.  
  61.    --max-args max-args
  62.    -n max-args        Use at most MAX-ARGS arguments per command line.  Fewer
  63.             than MAX-ARGS arguments will be used if the size
  64.             (see -s) is exceeded, unless the -x option is given,
  65.             in which case xargs will exit.
  66.  
  67.    --interactive
  68.    -p            Ask user about each command line before running it.
  69.             Implies -t.
  70.  
  71.    --no-run-if-empty
  72.    -r            If the standard input does not contain any nonblanks,
  73.             do not run the command.  Normally, the command is run
  74.             once even if there is no input.
  75.  
  76.    --max-chars max-chars
  77.    -s max-chars        Use at most MAX-CHARS characters per command line,
  78.             including command and initial arguments.
  79.             Default is as large as possible.
  80.  
  81.    --verbose
  82.    -t            Print command line string on stderr before executing.
  83.  
  84.    --exit
  85.    -x            Exit if size (see -s) is exceeded.
  86.  
  87.    --max-procs max-procs
  88.    -P max-procs        Run up to MAX-PROCS processes at a time (default is 1).
  89.             If MAX-PROCS is 0 it will run as many as possible.
  90.             Should use -n with -P; otherwise chances are that
  91.             only one exec will be done. */
  92.  
  93. #define _GNU_SOURCE
  94. #include <ctype.h>
  95. #ifndef isblank
  96. #define isblank(c) ((c) == ' ' || (c) == '\t')
  97. #endif
  98. #define ISSPACE(c) (isblank (c) || (c) == '\n' || (c) == '\r' || (c) == '\f' || (c) == '\v')
  99. #include <stdio.h>
  100. #include <errno.h>
  101. #include <getopt.h>
  102.  
  103. /* COMPAT:  SYSV version defaults size (and has a max value of) to 470. We
  104.    try to make it as large as possible. */
  105. #if defined(USG) || defined(STDC_HEADERS)
  106. #include <string.h>
  107.  
  108. #if !defined(STDC_HEADERS)
  109. #include <memory.h>
  110. #endif
  111.  
  112. #define bcopy(source, dest, count) (memcpy((dest), (source), (count)))
  113. #else                /* USG || STDC_HEADERS */
  114. #include <strings.h>
  115. #endif                /* USG || STDC_HEADERS */
  116.  
  117. char *strstr ();
  118.  
  119. #ifndef _POSIX_SOURCE
  120. #include <sys/param.h>
  121. #endif
  122.  
  123. #ifdef HAVE_LIMITS_H
  124. #include <limits.h>
  125. #endif
  126.  
  127. #ifdef HAVE_UNISTD_H
  128. #include <unistd.h>
  129. #endif
  130.  
  131. #ifdef _POSIX_VERSION
  132. #ifdef ARG_MAX
  133. #undef ARG_MAX
  134. #endif /* ARG_MAX */
  135. #define ARG_MAX sysconf (_SC_ARG_MAX)
  136. #endif /* _POSIX_VERSION */
  137.  
  138. #ifndef ARG_MAX
  139. #define ARG_MAX NCARGS
  140. #endif
  141.  
  142. #include "wait.h"
  143.  
  144. /* States for read_line. */
  145. #define NORM 0
  146. #define SPACE 1
  147. #define QUOTE 2
  148. #define BACKSLASH 3
  149.  
  150. /* A linked list of processes that we have forked off. */
  151. struct pid_list
  152. {
  153.   int pl_pid;
  154.   struct pid_list *pl_next;
  155. };
  156.  
  157. #ifdef STDC_HEADERS
  158. #include <stdlib.h>
  159. #else
  160. char *malloc ();
  161. void exit ();
  162. void free ();
  163. long strtol ();
  164.  
  165. extern int errno;
  166. #endif
  167.  
  168. char *strdup ();
  169.  
  170. char *xmalloc ();
  171. int print_args ();
  172. int read_line ();
  173. int read_string ();
  174. long env_size ();
  175. long parse_num ();
  176. void add_proc ();
  177. void do_exec ();
  178. void do_insert ();
  179. void error ();
  180. void push_arg ();
  181. void usage ();
  182. void wait_for_proc ();
  183.  
  184. extern char **environ;
  185.  
  186. /* The name this program was run with. */
  187. char *program_name;
  188.  
  189. /* If nonzero, then instead of putting the args from stdin
  190.    at the end of the command argument list, they are each stuck into the
  191.    initial args, replacing each occurrence of the `replace_pat' in the
  192.    initial args. */
  193. char *replace_pat = 0;
  194.  
  195. /* If nonzero, when this string is read on stdin it is treated as end of file.
  196.    I don't like this - it should default to NULL. */
  197. char *eof_str = "_";
  198.  
  199. /* If nonzero, the maximum number of nonblank lines from stdin to use
  200.    per command line. */
  201. long lines_per_exec = 0;
  202.  
  203. /* The maximum number of arguments to use per command line.
  204.    The default is specified by POSIX. */
  205. long nargs_per_exec = 255;
  206.  
  207. /* The maximum number of characters that can be used per command line. */
  208. long arg_max;
  209.  
  210. /* If nonzero, print each command on stderr before executing it. */
  211. int print_command = 0;
  212.  
  213. /* If nonzero, exit if lines_per_exec or nargs_per_exec is exceeded. */
  214. int exit_if_size_exceeded = 0;
  215.  
  216. /* If nonzero, query the user before executing each command, and only
  217.    execute the command if the user responds affirmatively. */
  218. int query_before_executing = 0;
  219.  
  220. /* If nonzero, run the command at least once, even if there is no input. */
  221. int always_run_command = 1;
  222.  
  223. /* If nonzero, the maximum number of child processes that can be running
  224.    at once. */
  225. int proc_max = 1;
  226.  
  227. /* Total number of child processes that have been executed. */
  228. int processes_executed = 0;
  229.  
  230. /* List of child processes currently executing. */
  231. struct pid_list *pid_list = 0;
  232.  
  233. /* The number of elements in `pid_list'. */
  234. int procs_executing = 0;
  235.  
  236. /* Default program to run. */
  237. char def_prog[] = "/bin/echo";
  238.  
  239. /* Buffer for reading arguments from stdin. */
  240. char *linebuf;
  241.  
  242. /* Temporary copy of each arg with the replace pattern replaced by the
  243.    real arg. */
  244. char *insertbuf;
  245.  
  246. /* Line number in stdin since the last command was executed. */
  247. int lineno = 0;
  248.  
  249. /* The list of args being built. */
  250. char **cmd_argv = 0;
  251.  
  252. /* Number of elements allocated for `cmd_argv'. */
  253. int cmd_nargv = 0;
  254.  
  255. /* Number of valid elements in `cmd_argv'. */
  256. int cmd_argc = 0;
  257.  
  258. /* Number of chars in `cmd_argv'. */
  259. int cmd_ncargs = 0;
  260.  
  261. /* Number of initial arguments given on the command line. */
  262. int cmd_initial_argc = 0;
  263.  
  264. /* Number of chars in the initial args. */
  265. int cmd_initial_ncargs = 0;
  266.  
  267. /* Nonzero when building up initial arguments in `cmd_argv'. */
  268. int static_args = 1;
  269.  
  270. /* Nonzero (exit status) if any child process exited with a status of 1-125. */
  271. int child_error = 0;
  272.  
  273. /* For reading user response to prompting from /dev/tty. */
  274. FILE *tty_stream;
  275.  
  276. struct option longopts[] =
  277. {
  278.   {"null", 0, NULL, '0'},
  279.   {"eof", 2, NULL, 'e'},
  280.   {"replace", 2, NULL, 'i'},
  281.   {"max-lines", 2, NULL, 'l'},
  282.   {"max-args", 1, NULL, 'n'},
  283.   {"interactive", 0, NULL, 'p'},
  284.   {"no-run-if-empty", 0, NULL, 'r'},
  285.   {"max-chars", 1, NULL, 's'},
  286.   {"verbose", 0, NULL, 't'},
  287.   {"exit", 0, NULL, 'x'},
  288.   {"max-procs", 1, NULL, 'P'},
  289.   {NULL, 0, NULL, 0}
  290. };
  291.  
  292. void
  293. main (argc, argv)
  294.      int argc;
  295.      char **argv;
  296. {
  297.   int optc;
  298.   long orig_arg_max;
  299.   char *dummy;
  300.   int (*read_args) () = read_line;
  301.  
  302.   program_name = argv[0];
  303.  
  304.   /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which
  305.      have it at 1 meg).  Things will work fine with a large ARG_MAX but it
  306.      will probably hurt the system more than it needs to; an array of this
  307.      size is allocated.  */
  308.   arg_max = ARG_MAX;
  309.   if (arg_max > 20 * 1024)
  310.     arg_max = 20 * 1024;
  311.  
  312.   /* Adjust arg_max to take the size of the environment into account. */
  313.   arg_max -= env_size (environ);
  314.   if (arg_max <= 0)
  315.     error (1, 0, "environment too large for exec");
  316.   orig_arg_max = arg_max;
  317.  
  318.   while ((optc = getopt_long (argc, argv, "+0e::i::l::n:prs:txP:",
  319.                   longopts, (int *) 0)) != EOF)
  320.     {
  321.       switch (optc)
  322.     {
  323.     case '0':
  324.       read_args = read_string;
  325.       break;
  326.  
  327.     case 'e':
  328.       if (optarg)
  329.         eof_str = optarg;
  330.       else
  331.         eof_str = 0;
  332.       break;
  333.  
  334.     case 'i':
  335.       if (optarg)
  336.         replace_pat = optarg;
  337.       else
  338.         replace_pat = "{}";
  339.       /* -i excludes -n -l. */
  340.       nargs_per_exec = 0;
  341.       lines_per_exec = 0;
  342.       break;
  343.  
  344.     case 'l':
  345.       if (optarg)
  346.         lines_per_exec = parse_num (optarg, 'l', 1L, -1L);
  347.       else
  348.         lines_per_exec = 1;
  349.       /* -l excludes -i -n. */
  350.       nargs_per_exec = 0;
  351.       replace_pat = 0;
  352.       break;
  353.       
  354.     case 'n':
  355.       nargs_per_exec = parse_num (optarg, 'n', 1L, -1L);
  356.       /* -n excludes -i -l. */
  357.       lines_per_exec = 0;
  358.       replace_pat = 0;
  359.       break;
  360.       
  361.     case 's':
  362.       arg_max = parse_num (optarg, 's', 1L, orig_arg_max);
  363.       break;
  364.       
  365.     case 't':
  366.       print_command++;
  367.       break;
  368.       
  369.     case 'x':
  370.       exit_if_size_exceeded++;
  371.       break;
  372.       
  373.     case 'p':
  374.       query_before_executing++;
  375.       break;
  376.       
  377.     case 'r':
  378.       always_run_command = 0;
  379.       break;
  380.  
  381.     case 'P':
  382.       proc_max = parse_num (optarg, 'P', 0L, -1L);
  383.       break;
  384.       
  385.     default:
  386.       usage ();
  387.     }
  388.     }
  389.  
  390.   if (query_before_executing)
  391.     {
  392.       print_command++;
  393.       tty_stream = fopen ("/dev/tty", "r");
  394.       if (!tty_stream)
  395.     error (1, errno, "/dev/tty");
  396.     }
  397.   if (replace_pat || lines_per_exec)
  398.     exit_if_size_exceeded++;
  399.  
  400.   linebuf = xmalloc ((unsigned) arg_max + 1);
  401.  
  402.   if (optind == argc)
  403.     {
  404.       optind = 0;
  405.       argc = 1;
  406.       dummy = def_prog;
  407.       argv = &dummy;
  408.     }
  409.  
  410.   if (!replace_pat)
  411.     {
  412.       while (optind < argc)
  413.     push_arg (argv[optind++]);
  414.       static_args = 0;
  415.  
  416.       cmd_initial_argc = cmd_argc;
  417.       cmd_initial_ncargs = cmd_ncargs;
  418.  
  419.       while ((*read_args) () == 0)
  420.     if (lines_per_exec && lineno >= lines_per_exec)
  421.       {
  422.         do_exec ();
  423.         lineno = 0;
  424.       }
  425.  
  426.       /* SYSV xargs seems to do at least one exec, even if the
  427.          input is empty. */
  428.       if (cmd_argc != cmd_initial_argc
  429.       || (always_run_command && processes_executed == 0))
  430.     do_exec ();
  431.     }
  432.   else
  433.     {
  434.       int ac;
  435.       char **av;
  436.  
  437.       insertbuf = xmalloc ((unsigned) arg_max + 1);
  438.       while ((*read_args) () == 0)
  439.     {
  440.       push_arg (argv[optind]);    /* Don't do insert on command name. */
  441.       for (ac = argc - optind, av = argv + optind; --ac > 0;)
  442.         do_insert (*++av, linebuf);
  443.       do_exec ();
  444.     }
  445.     }
  446.   wait_for_proc (1);
  447.   exit (child_error);
  448. }
  449.  
  450. /* Read a line of arguments from stdin and add them to the list of
  451.    arguments to pass to the command.  Ignore blank lines and initial blanks.
  452.    Single and double quotes and backslashes quote metacharacters and blanks
  453.    as they do in the shell.
  454.    Return -1 if eof (either physical or logical) is reached, 0 otherwise. */
  455.  
  456. int
  457. read_line ()
  458. {
  459.   static int eof = 0;
  460.   /* Start out in mode SPACE to always strip leading spaces (even with -i). */
  461.   int state = SPACE;        /* The type of character we last read. */
  462.   int lastc;            /* The previous value of c. */
  463.   int quotc;            /* The last quote character read. */
  464.   int c = EOF;
  465.   int first = 1;        /* Nonzero if reading first arg on the line. */
  466.   char *p = linebuf;
  467.   char *endbuf = linebuf + arg_max - 1;
  468.  
  469.   if (eof)
  470.     return -1;
  471.   while (1)
  472.     {
  473.       lastc = c;
  474.       c = getc (stdin);
  475.       if (c == EOF)
  476.     {
  477.       /* COMPAT: SYSV seems to ignore stuff on a line that
  478.          ends without a \n; we don't.  */
  479.       eof = 1;
  480.       if (p == linebuf)
  481.         return -1;
  482.       *p = '\0';
  483.       if (eof_str && first && !strcmp (eof_str, linebuf))
  484.         return -1;
  485.       if (!replace_pat)
  486.         push_arg (linebuf);
  487.       return 0;
  488.     }
  489.       switch (state)
  490.     {
  491.     case SPACE:
  492.       if (ISSPACE (c))
  493.         continue;
  494.       state = NORM;
  495.       /* aaahhhh.... */
  496.  
  497.     case NORM:
  498.       if (c == '\n')
  499.         {
  500.           if (!isblank (lastc))
  501.         lineno++;    /* For -l. */
  502.           if (p == linebuf)
  503.         {
  504.           state = SPACE;
  505.           continue;
  506.         }
  507.           *p = '\0';
  508.           if (eof_str && !strcmp (eof_str, linebuf))
  509.         {
  510.           eof = 1;
  511.           return first ? -1 : 0;
  512.         }
  513.           if (!replace_pat)
  514.         push_arg (linebuf);
  515.           return 0;
  516.         }
  517.       if (!replace_pat && ISSPACE (c))
  518.         {
  519.           *p = '\0';
  520.           if (eof_str && !strcmp (eof_str, linebuf))
  521.         {
  522.           eof = 1;
  523.           return first ? -1 : 0;
  524.         }
  525.           p = linebuf;
  526.           push_arg (p);
  527.           state = SPACE;
  528.           first = 0;
  529.           continue;
  530.         }
  531.       switch (c)
  532.         {
  533.         case '\\':
  534.           state = BACKSLASH;
  535.           continue;
  536.           
  537.         case '\'':
  538.         case '"':
  539.           state = QUOTE;
  540.           quotc = c;
  541.           continue;
  542.         }
  543.       break;
  544.  
  545.     case QUOTE:
  546.       if (c == '\n')
  547.         error (1, 0, "%s quote did not end before line did",
  548.            quotc == '"' ? "double" : "single");
  549.       if (c == quotc)
  550.         {
  551.           state = NORM;
  552.           continue;
  553.         }
  554.       break;
  555.  
  556.     case BACKSLASH:
  557.       state = NORM;
  558.       break;
  559.     }
  560.       if (p >= endbuf)
  561.     error (1, 0, "argument line too long");
  562.       *p++ = c;
  563.     }
  564. }
  565.  
  566. /* Read a null-terminated string from stdin and add it to the list of
  567.    arguments to pass to the command.
  568.    Return -1 if eof (either physical or logical) is reached, 0 otherwise. */
  569.  
  570. int
  571. read_string ()
  572. {
  573.   static int eof = 0;
  574.   int c;
  575.   char *p = linebuf;
  576.   char *endbuf = linebuf + arg_max - 1;
  577.  
  578.   if (eof)
  579.     return -1;
  580.   while (1)
  581.     {
  582.       c = getc (stdin);
  583.       if (c == EOF)
  584.     {
  585.       eof = 1;
  586.       if (p == linebuf)
  587.         return -1;
  588.       *p = '\0';
  589.       if (eof_str && !strcmp (eof_str, linebuf))
  590.         return -1;
  591.       if (!replace_pat)
  592.         push_arg (linebuf);
  593.       return 0;
  594.     }
  595.       if (c == '\0')
  596.     {
  597.       lineno++;    /* For -l. */
  598.       *p = '\0';
  599.       if (eof_str && !strcmp (eof_str, linebuf))
  600.         {
  601.           eof = 1;
  602.           return -1;
  603.         }
  604.       if (!replace_pat)
  605.         push_arg (linebuf);
  606.       return 0;
  607.     }
  608.       if (p >= endbuf)
  609.     error (1, 0, "argument line too long");
  610.       *p++ = c;
  611.     }
  612. }
  613.  
  614. /* Print the arguments of the command to execute.
  615.    If ASK is nonzero, prompt the user for a response, and
  616.    if the user responds affirmatively, return 1.
  617.    Otherwise, return 0. */
  618.  
  619. int
  620. print_args (ask)
  621.      int ask;
  622. {
  623.   int i;
  624.  
  625.   for (i = 0; i < cmd_argc - 1; i++)
  626.     fprintf (stderr, "%s ", cmd_argv[i]);
  627.   if (ask)
  628.     {
  629.       int c, savec;
  630.  
  631.       fputs ("?...", stderr);
  632.       fflush (stderr);
  633.       c = savec = getc (tty_stream);
  634.       while (c != EOF && c != '\n')
  635.     c = getc (tty_stream);
  636.       if (savec == 'y' || savec == 'Y')
  637.     return 1;
  638.     }
  639.   else
  640.     putc ('\n', stderr);
  641.  
  642.   return 0;
  643. }
  644.  
  645. /* Return the value of the number represented in STR.
  646.    OPTION is the command line option to which STR is the argument.
  647.    If the value does not fall within the boundaries MIN and MAX,
  648.    Print an error message mentioning OPTION and exit. */
  649.  
  650. long
  651. parse_num (str, option, min, max)
  652.      char *str;
  653.      int option;
  654.      long min;
  655.      long max;
  656. {
  657.   char *eptr;
  658.   long val;
  659.  
  660.   val = strtol (str, &eptr, 10);
  661.   if (eptr == str || *eptr)
  662.     {
  663.       fprintf (stderr, "%s: invalid number for -%c option\n",
  664.            program_name, option);
  665.       usage ();
  666.     }
  667.   else if (val < min)
  668.     {
  669.       fprintf (stderr, "%s: value for -%c option must be >= %d\n",
  670.            program_name, option, min);
  671.       usage ();
  672.     }
  673.   else if (max >= 0 && val > max)
  674.     {
  675.       fprintf (stderr, "%s: value for -%c option must be < %ld\n",
  676.            program_name, option, max);
  677.       usage ();
  678.     }
  679.   return val;
  680. }
  681.  
  682. /* Add ARG to the end of the list of arguments `cmd_argv' to pass
  683.    to the command.
  684.    If this brings the list up to its maximum size, execute the command. */
  685.  
  686. void
  687. push_arg (arg)
  688.      char *arg;
  689. {
  690.   if (arg)
  691.     {
  692.       int len = strlen (arg) + 1;
  693.  
  694.       if (cmd_ncargs + len > arg_max)
  695.     {
  696.       if (static_args || cmd_argc == cmd_initial_argc)
  697.         error (1, 0, "can not fit single argument within argument list size limit");
  698.       if (replace_pat
  699.           || exit_if_size_exceeded && (lines_per_exec || nargs_per_exec))
  700.         error (1, 0, "argument list too long");
  701.       do_exec ();
  702.     }
  703.       if (!static_args && nargs_per_exec &&
  704.       cmd_argc - cmd_initial_argc == nargs_per_exec)
  705.     do_exec ();
  706.       cmd_ncargs += len;
  707.     }
  708.   if (cmd_argc >= cmd_nargv)
  709.     {
  710.       char **new_argv;
  711.  
  712.       if (!cmd_argv)
  713.     cmd_nargv = 50;
  714.       new_argv = (char **)
  715.         xmalloc ((unsigned) (sizeof (char *) * cmd_nargv * 2));
  716.       cmd_nargv *= 2;
  717.       if (cmd_argv)
  718.     {
  719.       bcopy ((char *) cmd_argv, (char *) new_argv,
  720.          sizeof (char *) * cmd_argc);
  721.       free ((char *) cmd_argv);
  722.     }
  723.       cmd_argv = new_argv;
  724.     }
  725.   if (!arg)
  726.     cmd_argv[cmd_argc++] = 0;
  727.   else
  728.     {
  729.       cmd_argv[cmd_argc] = strdup (arg);
  730.       if (!cmd_argv[cmd_argc++])
  731.     error (1, 0, "virtual memory exhausted");
  732.     }
  733. }
  734.  
  735. /* Execute the command that has been built in `cmd_argv'.  This may involve
  736.    waiting for processes that were previously executed.
  737.    Also free the memory used by the command's arguments.
  738.  
  739.    COMPAT: since we don't wait for the process to complete before returning,
  740.    it is possible that we won't notice a command failing until the next
  741.    time do_exec is called.  This is only noticeable when xargs is run
  742.    interactivly.  It can be fixed by adding
  743.    if (proc_max == 1)
  744.      wait_for_proc (0)
  745.    after the add_proc call. */
  746.  
  747. void
  748. do_exec ()
  749. {
  750.   int child;
  751.  
  752.   push_arg ((char *) 0);    /* Null terminate the arg list. */
  753.   if (!query_before_executing || print_args (1))
  754.     {
  755.       if (proc_max && procs_executing >= proc_max)
  756.     wait_for_proc (0);
  757.       if (!query_before_executing && print_command)
  758.     print_args (0);
  759.       /* If we run out of processes, wait for a child to return and
  760.          try again.  */
  761.       while ((child = fork ()) < 0 && errno == EAGAIN && procs_executing)
  762.     wait_for_proc (0);
  763.       switch (child)
  764.     {
  765.     case -1:
  766.       error (1, errno, "cannot fork");
  767.  
  768.     case 0:            /* Child. */
  769.       execvp (cmd_argv[0], cmd_argv);
  770.       error (0, errno, "%s", cmd_argv[0]);
  771.       _exit (errno == ENOENT ? 127 : 126);
  772.     }
  773.       add_proc (child);
  774.       processes_executed++;
  775.     }
  776.  
  777.   --cmd_argc;            /* For the trailing null. */
  778.   while (--cmd_argc > cmd_initial_argc)
  779.     free (cmd_argv[cmd_argc]);
  780.   cmd_ncargs = cmd_initial_ncargs;
  781. }
  782.  
  783. /* If ALL is nonzero, wait for all child processes to finish;
  784.    otherwise, wait for one child process to finish.
  785.    Remove the processes that finish from the list of executing processes. */
  786.  
  787. void
  788. wait_for_proc (all)
  789.      int all;
  790. {
  791.   struct pid_list **pl_prev;
  792.   struct pid_list *pl;
  793.   int pid;
  794.   int status;
  795.  
  796.   while (procs_executing)
  797.     {
  798.       do
  799.     {
  800.       pid = wait (&status);
  801.       if (pid < 0)
  802.         error (1, 0, "error waiting for child process");
  803.  
  804.       /* Find the entry in `pid_list' for the child process that exited. */
  805.       pl_prev = &pid_list;
  806.       pl = pid_list;
  807.       while (pl != 0 && pl->pl_pid != pid)
  808.         {
  809.           pl_prev = &pl->pl_next;
  810.           pl = pl->pl_next;
  811.         }
  812.     }
  813.       while (pl == 0);        /* A child died that we didn't start? */
  814.  
  815.       /* Remove the child from the list. */
  816.       *pl_prev = pl->pl_next;
  817.       free ((char *) pl);
  818.       procs_executing--;
  819.  
  820.       if (WEXITSTATUS (status) == 126 || WEXITSTATUS (status) == 127)
  821.     exit (status);        /* Can't find or run the command. */
  822.       if (WEXITSTATUS (status) == 255)
  823.     error (124, 0, "%s: exited with status 255; aborting", cmd_argv[0]);
  824.       if (WIFSTOPPED (status))
  825.     error (125, 0, "%s: stopped by signal %d", cmd_argv[0], WSTOPSIG (status));
  826.       if (WIFSIGNALED (status))
  827.     error (125, 0, "%s: terminated by signal %d", cmd_argv[0], WTERMSIG (status));
  828.       if (WEXITSTATUS (status) != 0)
  829.     child_error = 123;
  830.  
  831.       if (!all)
  832.     break;
  833.     }
  834. }
  835.  
  836. /* Add the process with id PID to the list of processes that have
  837.    been executed. */
  838.  
  839. void
  840. add_proc (pid)
  841.      int pid;
  842. {
  843.   struct pid_list *pl;
  844.  
  845.   pl = (struct pid_list *) xmalloc (sizeof (struct pid_list));
  846.   pl->pl_pid = pid;
  847.   pl->pl_next = pid_list;
  848.   pid_list = pl;
  849.   procs_executing++;
  850. }
  851.  
  852. /* Replace all instances of `replace_pat' in ARG with LINE, and add the
  853.    resulting string to the list of arguments for the command to execute.
  854.  
  855.    COMPAT: insertions on the SYSV version are limited to 255 chars per line,
  856.    and a max of 5 occurences of replace_pat in the initial-arguments.  These
  857.    restristrions do not exist here.  */
  858.  
  859. void
  860. do_insert (arg, line)
  861.      char *arg;
  862.      char *line;
  863. {
  864.   char *p = insertbuf;
  865.   char *s;
  866.   int cnt = arg_max - 1;    /* Bytes left on the command line. */
  867.   int len;            /* Length of ARG before `replace_pat'. */
  868.   int ilen = strlen (replace_pat);
  869.   int llen = strlen (line);
  870.  
  871.   do
  872.     {
  873.       s = strstr (arg, replace_pat);
  874.       if (s)
  875.     len = s - arg;
  876.       else
  877.     len = strlen (arg);
  878.       cnt -= len;
  879.       if (cnt <= 0)
  880.     break;
  881.       strncpy (p, arg, len);
  882.       p += len;
  883.       arg += len;
  884.       if (s)
  885.     {
  886.       cnt -= llen;
  887.       if (cnt <= 0)
  888.         break;
  889.       strcpy (p, line);
  890.       arg += ilen;
  891.       p += llen;
  892.     }
  893.     }
  894.   while (*arg);
  895.   if (*arg)
  896.     error (1, 0, "command too long");
  897.   *p = '\0';
  898.   push_arg (insertbuf);
  899. }
  900.  
  901. /* Return how much of ARG_MAX is used by the environment. */
  902.  
  903. long
  904. env_size (envp)
  905.      char **envp;
  906. {
  907.   long len = 0;
  908.  
  909.   while (*envp)
  910.     len += strlen (*envp++) + 1;
  911.  
  912.   return len;
  913. }
  914.  
  915. void
  916. usage ()
  917. {
  918.   fprintf (stderr, "\
  919. Usage: %s [-0prtx] [-e[eof-str]] [-i[replace-str]] [-l[max-lines]]\n\
  920.        [-n max-args] [-s max-chars] [-P max-procs] [--null] [--eof[=eof-str]\n\
  921.        [--replace[=replace-str] [--max-lines[=max-lines] [--interactive]\n\
  922.        [--max-chars max-chars] [--verbose] [--exit] [--max-procs max-procs]\n\
  923.        [--no-run-if-empty] [command [initial-arguments]]\n",
  924.        program_name);
  925.   exit (1);
  926. }
  927.