for (;;) { tSCC z_err[] = "Error %d (%s) starting filter process for %s\n"; static int failCt = 0; int fd = chain_open (fdp.read_fd, (t_pchar *) p_fixd->patch_args, (process_chain_head == -1) ? &process_chain_head : (pid_t *) NULL);  if (fd != -1) { fdp.read_fd = fd; break; }  fprintf (stderr, z_err, errno, strerror (errno), p_fixd->fix_name);  if ((errno != EAGAIN) || (++failCt > 10)) exit (EXIT_FAILURE); sleep (1); }
read_fd = start_fixer (read_fd, p_fixd, pz_file_name); num_children++;
process (pz_data, pz_file_name)     char *pz_data;     const char *pz_file_name;{  static char env_current_file[1024] = { "file=" };  tFixDesc *p_fixd = fixDescList;  int todo_ct = FIX_COUNT;  t_fd_pair fdp = { -1, -1 };  /*  IF this is the first time through,      THEN put the 'file' environment variable into the environment.           This is used by some of the subject shell scripts and tests.   */  if (env_current_file[5] == NUL)    putenv (env_current_file);  /*     Ghastly as it is, this actually updates the value of the variable:          putenv(3C)             C Library Functions             putenv(3C)          DESCRIPTION            putenv() makes the value of the  environment  variable  name            equal  to value by altering an existing variable or creating            a new one.  In either case, the string pointed to by  string            becomes part of the environment, so altering the string will            change the environment.  string points to a  string  of  the            form  ``name=value.''  The space used by string is no longer            used once a new string-defining name is passed to putenv().   */  strcpy (env_current_file + 5, pz_file_name);  process_chain_head = NOPROCESS;  fprintf (stderr, "%-50s   \r", pz_file_name );  /* For every fix in our fix list, ...  */  for (; todo_ct > 0; p_fixd++, todo_ct--)    {      tTestDesc *p_test;      int test_ct;      if (p_fixd->fd_flags & FD_SKIP_TEST)        continue;      /*  IF there is a file name restriction,          THEN ensure the current file name matches one in the pattern  */      if (p_fixd->file_list != (char *) NULL)        {          const char *pz_fname = pz_file_name;          const char *pz_scan = p_fixd->file_list;          size_t name_len;          while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))            pz_fname += 2;          name_len = strlen (pz_fname);          for (;;)            {              pz_scan = strstr (pz_scan + 1, pz_fname);              /*  IF we can't match the string at all,                  THEN bail  */              if (pz_scan == (char *) NULL)                goto next_fix;              /*  IF the match is surrounded by the '|' markers,                  THEN we found a full match -- time to run the tests  */              if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))                break;            }        }      /*  FOR each test, see if it fails.          IF it does fail, then we go on to the next test */      for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;           test_ct-- > 0;           p_test++)        {#ifdef DEBUG_TEST          static const char z_test_fail[] =            "%16s test %2d failed for %s\n";#endif          switch (p_test->type)            {            case TT_TEST:              if (!SUCCESSFUL (test_test (p_test, pz_file_name)))                {#ifdef DEBUG_TEST                  fprintf (stderr, z_test_fail, p_fixd->fix_name,                           p_fixd->test_ct - test_ct, pz_file_name);#endif                  goto next_fix;                }              break;            case TT_EGREP:              if (!SUCCESSFUL (egrep_test (pz_data, p_test)))                {#ifdef DEBUG_TEST                  fprintf (stderr, z_test_fail, p_fixd->fix_name,                           p_fixd->test_ct - test_ct, pz_file_name);#endif                  goto next_fix;                }              break;            case TT_NEGREP:              if (SUCCESSFUL (egrep_test (pz_data, p_test)))                {#ifdef DEBUG_TEST                  fprintf (stderr, z_test_fail, p_fixd->fix_name,                           p_fixd->test_ct - test_ct, pz_file_name);#endif                  goto next_fix;                }              break;            }        }      fprintf (stderr, "Applying %-24s to %s\n",               p_fixd->fix_name, pz_file_name);      /*  IF we do not have a read pointer,          THEN this is the first fix for the current file.          Open the source file.  That will be used as stdin for          the first fix.  Any subsequent fixes will use the          stdout descriptor of the previous fix as its stdin.  */      if (fdp.read_fd == -1)        {          fdp.read_fd = open (pz_file_name, O_RDONLY);          if (fdp.read_fd < 0)            {              fprintf (stderr, "Error %d (%s) opening %s\n", errno,                       strerror (errno), pz_file_name);              exit (EXIT_FAILURE);            }        }      /*  This loop should only cycle for 1/2 of one loop.          "chain_open" starts a process that uses "fdp.read_fd" as          its stdin and returns the new fd this process will use          for stdout.  */      for (;;)        {          tSCC z_err[] = "Error %d (%s) starting filter process for %s\n";          static int failCt = 0;          int fd = chain_open (fdp.read_fd,                               (t_pchar *) p_fixd->patch_args,                               (process_chain_head == -1)                               ? &process_chain_head : (pid_t *) NULL);          if (fd != -1)            {              fdp.read_fd = fd;              break;            }          fprintf (stderr, z_err, errno, strerror (errno),                   p_fixd->fix_name);          if ((errno != EAGAIN) || (++failCt > 10))            exit (EXIT_FAILURE);          sleep (1);        }    next_fix:      ;    }  /*  IF after all the tests we did not start any patch programs,      THEN quit now.   */  if (fdp.read_fd < 0)    return;  /*  OK.  We have work to do.  Read back in the output      of the filtering chain.  Compare each byte as we read it with      the contents of the original file.  As soon as we find any      difference, we will create the output file, write out all      the matched text and then copy any remaining data from the      output of the filter chain.      */  {    FILE *in_fp = fdopen (fdp.read_fd, "r");    FILE *out_fp = (FILE *) NULL;    char *pz_cmp = pz_data;    for (;;)      {        int ch;        ch = getc (in_fp);        if (ch == EOF)          break;        /*  IF we are emitting the output            THEN emit this character, too.            */        if (out_fp != (FILE *) NULL)          putc (ch, out_fp);        /*  ELSE if this character does not match the original,            THEN now is the time to start the output.            */        else if (ch != *pz_cmp)          {            out_fp = create_file (pz_file_name);            /*  IF there are matched data, write it all now. */            if (pz_cmp != pz_data)              {                char c = *pz_cmp;                                *pz_cmp = NUL;                fputs (pz_data, out_fp);                *pz_cmp = c;              }            /*  Emit the current unmatching character */            putc (ch, out_fp);          }        else          /*  ELSE the character matches.  Advance the compare ptr */          pz_cmp++;      }    /*  IF we created the output file, ... */    if (out_fp != (FILE *) NULL)      {        regmatch_t match;        /* Close the file and see if we have to worry about	   `#include "file.h"' constructs.  */        fclose (out_fp);        if (regexec (&incl_quote_re, pz_data, 1, &match, 0) == 0)          extract_quoted_files (pz_data, pz_file_name, &match);      }    fclose (in_fp);  }  close (fdp.read_fd);  /* probably redundant, but I'm paranoid */}