Home | History | Annotate | Line # | Download | only in fixincludes
      1      1.1  mrg /* Install modified versions of certain ANSI-incompatible system header
      2      1.1  mrg    files which are fixed to work correctly with ANSI C and placed in a
      3      1.1  mrg    directory that GCC will search.
      4      1.1  mrg 
      5  1.1.1.2  mrg    Copyright (C) 1997, 1998, 1999, 2000, 2004, 2009, 2012
      6      1.1  mrg    Free Software Foundation, Inc.
      7      1.1  mrg 
      8      1.1  mrg This file is part of GCC.
      9      1.1  mrg 
     10      1.1  mrg GCC is free software; you can redistribute it and/or modify
     11      1.1  mrg it under the terms of the GNU General Public License as published by
     12      1.1  mrg the Free Software Foundation; either version 3, or (at your option)
     13      1.1  mrg any later version.
     14      1.1  mrg 
     15      1.1  mrg GCC is distributed in the hope that it will be useful,
     16      1.1  mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
     17      1.1  mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18      1.1  mrg GNU General Public License for more details.
     19      1.1  mrg 
     20      1.1  mrg You should have received a copy of the GNU General Public License
     21      1.1  mrg along with GCC; see the file COPYING3.  If not see
     22      1.1  mrg <http://www.gnu.org/licenses/>.  */
     23      1.1  mrg 
     24      1.1  mrg #include "fixlib.h"
     25      1.1  mrg 
     26      1.1  mrg #include <fnmatch.h>
     27      1.1  mrg #include <sys/stat.h>
     28      1.1  mrg #ifndef SEPARATE_FIX_PROC
     29      1.1  mrg #include <sys/wait.h>
     30      1.1  mrg #endif
     31      1.1  mrg 
     32      1.1  mrg #if defined( HAVE_MMAP_FILE )
     33      1.1  mrg #include <sys/mman.h>
     34      1.1  mrg #define  BAD_ADDR ((void*)-1)
     35      1.1  mrg #endif
     36      1.1  mrg 
     37      1.1  mrg #ifndef SEPARATE_FIX_PROC
     38      1.1  mrg #include "server.h"
     39      1.1  mrg #endif
     40      1.1  mrg 
     41      1.1  mrg /*  The contents of this string are not very important.  It is mostly
     42      1.1  mrg     just used as part of the "I am alive and working" test.  */
     43      1.1  mrg 
     44      1.1  mrg static const char program_id[] = "fixincl version 1.1";
     45      1.1  mrg 
     46      1.1  mrg /*  This format will be used at the start of every generated file */
     47      1.1  mrg 
     48      1.1  mrg static const char z_std_preamble[] =
     49      1.1  mrg "/*  DO NOT EDIT THIS FILE.\n\n\
     50      1.1  mrg     It has been auto-edited by fixincludes from:\n\n\
     51      1.1  mrg \t\"%s/%s\"\n\n\
     52      1.1  mrg     This had to be done to correct non-standard usages in the\n\
     53      1.1  mrg     original, manufacturer supplied header file.  */\n\n";
     54      1.1  mrg 
     55      1.1  mrg int find_base_len = 0;
     56      1.1  mrg int have_tty = 0;
     57      1.1  mrg 
     58      1.1  mrg pid_t process_chain_head = (pid_t) -1;
     59      1.1  mrg 
     60      1.1  mrg char*  pz_curr_file;  /*  name of the current file under test/fix  */
     61      1.1  mrg char*  pz_curr_data;  /*  original contents of that file  */
     62      1.1  mrg char*  pz_temp_file;  /*  for DOS, a place to stash the temporary
     63      1.1  mrg                           fixed data between system(3) calls  */
     64      1.1  mrg t_bool curr_data_mapped;
     65      1.1  mrg int    data_map_fd;
     66      1.1  mrg size_t data_map_size;
     67      1.1  mrg size_t ttl_data_size = 0;
     68      1.1  mrg 
     69      1.1  mrg #ifdef DO_STATS
     70      1.1  mrg int process_ct = 0;
     71      1.1  mrg int apply_ct = 0;
     72      1.1  mrg int fixed_ct = 0;
     73      1.1  mrg int altered_ct = 0;
     74      1.1  mrg #endif /* DO_STATS */
     75      1.1  mrg 
     76      1.1  mrg const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
     77      1.1  mrg regex_t incl_quote_re;
     78      1.1  mrg 
     79  1.1.1.4  mrg #ifndef SEPARATE_FIX_PROC
     80  1.1.1.4  mrg tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
     81  1.1.1.4  mrg #endif
     82  1.1.1.4  mrg 
     83      1.1  mrg static void do_version (void) ATTRIBUTE_NORETURN;
     84      1.1  mrg char *load_file (const char *);
     85      1.1  mrg void run_compiles (void);
     86      1.1  mrg void initialize (int argc, char** argv);
     87      1.1  mrg void process (void);
     88      1.1  mrg 
     89      1.1  mrg /*  External Source Code */
     90      1.1  mrg 
     91      1.1  mrg #include "fixincl.x"
     92      1.1  mrg 
     93      1.1  mrg /* * * * * * * * * * * * * * * * * * *
     94      1.1  mrg  *
     95      1.1  mrg  *  MAIN ROUTINE
     96      1.1  mrg  */
     97      1.1  mrg extern int main (int, char **);
     98      1.1  mrg int
     99      1.1  mrg main (int argc, char** argv)
    100      1.1  mrg {
    101      1.1  mrg   char *file_name_buf;
    102      1.1  mrg 
    103      1.1  mrg   initialize ( argc, argv );
    104      1.1  mrg 
    105      1.1  mrg   have_tty = isatty (fileno (stderr));
    106      1.1  mrg 
    107      1.1  mrg   /* Before anything else, ensure we can allocate our file name buffer. */
    108      1.1  mrg   file_name_buf = load_file_data (stdin);
    109      1.1  mrg 
    110      1.1  mrg   /*  Because of the way server shells work, you have to keep stdin, out
    111      1.1  mrg       and err open so that the proper input file does not get closed
    112      1.1  mrg       by accident  */
    113      1.1  mrg 
    114      1.1  mrg   freopen ("/dev/null", "r", stdin);
    115      1.1  mrg 
    116      1.1  mrg   if (file_name_buf == (char *) NULL)
    117      1.1  mrg     {
    118      1.1  mrg       fputs ("No file names listed for fixing\n", stderr);
    119      1.1  mrg       exit (EXIT_FAILURE);
    120      1.1  mrg     }
    121      1.1  mrg 
    122      1.1  mrg   for (;;)
    123      1.1  mrg     {
    124      1.1  mrg       char* pz_end;
    125      1.1  mrg 
    126      1.1  mrg       /*  skip to start of name, past any "./" prefixes */
    127      1.1  mrg 
    128      1.1  mrg       while (ISSPACE (*file_name_buf))  file_name_buf++;
    129      1.1  mrg       while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
    130      1.1  mrg         file_name_buf += 2;
    131      1.1  mrg 
    132      1.1  mrg       /*  Check for end of list  */
    133      1.1  mrg 
    134      1.1  mrg       if (*file_name_buf == NUL)
    135      1.1  mrg         break;
    136      1.1  mrg 
    137      1.1  mrg       /*  Set global file name pointer and find end of name */
    138      1.1  mrg 
    139      1.1  mrg       pz_curr_file = file_name_buf;
    140      1.1  mrg       pz_end = strchr( pz_curr_file, '\n' );
    141      1.1  mrg       if (pz_end == (char*)NULL)
    142      1.1  mrg         pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
    143      1.1  mrg       else
    144      1.1  mrg         file_name_buf = pz_end + 1;
    145      1.1  mrg 
    146      1.1  mrg       while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1]))  pz_end--;
    147      1.1  mrg 
    148      1.1  mrg       /*  IF no name is found (blank line) or comment marker, skip line  */
    149      1.1  mrg 
    150      1.1  mrg       if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
    151      1.1  mrg         continue;
    152      1.1  mrg       *pz_end = NUL;
    153      1.1  mrg 
    154      1.1  mrg       process ();
    155      1.1  mrg     } /*  for (;;) */
    156      1.1  mrg 
    157      1.1  mrg #ifdef DO_STATS
    158      1.1  mrg   if (VLEVEL( VERB_PROGRESS )) {
    159      1.1  mrg     tSCC zFmt[] =
    160      1.1  mrg       "\
    161      1.1  mrg Processed %5d files containing %d bytes    \n\
    162      1.1  mrg Applying  %5d fixes to %d files\n\
    163      1.1  mrg Altering  %5d of them\n";
    164      1.1  mrg 
    165      1.1  mrg     fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
    166      1.1  mrg              fixed_ct, altered_ct);
    167      1.1  mrg   }
    168      1.1  mrg #endif /* DO_STATS */
    169      1.1  mrg 
    170      1.1  mrg # ifdef SEPARATE_FIX_PROC
    171      1.1  mrg   unlink( pz_temp_file );
    172      1.1  mrg # endif
    173      1.1  mrg   exit (EXIT_SUCCESS);
    174      1.1  mrg }
    175      1.1  mrg 
    176      1.1  mrg 
    177      1.1  mrg static void
    178      1.1  mrg do_version (void)
    179      1.1  mrg {
    180      1.1  mrg   static const char zFmt[] = "echo '%s'";
    181      1.1  mrg   char zBuf[ 1024 ];
    182      1.1  mrg 
    183      1.1  mrg   /* The 'version' option is really used to test that:
    184      1.1  mrg      1.  The program loads correctly (no missing libraries)
    185      1.1  mrg      2.  that we can compile all the regular expressions.
    186      1.1  mrg      3.  we can correctly run our server shell process
    187      1.1  mrg   */
    188      1.1  mrg   run_compiles ();
    189      1.1  mrg   sprintf (zBuf, zFmt, program_id);
    190      1.1  mrg #ifndef SEPARATE_FIX_PROC
    191      1.1  mrg   puts (zBuf + 5);
    192      1.1  mrg   exit (strcmp (run_shell (zBuf), program_id));
    193      1.1  mrg #else
    194  1.1.1.4  mrg   exit (system_with_shell (zBuf));
    195      1.1  mrg #endif
    196      1.1  mrg }
    197      1.1  mrg 
    198      1.1  mrg /* * * * * * * * * * * * */
    199      1.1  mrg 
    200      1.1  mrg void
    201      1.1  mrg initialize ( int argc, char** argv )
    202      1.1  mrg {
    203      1.1  mrg   xmalloc_set_program_name (argv[0]);
    204      1.1  mrg 
    205      1.1  mrg   switch (argc)
    206      1.1  mrg     {
    207      1.1  mrg     case 1:
    208      1.1  mrg       break;
    209      1.1  mrg 
    210      1.1  mrg     case 2:
    211      1.1  mrg       if (strcmp (argv[1], "-v") == 0)
    212      1.1  mrg         do_version ();
    213      1.1  mrg       if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
    214      1.1  mrg         {
    215      1.1  mrg           fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
    216      1.1  mrg                    errno, xstrerror (errno), argv[1] );
    217      1.1  mrg           exit (EXIT_FAILURE);
    218      1.1  mrg         }
    219      1.1  mrg       break;
    220      1.1  mrg 
    221      1.1  mrg     default:
    222      1.1  mrg       fputs ("fixincl ERROR:  too many command line arguments\n", stderr);
    223      1.1  mrg       exit (EXIT_FAILURE);
    224      1.1  mrg     }
    225      1.1  mrg 
    226      1.1  mrg #ifdef SIGCHLD
    227      1.1  mrg   /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
    228      1.1  mrg      receive the signal.  A different setting is inheritable */
    229      1.1  mrg   signal (SIGCHLD, SIG_DFL);
    230      1.1  mrg #endif
    231      1.1  mrg 
    232      1.1  mrg   initialize_opts ();
    233      1.1  mrg 
    234      1.1  mrg   if (ISDIGIT ( *pz_verbose ))
    235      1.1  mrg     verbose_level = (te_verbose)atoi( pz_verbose );
    236      1.1  mrg   else
    237      1.1  mrg     switch (*pz_verbose) {
    238      1.1  mrg     case 's':
    239      1.1  mrg     case 'S':
    240      1.1  mrg       verbose_level = VERB_SILENT;     break;
    241      1.1  mrg 
    242      1.1  mrg     case 'f':
    243      1.1  mrg     case 'F':
    244      1.1  mrg       verbose_level = VERB_FIXES;      break;
    245      1.1  mrg 
    246      1.1  mrg     case 'a':
    247      1.1  mrg     case 'A':
    248      1.1  mrg       verbose_level = VERB_APPLIES;    break;
    249      1.1  mrg 
    250      1.1  mrg     default:
    251      1.1  mrg     case 'p':
    252      1.1  mrg     case 'P':
    253      1.1  mrg       verbose_level = VERB_PROGRESS;   break;
    254      1.1  mrg 
    255      1.1  mrg     case 't':
    256      1.1  mrg     case 'T':
    257      1.1  mrg       verbose_level = VERB_TESTS;      break;
    258      1.1  mrg 
    259      1.1  mrg     case 'e':
    260      1.1  mrg     case 'E':
    261      1.1  mrg       verbose_level = VERB_EVERYTHING; break;
    262      1.1  mrg     }
    263      1.1  mrg   if (verbose_level >= VERB_EVERYTHING) {
    264      1.1  mrg     verbose_level = VERB_EVERYTHING;
    265      1.1  mrg     fputs ("fixinc verbosity:  EVERYTHING\n", stderr);
    266      1.1  mrg   }
    267      1.1  mrg   while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
    268      1.1  mrg     pz_find_base += 2;
    269      1.1  mrg   if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
    270      1.1  mrg     find_base_len = strlen( pz_find_base );
    271      1.1  mrg 
    272      1.1  mrg   /*  Compile all the regular expressions now.
    273      1.1  mrg       That way, it is done only once for the whole run.
    274      1.1  mrg       */
    275      1.1  mrg   run_compiles ();
    276      1.1  mrg 
    277      1.1  mrg # ifdef SEPARATE_FIX_PROC
    278      1.1  mrg   /* NULL as the first argument to `tempnam' causes it to DTRT
    279      1.1  mrg      wrt the temporary directory where the file will be created.  */
    280      1.1  mrg   pz_temp_file = tempnam( NULL, "fxinc" );
    281  1.1.1.4  mrg 
    282  1.1.1.4  mrg #if defined(__MINGW32__)
    283  1.1.1.4  mrg   fix_path_separators (pz_temp_file);
    284  1.1.1.4  mrg #endif
    285  1.1.1.4  mrg 
    286      1.1  mrg # endif
    287      1.1  mrg 
    288      1.1  mrg   signal (SIGQUIT, SIG_IGN);
    289      1.1  mrg   signal (SIGIOT,  SIG_IGN);
    290      1.1  mrg   signal (SIGPIPE, SIG_IGN);
    291      1.1  mrg   signal (SIGALRM, SIG_IGN);
    292      1.1  mrg   signal (SIGTERM, SIG_IGN);
    293      1.1  mrg }
    294      1.1  mrg 
    295      1.1  mrg /* * * * * * * * * * * * *
    296      1.1  mrg 
    297      1.1  mrg    load_file loads all the contents of a file into malloc-ed memory.
    298      1.1  mrg    Its argument is the name of the file to read in; the returned
    299      1.1  mrg    result is the NUL terminated contents of the file.  The file
    300      1.1  mrg    is presumed to be an ASCII text file containing no NULs.  */
    301      1.1  mrg char *
    302      1.1  mrg load_file ( const char* fname )
    303      1.1  mrg {
    304      1.1  mrg   struct stat stbf;
    305      1.1  mrg   char* res;
    306      1.1  mrg 
    307      1.1  mrg   if (stat (fname, &stbf) != 0)
    308      1.1  mrg     {
    309      1.1  mrg       if (NOT_SILENT)
    310      1.1  mrg         fprintf (stderr, "error %d (%s) stat-ing %s\n",
    311      1.1  mrg                  errno, xstrerror (errno), fname );
    312      1.1  mrg       return (char *) NULL;
    313      1.1  mrg     }
    314      1.1  mrg   if (stbf.st_size == 0)
    315      1.1  mrg     return (char*)NULL;
    316      1.1  mrg 
    317      1.1  mrg   /*  Make the data map size one larger than the file size for documentation
    318      1.1  mrg       purposes.  Truth is that there will be a following NUL character if
    319      1.1  mrg       the file size is not a multiple of the page size.  If it is a multiple,
    320      1.1  mrg       then this adjustment sometimes fails anyway.  */
    321      1.1  mrg   data_map_size = stbf.st_size+1;
    322      1.1  mrg   data_map_fd   = open (fname, O_RDONLY);
    323      1.1  mrg   ttl_data_size += data_map_size-1;
    324      1.1  mrg 
    325      1.1  mrg   if (data_map_fd < 0)
    326      1.1  mrg     {
    327      1.1  mrg       if (NOT_SILENT)
    328      1.1  mrg         fprintf (stderr, "error %d (%s) opening %s for read\n",
    329      1.1  mrg                  errno, xstrerror (errno), fname);
    330      1.1  mrg       return (char*)NULL;
    331      1.1  mrg     }
    332      1.1  mrg 
    333      1.1  mrg #ifdef HAVE_MMAP_FILE
    334      1.1  mrg   curr_data_mapped = BOOL_TRUE;
    335      1.1  mrg 
    336      1.1  mrg   /*  IF the file size is a multiple of the page size,
    337      1.1  mrg       THEN sometimes you will seg fault trying to access a trailing byte */
    338      1.1  mrg   if ((stbf.st_size & (getpagesize()-1)) == 0)
    339      1.1  mrg     res = (char*)BAD_ADDR;
    340      1.1  mrg   else
    341      1.1  mrg     res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
    342      1.1  mrg                        MAP_PRIVATE, data_map_fd, 0);
    343      1.1  mrg   if (res == (char*)BAD_ADDR)
    344      1.1  mrg #endif
    345      1.1  mrg     {
    346      1.1  mrg       FILE* fp = fdopen (data_map_fd, "r");
    347      1.1  mrg       curr_data_mapped = BOOL_FALSE;
    348      1.1  mrg       res = load_file_data (fp);
    349      1.1  mrg       fclose (fp);
    350      1.1  mrg     }
    351      1.1  mrg 
    352      1.1  mrg   return res;
    353      1.1  mrg }
    354      1.1  mrg 
    355      1.1  mrg static int
    356      1.1  mrg machine_matches( tFixDesc* p_fixd )
    357      1.1  mrg {
    358      1.1  mrg   char const ** papz_machs = p_fixd->papz_machs;
    359      1.1  mrg   int have_match = BOOL_FALSE;
    360      1.1  mrg 
    361      1.1  mrg   for (;;)
    362      1.1  mrg     {
    363      1.1  mrg       char const * pz_mpat = *(papz_machs++);
    364      1.1  mrg       if (pz_mpat == NULL)
    365      1.1  mrg         break;
    366      1.1  mrg       if (fnmatch(pz_mpat, pz_machine, 0) == 0)
    367      1.1  mrg         {
    368      1.1  mrg           have_match = BOOL_TRUE;
    369      1.1  mrg           break;
    370      1.1  mrg         }
    371      1.1  mrg     }
    372      1.1  mrg 
    373      1.1  mrg   /* Check for sense inversion then set the "skip test" flag, if needed */
    374      1.1  mrg   if (p_fixd->fd_flags & FD_MACH_IFNOT)
    375      1.1  mrg     have_match = ! have_match;
    376      1.1  mrg 
    377      1.1  mrg   if (! have_match)
    378      1.1  mrg     p_fixd->fd_flags |= FD_SKIP_TEST;
    379      1.1  mrg 
    380      1.1  mrg   return have_match;
    381      1.1  mrg }
    382      1.1  mrg 
    383      1.1  mrg /* * * * * * * * * * * * *
    384      1.1  mrg  *
    385      1.1  mrg  *  run_compiles   run all the regexp compiles for all the fixes once.
    386      1.1  mrg  */
    387      1.1  mrg void
    388      1.1  mrg run_compiles (void)
    389      1.1  mrg {
    390      1.1  mrg   tFixDesc *p_fixd = fixDescList;
    391      1.1  mrg   int fix_ct = FIX_COUNT;
    392      1.1  mrg   regex_t *p_re = XCNEWVEC (regex_t, REGEX_COUNT);
    393      1.1  mrg 
    394      1.1  mrg   /*  Make sure compile_re does not stumble across invalid data */
    395      1.1  mrg 
    396      1.1  mrg   memset (&incl_quote_re, '\0', sizeof (regex_t));
    397      1.1  mrg 
    398      1.1  mrg   compile_re (incl_quote_pat, &incl_quote_re, 1,
    399      1.1  mrg               "quoted include", "run_compiles");
    400      1.1  mrg 
    401      1.1  mrg   /*  Allow machine name tests to be ignored (testing, mainly) */
    402      1.1  mrg 
    403      1.1  mrg   if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
    404      1.1  mrg     pz_machine = (char*)NULL;
    405      1.1  mrg 
    406      1.1  mrg   /* FOR every fixup, ...  */
    407      1.1  mrg   do
    408      1.1  mrg     {
    409  1.1.1.2  mrg       tTestDesc *p_test;
    410  1.1.1.2  mrg       int test_ct;
    411  1.1.1.2  mrg 
    412  1.1.1.2  mrg       if (fixinc_mode && (p_fixd->fd_flags & FD_REPLACEMENT))
    413  1.1.1.2  mrg         {
    414  1.1.1.2  mrg           p_fixd->fd_flags |= FD_SKIP_TEST;
    415  1.1.1.2  mrg           continue;
    416  1.1.1.2  mrg         }
    417  1.1.1.2  mrg 
    418  1.1.1.2  mrg       p_test = p_fixd->p_test_desc;
    419  1.1.1.2  mrg       test_ct = p_fixd->test_ct;
    420      1.1  mrg 
    421      1.1  mrg       /*  IF the machine type pointer is not NULL (we are not in test mode)
    422      1.1  mrg              AND this test is for or not done on particular machines
    423      1.1  mrg           THEN ...   */
    424      1.1  mrg 
    425      1.1  mrg       if (  (pz_machine != NULL)
    426      1.1  mrg          && (p_fixd->papz_machs != (const char**) NULL)
    427      1.1  mrg          && ! machine_matches (p_fixd) )
    428      1.1  mrg         continue;
    429      1.1  mrg 
    430      1.1  mrg       /* FOR every test for the fixup, ...  */
    431      1.1  mrg 
    432      1.1  mrg       while (--test_ct >= 0)
    433      1.1  mrg         {
    434      1.1  mrg           switch (p_test->type)
    435      1.1  mrg             {
    436      1.1  mrg             case TT_EGREP:
    437      1.1  mrg             case TT_NEGREP:
    438      1.1  mrg               p_test->p_test_regex = p_re++;
    439      1.1  mrg               compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
    440      1.1  mrg                           "select test", p_fixd->fix_name);
    441      1.1  mrg             default: break;
    442      1.1  mrg             }
    443      1.1  mrg           p_test++;
    444      1.1  mrg         }
    445      1.1  mrg     }
    446      1.1  mrg   while (p_fixd++, --fix_ct > 0);
    447      1.1  mrg }
    448      1.1  mrg 
    449      1.1  mrg 
    450      1.1  mrg /* * * * * * * * * * * * *
    451      1.1  mrg 
    452      1.1  mrg    create_file  Create the output modified file.
    453      1.1  mrg    Input:    the name of the file to create
    454      1.1  mrg    Returns:  a file pointer to the new, open file  */
    455      1.1  mrg 
    456      1.1  mrg #if defined(S_IRUSR) && defined(S_IWUSR) && \
    457      1.1  mrg     defined(S_IRGRP) && defined(S_IROTH)
    458      1.1  mrg 
    459      1.1  mrg #   define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
    460      1.1  mrg #else
    461      1.1  mrg #   define S_IRALL 0644
    462      1.1  mrg #endif
    463      1.1  mrg 
    464      1.1  mrg #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
    465      1.1  mrg     defined(S_IROTH) && defined(S_IXOTH)
    466      1.1  mrg 
    467      1.1  mrg #   define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
    468      1.1  mrg #else
    469      1.1  mrg #   define S_DIRALL 0755
    470      1.1  mrg #endif
    471      1.1  mrg 
    472      1.1  mrg 
    473      1.1  mrg static FILE *
    474      1.1  mrg create_file (void)
    475      1.1  mrg {
    476      1.1  mrg   int fd;
    477      1.1  mrg   FILE *pf;
    478      1.1  mrg   char fname[MAXPATHLEN];
    479      1.1  mrg 
    480      1.1  mrg   sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
    481      1.1  mrg 
    482      1.1  mrg   fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
    483      1.1  mrg 
    484      1.1  mrg   /*  We may need to create the directories needed... */
    485      1.1  mrg   if ((fd < 0) && (errno == ENOENT))
    486      1.1  mrg     {
    487      1.1  mrg       char *pz_dir = strchr (fname + 1, '/');
    488      1.1  mrg       struct stat stbf;
    489      1.1  mrg 
    490      1.1  mrg       while (pz_dir != (char *) NULL)
    491      1.1  mrg         {
    492      1.1  mrg           *pz_dir = NUL;
    493      1.1  mrg           if (stat (fname, &stbf) < 0)
    494      1.1  mrg             {
    495      1.1  mrg #ifdef _WIN32
    496      1.1  mrg               mkdir (fname);
    497      1.1  mrg #else
    498      1.1  mrg               mkdir (fname, S_IFDIR | S_DIRALL);
    499      1.1  mrg #endif
    500      1.1  mrg             }
    501      1.1  mrg 
    502      1.1  mrg           *pz_dir = '/';
    503      1.1  mrg           pz_dir = strchr (pz_dir + 1, '/');
    504      1.1  mrg         }
    505      1.1  mrg 
    506      1.1  mrg       /*  Now, lets try the open again... */
    507      1.1  mrg       fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
    508      1.1  mrg     }
    509      1.1  mrg   if (fd < 0)
    510      1.1  mrg     {
    511      1.1  mrg       fprintf (stderr, "Error %d (%s) creating %s\n",
    512      1.1  mrg                errno, xstrerror (errno), fname);
    513      1.1  mrg       exit (EXIT_FAILURE);
    514      1.1  mrg     }
    515      1.1  mrg   if (NOT_SILENT)
    516      1.1  mrg     fprintf (stderr, "Fixed:  %s\n", pz_curr_file);
    517      1.1  mrg   pf = fdopen (fd, "w");
    518      1.1  mrg 
    519      1.1  mrg   /*
    520      1.1  mrg    *  IF pz_machine is NULL, then we are in some sort of test mode.
    521      1.1  mrg    *  Do not insert the current directory name.  Use a constant string.
    522      1.1  mrg    */
    523      1.1  mrg   fprintf (pf, z_std_preamble,
    524      1.1  mrg            (pz_machine == NULL)
    525      1.1  mrg            ? "fixinc/tests/inc"
    526      1.1  mrg            : pz_input_dir,
    527      1.1  mrg            pz_curr_file);
    528      1.1  mrg 
    529      1.1  mrg   return pf;
    530      1.1  mrg }
    531      1.1  mrg 
    532      1.1  mrg 
    533      1.1  mrg /* * * * * * * * * * * * *
    534      1.1  mrg 
    535      1.1  mrg   test_test   make sure a shell-style test expression passes.
    536      1.1  mrg   Input:  a pointer to the descriptor of the test to run and
    537      1.1  mrg           the name of the file that we might want to fix
    538      1.1  mrg   Result: APPLY_FIX or SKIP_FIX, depending on the result of the
    539      1.1  mrg           shell script we run.  */
    540      1.1  mrg #ifndef SEPARATE_FIX_PROC
    541      1.1  mrg static int
    542      1.1  mrg test_test (tTestDesc* p_test, char* pz_test_file)
    543      1.1  mrg {
    544      1.1  mrg   tSCC cmd_fmt[] =
    545      1.1  mrg "file=%s\n\
    546      1.1  mrg if ( test %s ) > /dev/null 2>&1\n\
    547      1.1  mrg then echo TRUE\n\
    548      1.1  mrg else echo FALSE\n\
    549      1.1  mrg fi";
    550      1.1  mrg 
    551      1.1  mrg   char *pz_res;
    552      1.1  mrg   int res;
    553      1.1  mrg 
    554      1.1  mrg   static char cmd_buf[4096];
    555      1.1  mrg 
    556      1.1  mrg   sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
    557      1.1  mrg   pz_res = run_shell (cmd_buf);
    558      1.1  mrg 
    559      1.1  mrg   switch (*pz_res) {
    560      1.1  mrg   case 'T':
    561      1.1  mrg     res = APPLY_FIX;
    562      1.1  mrg     break;
    563      1.1  mrg 
    564      1.1  mrg   case 'F':
    565      1.1  mrg     res = SKIP_FIX;
    566      1.1  mrg     break;
    567      1.1  mrg 
    568      1.1  mrg   default:
    569      1.1  mrg     fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
    570      1.1  mrg              pz_res, cmd_buf );
    571      1.1  mrg     res = SKIP_FIX;
    572      1.1  mrg   }
    573      1.1  mrg 
    574      1.1  mrg   free ((void *) pz_res);
    575      1.1  mrg   return res;
    576      1.1  mrg }
    577  1.1.1.4  mrg #elif defined(__MINGW32__) || defined(__DJGPP__)
    578  1.1.1.4  mrg static int
    579  1.1.1.4  mrg test_test (tTestDesc* p_test, char* pz_test_file)
    580  1.1.1.4  mrg {
    581  1.1.1.4  mrg   tSCC cmd_fmt[] =
    582  1.1.1.4  mrg #if defined(__DJGPP__)
    583  1.1.1.4  mrg     "file=%s; test %s >/dev/null 2>/dev/null";
    584  1.1.1.4  mrg #else
    585  1.1.1.4  mrg     "file=%s; test %s > /dev/null 2>&1";
    586  1.1.1.4  mrg #endif
    587  1.1.1.4  mrg   int res;
    588  1.1.1.4  mrg 
    589  1.1.1.4  mrg   char *cmd_buf = XNEWVEC (char, strlen(cmd_fmt) + strlen(pz_test_file) + strlen(p_test->pz_test_text));
    590  1.1.1.4  mrg 
    591  1.1.1.4  mrg   sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
    592  1.1.1.4  mrg   res = system_with_shell (cmd_buf);
    593  1.1.1.4  mrg 
    594  1.1.1.4  mrg   free (cmd_buf);
    595  1.1.1.4  mrg   return res ? SKIP_FIX : APPLY_FIX;
    596  1.1.1.4  mrg }
    597      1.1  mrg #else
    598      1.1  mrg /*
    599      1.1  mrg  *  IF we are in MS-DOS land, then whatever shell-type test is required
    600      1.1  mrg  *  will, by definition, fail
    601      1.1  mrg  */
    602      1.1  mrg #define test_test(t,tf)  SKIP_FIX
    603      1.1  mrg #endif
    604      1.1  mrg 
    605      1.1  mrg /* * * * * * * * * * * * *
    606      1.1  mrg 
    607      1.1  mrg   egrep_test   make sure an egrep expression is found in the file text.
    608      1.1  mrg   Input:  a pointer to the descriptor of the test to run and
    609      1.1  mrg           the pointer to the contents of the file under suspicion
    610      1.1  mrg   Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
    611      1.1  mrg 
    612      1.1  mrg   The caller may choose to reverse meaning if the sense of the test
    613      1.1  mrg   is inverted.  */
    614      1.1  mrg 
    615      1.1  mrg static int
    616      1.1  mrg egrep_test (char* pz_data, tTestDesc* p_test)
    617      1.1  mrg {
    618      1.1  mrg #ifdef DEBUG
    619      1.1  mrg   if (p_test->p_test_regex == 0)
    620      1.1  mrg     fprintf (stderr, "fixincl ERROR RE not compiled:  `%s'\n",
    621      1.1  mrg              p_test->pz_test_text);
    622      1.1  mrg #endif
    623      1.1  mrg   if (xregexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
    624      1.1  mrg     return APPLY_FIX;
    625      1.1  mrg   return SKIP_FIX;
    626      1.1  mrg }
    627      1.1  mrg 
    628  1.1.1.3  mrg /* * * * * * * * * * * * *
    629  1.1.1.3  mrg 
    630  1.1.1.3  mrg   cksum_test   check the sum of the candidate file
    631  1.1.1.3  mrg   Input:  the original file contents and the file name
    632  1.1.1.3  mrg   Result: APPLY_FIX if the check sum matches, SKIP_FIX otherwise
    633  1.1.1.3  mrg 
    634  1.1.1.3  mrg   The caller may choose to reverse meaning if the sense of the test
    635  1.1.1.3  mrg   is inverted.  */
    636  1.1.1.3  mrg 
    637  1.1.1.3  mrg static int
    638  1.1.1.3  mrg cksum_test (char * pz_data, tTestDesc * p_test, char * fname)
    639  1.1.1.3  mrg {
    640  1.1.1.3  mrg   unsigned int cksum;
    641  1.1.1.3  mrg 
    642  1.1.1.3  mrg   /*
    643  1.1.1.3  mrg    * Testing is off in normal operation mode.
    644  1.1.1.3  mrg    * So, in testing mode, APPLY_FIX is always returned.
    645  1.1.1.3  mrg    */
    646  1.1.1.3  mrg   if (fixinc_mode != TESTING_OFF)
    647  1.1.1.3  mrg     return APPLY_FIX;
    648  1.1.1.3  mrg 
    649  1.1.1.3  mrg   {
    650  1.1.1.3  mrg     char * fnm = strrchr(fname, '/');
    651  1.1.1.3  mrg     if (fnm != NULL)
    652  1.1.1.3  mrg       fname = fnm + 1;
    653  1.1.1.3  mrg 
    654  1.1.1.3  mrg     errno = 0;
    655  1.1.1.3  mrg     cksum = (unsigned int)strtoul(p_test->pz_test_text, &fnm, 10);
    656  1.1.1.3  mrg     if (errno != 0)
    657  1.1.1.3  mrg       return SKIP_FIX;
    658  1.1.1.3  mrg 
    659  1.1.1.3  mrg     if (! ISSPACE(*fnm++))
    660  1.1.1.3  mrg       return SKIP_FIX;
    661  1.1.1.3  mrg     while (ISSPACE(*fnm)) fnm++;
    662  1.1.1.3  mrg 
    663  1.1.1.3  mrg     if (! ISDIGIT(*fnm++))
    664  1.1.1.3  mrg       return SKIP_FIX;
    665  1.1.1.3  mrg     while (ISDIGIT(*fnm)) fnm++;
    666  1.1.1.3  mrg 
    667  1.1.1.3  mrg     if (! ISSPACE(*fnm++))
    668  1.1.1.3  mrg       return SKIP_FIX;
    669  1.1.1.3  mrg     while (ISSPACE(*fnm)) fnm++;
    670  1.1.1.3  mrg 
    671  1.1.1.3  mrg     if (strcmp(fnm, fname) != 0)
    672  1.1.1.3  mrg       return SKIP_FIX;
    673  1.1.1.3  mrg   }
    674  1.1.1.3  mrg 
    675  1.1.1.3  mrg   {
    676  1.1.1.3  mrg     unsigned int sum = 0;
    677  1.1.1.3  mrg     while (*pz_data != NUL) {
    678  1.1.1.3  mrg       sum = (sum >> 1) + ((sum & 1) << 15) + (unsigned)(*pz_data++);
    679  1.1.1.3  mrg       sum &= 0xFFFF;
    680  1.1.1.3  mrg     }
    681  1.1.1.3  mrg 
    682  1.1.1.3  mrg     return (sum == cksum) ? APPLY_FIX : SKIP_FIX;
    683  1.1.1.3  mrg   }
    684  1.1.1.3  mrg }
    685      1.1  mrg 
    686      1.1  mrg /* * * * * * * * * * * * *
    687      1.1  mrg 
    688      1.1  mrg   quoted_file_exists  Make sure that a file exists before we emit
    689      1.1  mrg   the file name.  If we emit the name, our invoking shell will try
    690      1.1  mrg   to copy a non-existing file into the destination directory.  */
    691      1.1  mrg 
    692      1.1  mrg static int
    693      1.1  mrg quoted_file_exists (const char* pz_src_path,
    694      1.1  mrg                     const char* pz_file_path,
    695      1.1  mrg                     const char* pz_file)
    696      1.1  mrg {
    697      1.1  mrg   char z[ MAXPATHLEN ];
    698      1.1  mrg   char* pz;
    699      1.1  mrg   sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
    700      1.1  mrg   pz = z + strlen ( z );
    701      1.1  mrg 
    702      1.1  mrg   for (;;) {
    703      1.1  mrg     char ch = *pz_file++;
    704      1.1  mrg     if (! ISGRAPH( ch ))
    705      1.1  mrg       return 0;
    706      1.1  mrg     if (ch == '"')
    707      1.1  mrg       break;
    708      1.1  mrg     *pz++ = ch;
    709      1.1  mrg   }
    710      1.1  mrg   *pz = '\0';
    711      1.1  mrg   {
    712      1.1  mrg     struct stat s;
    713      1.1  mrg     if (stat (z, &s) != 0)
    714      1.1  mrg       return 0;
    715      1.1  mrg     return S_ISREG( s.st_mode );
    716      1.1  mrg   }
    717      1.1  mrg }
    718      1.1  mrg 
    719      1.1  mrg 
    720      1.1  mrg /* * * * * * * * * * * * *
    721      1.1  mrg  *
    722      1.1  mrg    extract_quoted_files
    723      1.1  mrg 
    724      1.1  mrg    The syntax, `#include "file.h"' specifies that the compiler is to
    725      1.1  mrg    search the local directory of the current file before the include
    726      1.1  mrg    list.  Consequently, if we have modified a header and stored it in
    727      1.1  mrg    another directory, any files that are included by that modified
    728      1.1  mrg    file in that fashion must also be copied into this new directory.
    729      1.1  mrg    This routine finds those flavors of #include and for each one found
    730      1.1  mrg    emits a triple of:
    731      1.1  mrg 
    732      1.1  mrg     1.  source directory of the original file
    733      1.1  mrg     2.  the relative path file name of the #includ-ed file
    734      1.1  mrg     3.  the full destination path for this file
    735      1.1  mrg 
    736      1.1  mrg    Input:  the text of the file, the file name and a pointer to the
    737      1.1  mrg            match list where the match information was stored.
    738      1.1  mrg    Result: internally nothing.  The results are written to stdout
    739      1.1  mrg            for interpretation by the invoking shell  */
    740      1.1  mrg 
    741      1.1  mrg 
    742      1.1  mrg static void
    743      1.1  mrg extract_quoted_files (char* pz_data,
    744      1.1  mrg                       const char* pz_fixed_file,
    745      1.1  mrg                       regmatch_t* p_re_match)
    746      1.1  mrg {
    747      1.1  mrg   char *pz_dir_end = strrchr (pz_fixed_file, '/');
    748      1.1  mrg   char *pz_incl_quot = pz_data;
    749      1.1  mrg 
    750      1.1  mrg   if (VLEVEL( VERB_APPLIES ))
    751      1.1  mrg     fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
    752      1.1  mrg 
    753      1.1  mrg   /*  Set "pz_fixed_file" to point to the containing subdirectory of the source
    754      1.1  mrg       If there is none, then it is in our current directory, ".".   */
    755      1.1  mrg 
    756      1.1  mrg   if (pz_dir_end == (char *) NULL)
    757      1.1  mrg     pz_fixed_file = ".";
    758      1.1  mrg   else
    759      1.1  mrg     *pz_dir_end = '\0';
    760      1.1  mrg 
    761      1.1  mrg   for (;;)
    762      1.1  mrg     {
    763      1.1  mrg       pz_incl_quot += p_re_match->rm_so;
    764      1.1  mrg 
    765      1.1  mrg       /*  Skip forward to the included file name */
    766      1.1  mrg       while (*pz_incl_quot != '"')
    767      1.1  mrg         pz_incl_quot++;
    768      1.1  mrg 
    769      1.1  mrg       if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
    770      1.1  mrg         {
    771      1.1  mrg           /* Print the source directory and the subdirectory
    772      1.1  mrg              of the file in question.  */
    773      1.1  mrg           printf ("%s  %s/", pz_src_dir, pz_fixed_file);
    774      1.1  mrg           pz_dir_end = pz_incl_quot;
    775      1.1  mrg 
    776      1.1  mrg           /* Append to the directory the relative path of the desired file */
    777      1.1  mrg           while (*pz_incl_quot != '"')
    778      1.1  mrg             putc (*pz_incl_quot++, stdout);
    779      1.1  mrg 
    780      1.1  mrg           /* Now print the destination directory appended with the
    781      1.1  mrg              relative path of the desired file */
    782      1.1  mrg           printf ("  %s/%s/", pz_dest_dir, pz_fixed_file);
    783      1.1  mrg           while (*pz_dir_end != '"')
    784      1.1  mrg             putc (*pz_dir_end++, stdout);
    785      1.1  mrg 
    786      1.1  mrg           /* End of entry */
    787      1.1  mrg           putc ('\n', stdout);
    788      1.1  mrg         }
    789      1.1  mrg 
    790      1.1  mrg       /* Find the next entry */
    791      1.1  mrg       if (xregexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
    792      1.1  mrg         break;
    793      1.1  mrg     }
    794      1.1  mrg }
    795      1.1  mrg 
    796      1.1  mrg 
    797      1.1  mrg /* * * * * * * * * * * * *
    798      1.1  mrg 
    799      1.1  mrg     Somebody wrote a *_fix subroutine that we must call.
    800      1.1  mrg     */
    801      1.1  mrg #ifndef SEPARATE_FIX_PROC
    802      1.1  mrg static int
    803      1.1  mrg internal_fix (int read_fd, tFixDesc* p_fixd)
    804      1.1  mrg {
    805      1.1  mrg   int fd[2];
    806      1.1  mrg 
    807      1.1  mrg   if (pipe( fd ) != 0)
    808      1.1  mrg     {
    809      1.1  mrg       fprintf (stderr, "Error %d on pipe(2) call\n", errno );
    810      1.1  mrg       exit (EXIT_FAILURE);
    811      1.1  mrg     }
    812      1.1  mrg 
    813      1.1  mrg   for (;;)
    814      1.1  mrg     {
    815      1.1  mrg       pid_t childid = fork();
    816      1.1  mrg 
    817      1.1  mrg       switch (childid)
    818      1.1  mrg         {
    819      1.1  mrg         case -1:
    820      1.1  mrg           break;
    821      1.1  mrg 
    822      1.1  mrg         case 0:
    823      1.1  mrg           close (fd[0]);
    824      1.1  mrg           goto do_child_task;
    825      1.1  mrg 
    826      1.1  mrg         default:
    827      1.1  mrg           /*
    828      1.1  mrg            *  Parent process
    829      1.1  mrg            */
    830      1.1  mrg           close (read_fd);
    831      1.1  mrg           close (fd[1]);
    832      1.1  mrg           return fd[0];
    833      1.1  mrg         }
    834      1.1  mrg 
    835      1.1  mrg       /*
    836      1.1  mrg        *  Parent in error
    837      1.1  mrg        */
    838      1.1  mrg       fprintf (stderr, z_fork_err, errno, xstrerror (errno),
    839      1.1  mrg                p_fixd->fix_name);
    840      1.1  mrg       {
    841      1.1  mrg         static int failCt = 0;
    842      1.1  mrg         if ((errno != EAGAIN) || (++failCt > 10))
    843      1.1  mrg           exit (EXIT_FAILURE);
    844      1.1  mrg         sleep (1);
    845      1.1  mrg       }
    846      1.1  mrg     } do_child_task:;
    847      1.1  mrg 
    848      1.1  mrg   /*
    849      1.1  mrg    *  Close our current stdin and stdout
    850      1.1  mrg    */
    851      1.1  mrg   close (STDIN_FILENO);
    852      1.1  mrg   close (STDOUT_FILENO);
    853      1.1  mrg   UNLOAD_DATA();
    854      1.1  mrg 
    855      1.1  mrg   /*
    856      1.1  mrg    *  Make the fd passed in the stdin, and the write end of
    857      1.1  mrg    *  the new pipe become the stdout.
    858      1.1  mrg    */
    859      1.1  mrg   dup2 (fd[1], STDOUT_FILENO);
    860      1.1  mrg   dup2 (read_fd, STDIN_FILENO);
    861      1.1  mrg 
    862      1.1  mrg   apply_fix (p_fixd, pz_curr_file);
    863      1.1  mrg   exit (0);
    864      1.1  mrg }
    865      1.1  mrg #endif /* !SEPARATE_FIX_PROC */
    866      1.1  mrg 
    867      1.1  mrg 
    868      1.1  mrg #ifdef SEPARATE_FIX_PROC
    869      1.1  mrg static void
    870      1.1  mrg fix_with_system (tFixDesc* p_fixd,
    871      1.1  mrg                  tCC* pz_fix_file,
    872      1.1  mrg                  tCC* pz_file_source,
    873      1.1  mrg                  tCC* pz_temp_file)
    874      1.1  mrg {
    875      1.1  mrg   char*  pz_cmd;
    876      1.1  mrg   char*  pz_scan;
    877      1.1  mrg   size_t argsize;
    878      1.1  mrg 
    879      1.1  mrg   if (p_fixd->fd_flags & FD_SUBROUTINE)
    880      1.1  mrg     {
    881      1.1  mrg       static const char z_applyfix_prog[] =
    882  1.1.1.3  mrg         "/../fixincludes/applyfix" EXE_EXT;
    883      1.1  mrg 
    884      1.1  mrg       struct stat buf;
    885      1.1  mrg       argsize = 32
    886      1.1  mrg               + strlen (pz_orig_dir)
    887      1.1  mrg               + sizeof (z_applyfix_prog)
    888      1.1  mrg               + strlen (pz_fix_file)
    889      1.1  mrg               + strlen (pz_file_source)
    890      1.1  mrg               + strlen (pz_temp_file);
    891      1.1  mrg 
    892      1.1  mrg       /* Allocate something sure to be big enough for our purposes */
    893      1.1  mrg       pz_cmd = XNEWVEC (char, argsize);
    894      1.1  mrg       strcpy (pz_cmd, pz_orig_dir);
    895      1.1  mrg       pz_scan = pz_cmd + strlen (pz_orig_dir);
    896      1.1  mrg 
    897      1.1  mrg       strcpy (pz_scan, z_applyfix_prog);
    898      1.1  mrg 
    899      1.1  mrg       /* IF we can't find the "applyfix" executable file at the first guess,
    900  1.1.1.3  mrg          try one level higher up  */
    901      1.1  mrg       if (stat (pz_cmd, &buf) == -1)
    902  1.1.1.3  mrg         {
    903  1.1.1.3  mrg           strcpy (pz_scan, "/..");
    904  1.1.1.3  mrg           strcpy (pz_scan+3, z_applyfix_prog);
    905  1.1.1.3  mrg         }
    906      1.1  mrg 
    907      1.1  mrg       pz_scan += strlen (pz_scan);
    908      1.1  mrg 
    909      1.1  mrg       /*
    910      1.1  mrg        *  Now add the fix number and file names that may be needed
    911      1.1  mrg        */
    912  1.1.1.2  mrg       sprintf (pz_scan, " %ld '%s' '%s' '%s'", (long) (p_fixd - fixDescList),
    913  1.1.1.3  mrg                pz_fix_file, pz_file_source, pz_temp_file);
    914      1.1  mrg     }
    915      1.1  mrg   else /* NOT an "internal" fix: */
    916      1.1  mrg     {
    917      1.1  mrg       size_t parg_size;
    918  1.1.1.4  mrg #if defined(__MSDOS__) && !defined(__DJGPP__)
    919      1.1  mrg       /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
    920      1.1  mrg          dst is a temporary file anyway, so we know there's no other
    921      1.1  mrg          file by that name; and DOS's system(3) doesn't mind to
    922      1.1  mrg          clobber existing file in redirection.  Besides, with DOS 8+3
    923      1.1  mrg          limited file namespace, we can easily lose if dst already has
    924      1.1  mrg          an extension that is 3 or more characters long.
    925      1.1  mrg 
    926      1.1  mrg          I do not think the 8+3 issue is relevant because all the files
    927      1.1  mrg          we operate on are named "*.h", making 8+2 adequate.  Anyway,
    928      1.1  mrg          the following bizarre use of 'cat' only works on DOS boxes.
    929      1.1  mrg          It causes the file to be dropped into a temporary file for
    930      1.1  mrg          'cat' to read (pipes do not work on DOS).  */
    931      1.1  mrg       tSCC   z_cmd_fmt[] = " '%s' | cat > '%s'";
    932      1.1  mrg #else
    933      1.1  mrg       /* Don't use positional formatting arguments because some lame-o
    934      1.1  mrg          implementations cannot cope  :-(.  */
    935      1.1  mrg       tSCC   z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
    936      1.1  mrg #endif
    937  1.1.1.4  mrg       tSCC   z_subshell_start[] = "( ";
    938  1.1.1.4  mrg       tSCC   z_subshell_end[] = " ) < ";
    939      1.1  mrg       tCC**  ppArgs = p_fixd->patch_args;
    940      1.1  mrg 
    941      1.1  mrg       argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
    942      1.1  mrg               + strlen( pz_file_source );
    943      1.1  mrg       parg_size = argsize;
    944      1.1  mrg 
    945  1.1.1.4  mrg       if (p_fixd->fd_flags & FD_SHELL_SCRIPT)
    946  1.1.1.4  mrg         {
    947  1.1.1.4  mrg           argsize += strlen( z_subshell_start ) + strlen ( z_subshell_end );
    948  1.1.1.4  mrg         }
    949      1.1  mrg 
    950      1.1  mrg       /*
    951      1.1  mrg        *  Compute the size of the command line.  Add lotsa extra space
    952      1.1  mrg        *  because some of the args to sed use lotsa single quotes.
    953      1.1  mrg        *  (This requires three extra bytes per quote.  Here we allow
    954      1.1  mrg        *  for up to 8 single quotes for each argument, including the
    955      1.1  mrg        *  command name "sed" itself.  Nobody will *ever* need more. :)
    956      1.1  mrg        */
    957      1.1  mrg       for (;;)
    958      1.1  mrg         {
    959      1.1  mrg           tCC* p_arg = *(ppArgs++);
    960      1.1  mrg           if (p_arg == NULL)
    961      1.1  mrg             break;
    962      1.1  mrg           argsize += 24 + strlen( p_arg );
    963      1.1  mrg         }
    964      1.1  mrg 
    965      1.1  mrg       /* Estimated buffer size we will need.  */
    966      1.1  mrg       pz_scan = pz_cmd = XNEWVEC (char, argsize);
    967      1.1  mrg       /* How much of it do we allot to the program name and its
    968      1.1  mrg          arguments.  */
    969      1.1  mrg       parg_size = argsize - parg_size;
    970      1.1  mrg 
    971      1.1  mrg       ppArgs = p_fixd->patch_args;
    972      1.1  mrg 
    973      1.1  mrg       /*
    974  1.1.1.4  mrg        * If it's shell script, enclose it in parentheses and skip "sh -c".
    975  1.1.1.4  mrg        */
    976  1.1.1.4  mrg       if (p_fixd->fd_flags & FD_SHELL_SCRIPT)
    977  1.1.1.4  mrg         {
    978  1.1.1.4  mrg           strcpy (pz_scan, z_subshell_start);
    979  1.1.1.4  mrg           pz_scan += strlen (z_subshell_start);
    980  1.1.1.4  mrg           ppArgs += 2;
    981  1.1.1.4  mrg         }
    982  1.1.1.4  mrg 
    983  1.1.1.4  mrg       /*
    984      1.1  mrg        *  Copy the program name, unquoted
    985      1.1  mrg        */
    986      1.1  mrg       {
    987      1.1  mrg         tCC*   pArg = *(ppArgs++);
    988      1.1  mrg         for (;;)
    989      1.1  mrg           {
    990      1.1  mrg             char ch = *(pArg++);
    991      1.1  mrg             if (ch == NUL)
    992      1.1  mrg               break;
    993      1.1  mrg             *(pz_scan++) = ch;
    994      1.1  mrg           }
    995      1.1  mrg       }
    996      1.1  mrg 
    997      1.1  mrg       /*
    998      1.1  mrg        *  Copy the program arguments, quoted
    999      1.1  mrg        */
   1000      1.1  mrg       for (;;)
   1001      1.1  mrg         {
   1002      1.1  mrg           tCC*   pArg = *(ppArgs++);
   1003  1.1.1.3  mrg           char*  pz_scan_save;
   1004      1.1  mrg           if (pArg == NULL)
   1005      1.1  mrg             break;
   1006      1.1  mrg           *(pz_scan++) = ' ';
   1007      1.1  mrg           pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
   1008  1.1.1.3  mrg                                         parg_size - (pz_scan - pz_cmd) );
   1009  1.1.1.3  mrg           /*
   1010  1.1.1.3  mrg            *  Make sure we don't overflow the buffer due to sloppy
   1011  1.1.1.3  mrg            *  size estimation.
   1012  1.1.1.3  mrg            */
   1013  1.1.1.3  mrg           while (pz_scan == (char*)NULL)
   1014  1.1.1.3  mrg             {
   1015  1.1.1.3  mrg               size_t already_filled = pz_scan_save - pz_cmd;
   1016  1.1.1.3  mrg               pz_cmd = xrealloc (pz_cmd, argsize += 100);
   1017  1.1.1.3  mrg               pz_scan_save = pz_scan = pz_cmd + already_filled;
   1018  1.1.1.3  mrg               parg_size += 100;
   1019  1.1.1.3  mrg               pz_scan = make_raw_shell_str( pz_scan, pArg,
   1020  1.1.1.3  mrg                                             parg_size - (pz_scan - pz_cmd) );
   1021  1.1.1.3  mrg             }
   1022      1.1  mrg         }
   1023      1.1  mrg 
   1024      1.1  mrg       /*
   1025  1.1.1.4  mrg        * Close parenthesis if it's shell script.
   1026  1.1.1.4  mrg        */
   1027  1.1.1.4  mrg       if (p_fixd->fd_flags & FD_SHELL_SCRIPT)
   1028  1.1.1.4  mrg         {
   1029  1.1.1.4  mrg           strcpy (pz_scan, z_subshell_end);
   1030  1.1.1.4  mrg           pz_scan += strlen (z_subshell_end);
   1031  1.1.1.4  mrg         }
   1032  1.1.1.4  mrg 
   1033  1.1.1.4  mrg       /*
   1034      1.1  mrg        *  add the file machinations.
   1035      1.1  mrg        */
   1036  1.1.1.4  mrg #if defined(__MSDOS__) && !defined(__DJGPP__)
   1037      1.1  mrg       sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
   1038      1.1  mrg #else
   1039      1.1  mrg       sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
   1040      1.1  mrg                pz_temp_file, pz_temp_file, pz_temp_file);
   1041      1.1  mrg #endif
   1042      1.1  mrg     }
   1043  1.1.1.4  mrg   system_with_shell (pz_cmd);
   1044  1.1.1.4  mrg   free (pz_cmd);
   1045      1.1  mrg }
   1046      1.1  mrg 
   1047      1.1  mrg /* * * * * * * * * * * * *
   1048      1.1  mrg 
   1049      1.1  mrg     This loop should only cycle for 1/2 of one loop.
   1050      1.1  mrg     "chain_open" starts a process that uses "read_fd" as
   1051      1.1  mrg     its stdin and returns the new fd this process will use
   1052      1.1  mrg     for stdout.  */
   1053      1.1  mrg 
   1054      1.1  mrg #else /* is *NOT* SEPARATE_FIX_PROC */
   1055      1.1  mrg static int
   1056      1.1  mrg start_fixer (int read_fd, tFixDesc* p_fixd, char* pz_fix_file)
   1057      1.1  mrg {
   1058      1.1  mrg   tCC* pz_cmd_save;
   1059      1.1  mrg   char* pz_cmd;
   1060      1.1  mrg 
   1061      1.1  mrg   if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
   1062      1.1  mrg     return internal_fix (read_fd, p_fixd);
   1063      1.1  mrg 
   1064      1.1  mrg   if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
   1065      1.1  mrg     {
   1066      1.1  mrg       pz_cmd = NULL;
   1067      1.1  mrg       pz_cmd_save = NULL;
   1068      1.1  mrg     }
   1069      1.1  mrg   else
   1070      1.1  mrg     {
   1071      1.1  mrg       tSCC z_cmd_fmt[] = "file='%s'\n%s";
   1072      1.1  mrg       pz_cmd = XNEWVEC (char, strlen (p_fixd->patch_args[2])
   1073  1.1.1.3  mrg                         + sizeof (z_cmd_fmt) + strlen (pz_fix_file));
   1074      1.1  mrg       sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
   1075      1.1  mrg       pz_cmd_save = p_fixd->patch_args[2];
   1076      1.1  mrg       p_fixd->patch_args[2] = pz_cmd;
   1077      1.1  mrg     }
   1078      1.1  mrg 
   1079      1.1  mrg   /*  Start a fix process, handing off the  previous read fd for its
   1080      1.1  mrg       stdin and getting a new fd that reads from the fix process' stdout.
   1081      1.1  mrg       We normally will not loop, but we will up to 10 times if we keep
   1082      1.1  mrg       getting "EAGAIN" errors.
   1083      1.1  mrg 
   1084      1.1  mrg       */
   1085      1.1  mrg   for (;;)
   1086      1.1  mrg     {
   1087      1.1  mrg       static int failCt = 0;
   1088      1.1  mrg       int fd;
   1089      1.1  mrg 
   1090      1.1  mrg       fd = chain_open (read_fd,
   1091      1.1  mrg                        (tCC **) p_fixd->patch_args,
   1092      1.1  mrg                        (process_chain_head == -1)
   1093      1.1  mrg                        ? &process_chain_head : (pid_t *) NULL);
   1094      1.1  mrg 
   1095      1.1  mrg       if (fd != -1)
   1096      1.1  mrg         {
   1097      1.1  mrg           read_fd = fd;
   1098      1.1  mrg           break;
   1099      1.1  mrg         }
   1100      1.1  mrg 
   1101      1.1  mrg       fprintf (stderr, z_fork_err, errno, xstrerror (errno),
   1102      1.1  mrg                p_fixd->fix_name);
   1103      1.1  mrg 
   1104      1.1  mrg       if ((errno != EAGAIN) || (++failCt > 10))
   1105      1.1  mrg         exit (EXIT_FAILURE);
   1106      1.1  mrg       sleep (1);
   1107      1.1  mrg     }
   1108      1.1  mrg 
   1109      1.1  mrg   /*  IF we allocated a shell script command,
   1110      1.1  mrg       THEN free it and restore the command format to the fix description */
   1111      1.1  mrg   if (pz_cmd != (char*)NULL)
   1112      1.1  mrg     {
   1113      1.1  mrg       free ((void*)pz_cmd);
   1114      1.1  mrg       p_fixd->patch_args[2] = pz_cmd_save;
   1115      1.1  mrg     }
   1116      1.1  mrg 
   1117      1.1  mrg   return read_fd;
   1118      1.1  mrg }
   1119      1.1  mrg #endif
   1120  1.1.1.3  mrg #ifdef DEBUG
   1121  1.1.1.3  mrg # define NOTE_SKIP(_ttyp)  do {                                         \
   1122  1.1.1.3  mrg             if (VLEVEL( VERB_EVERYTHING ))                              \
   1123  1.1.1.3  mrg               fprintf (stderr, z_failed, _ttyp, p_fixd->fix_name,       \
   1124  1.1.1.3  mrg                        pz_fname, p_fixd->test_ct - test_ct);            \
   1125  1.1.1.3  mrg           } while (0)
   1126  1.1.1.3  mrg #else
   1127  1.1.1.3  mrg # define NOTE_SKIP(_ttyp)
   1128  1.1.1.3  mrg #endif
   1129      1.1  mrg 
   1130      1.1  mrg /* * * * * * * * * * * * *
   1131      1.1  mrg  *
   1132      1.1  mrg  *  Process the potential fixes for a particular include file.
   1133      1.1  mrg  *  Input:  the original text of the file and the file's name
   1134      1.1  mrg  *  Result: none.  A new file may or may not be created.
   1135      1.1  mrg  */
   1136      1.1  mrg static t_bool
   1137      1.1  mrg fix_applies (tFixDesc* p_fixd)
   1138      1.1  mrg {
   1139      1.1  mrg   const char *pz_fname = pz_curr_file;
   1140      1.1  mrg   const char *pz_scan = p_fixd->file_list;
   1141      1.1  mrg   int test_ct;
   1142      1.1  mrg   tTestDesc *p_test;
   1143  1.1.1.3  mrg   t_bool saw_sum_test   = BOOL_FALSE;
   1144  1.1.1.3  mrg   t_bool one_sum_passed = BOOL_FALSE;
   1145      1.1  mrg 
   1146  1.1.1.4  mrg #if defined(__MSDOS__) && !defined(__DJGPP__)
   1147      1.1  mrg   /*
   1148      1.1  mrg    *  There is only one fix that uses a shell script as of this writing.
   1149      1.1  mrg    *  I hope to nuke it anyway, it does not apply to DOS and it would
   1150      1.1  mrg    *  be painful to implement.  Therefore, no "shell" fixes for DOS.
   1151      1.1  mrg    */
   1152      1.1  mrg   if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
   1153      1.1  mrg     return BOOL_FALSE;
   1154      1.1  mrg #else
   1155      1.1  mrg   if (p_fixd->fd_flags & FD_SKIP_TEST)
   1156      1.1  mrg     return BOOL_FALSE;
   1157      1.1  mrg #endif
   1158      1.1  mrg 
   1159      1.1  mrg   /*  IF there is a file name restriction,
   1160      1.1  mrg       THEN ensure the current file name matches one in the pattern  */
   1161      1.1  mrg 
   1162      1.1  mrg   if (pz_scan != (char *) NULL)
   1163      1.1  mrg     {
   1164      1.1  mrg       while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
   1165      1.1  mrg         pz_fname += 2;
   1166      1.1  mrg 
   1167      1.1  mrg       for (;;)
   1168      1.1  mrg         {
   1169      1.1  mrg           if (fnmatch (pz_scan, pz_fname, 0) == 0)
   1170      1.1  mrg             break;
   1171      1.1  mrg           pz_scan += strlen (pz_scan) + 1;
   1172      1.1  mrg           if (*pz_scan == NUL)
   1173      1.1  mrg             return BOOL_FALSE;
   1174      1.1  mrg         }
   1175      1.1  mrg     }
   1176      1.1  mrg 
   1177      1.1  mrg   /*  FOR each test, see if it fails.
   1178  1.1.1.3  mrg       "sum" fails only if all "sum" tests fail.
   1179      1.1  mrg       IF it does fail, then we go on to the next test */
   1180      1.1  mrg 
   1181      1.1  mrg   for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
   1182      1.1  mrg        test_ct-- > 0;
   1183      1.1  mrg        p_test++)
   1184      1.1  mrg     {
   1185      1.1  mrg       switch (p_test->type)
   1186      1.1  mrg         {
   1187      1.1  mrg         case TT_TEST:
   1188      1.1  mrg           if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
   1189  1.1.1.3  mrg             NOTE_SKIP("TEST");
   1190      1.1  mrg             return BOOL_FALSE;
   1191      1.1  mrg           }
   1192      1.1  mrg           break;
   1193      1.1  mrg 
   1194      1.1  mrg         case TT_EGREP:
   1195      1.1  mrg           if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
   1196  1.1.1.3  mrg             NOTE_SKIP("EGREP");
   1197      1.1  mrg             return BOOL_FALSE;
   1198      1.1  mrg           }
   1199      1.1  mrg           break;
   1200      1.1  mrg 
   1201      1.1  mrg         case TT_NEGREP:
   1202      1.1  mrg           if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
   1203  1.1.1.3  mrg             NOTE_SKIP("NEGREP");
   1204      1.1  mrg             /*  Negated sense  */
   1205      1.1  mrg             return BOOL_FALSE;
   1206      1.1  mrg           }
   1207      1.1  mrg           break;
   1208      1.1  mrg 
   1209  1.1.1.3  mrg         case TT_CKSUM:
   1210  1.1.1.3  mrg 	  if (one_sum_passed)
   1211  1.1.1.3  mrg 	    break; /*  No need to check any more  */
   1212  1.1.1.3  mrg 
   1213  1.1.1.3  mrg           saw_sum_test = BOOL_TRUE;
   1214  1.1.1.3  mrg           if (cksum_test (pz_curr_data, p_test, pz_curr_file) != APPLY_FIX) {
   1215  1.1.1.3  mrg             NOTE_SKIP("CKSUM");
   1216  1.1.1.3  mrg           } else {
   1217  1.1.1.3  mrg             one_sum_passed = BOOL_TRUE;
   1218  1.1.1.3  mrg           }
   1219  1.1.1.3  mrg           break;
   1220  1.1.1.3  mrg 
   1221      1.1  mrg         case TT_FUNCTION:
   1222      1.1  mrg           if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
   1223      1.1  mrg               != APPLY_FIX) {
   1224  1.1.1.3  mrg             NOTE_SKIP("FTEST");
   1225      1.1  mrg             return BOOL_FALSE;
   1226      1.1  mrg           }
   1227      1.1  mrg           break;
   1228      1.1  mrg         }
   1229      1.1  mrg     }
   1230      1.1  mrg 
   1231  1.1.1.3  mrg   if (saw_sum_test)
   1232  1.1.1.3  mrg     return one_sum_passed;
   1233  1.1.1.3  mrg 
   1234      1.1  mrg   return BOOL_TRUE;
   1235      1.1  mrg }
   1236      1.1  mrg 
   1237      1.1  mrg 
   1238      1.1  mrg /* * * * * * * * * * * * *
   1239      1.1  mrg 
   1240      1.1  mrg    Write out a replacement file  */
   1241      1.1  mrg 
   1242      1.1  mrg static void
   1243      1.1  mrg write_replacement (tFixDesc* p_fixd)
   1244      1.1  mrg {
   1245      1.1  mrg    const char* pz_text = p_fixd->patch_args[0];
   1246      1.1  mrg 
   1247      1.1  mrg    if ((pz_text == (char*)NULL) || (*pz_text == NUL))
   1248      1.1  mrg      return;
   1249      1.1  mrg 
   1250      1.1  mrg    {
   1251      1.1  mrg      FILE* out_fp = create_file ();
   1252      1.1  mrg      size_t sz = strlen (pz_text);
   1253      1.1  mrg      fwrite (pz_text, sz, 1, out_fp);
   1254      1.1  mrg      if (pz_text[ sz-1 ] != '\n')
   1255      1.1  mrg        fputc ('\n', out_fp);
   1256      1.1  mrg      fclose (out_fp);
   1257      1.1  mrg    }
   1258      1.1  mrg }
   1259      1.1  mrg 
   1260      1.1  mrg 
   1261      1.1  mrg /* * * * * * * * * * * * *
   1262      1.1  mrg 
   1263      1.1  mrg     We have work to do.  Read back in the output
   1264      1.1  mrg     of the filtering chain.  Compare each byte as we read it with
   1265      1.1  mrg     the contents of the original file.  As soon as we find any
   1266      1.1  mrg     difference, we will create the output file, write out all
   1267      1.1  mrg     the matched text and then copy any remaining data from the
   1268      1.1  mrg     output of the filter chain.
   1269      1.1  mrg     */
   1270      1.1  mrg static void
   1271      1.1  mrg test_for_changes (int read_fd)
   1272      1.1  mrg {
   1273      1.1  mrg   FILE *in_fp = fdopen (read_fd, "r");
   1274      1.1  mrg   FILE *out_fp = (FILE *) NULL;
   1275      1.1  mrg   unsigned char *pz_cmp = (unsigned char*)pz_curr_data;
   1276      1.1  mrg 
   1277      1.1  mrg #ifdef DO_STATS
   1278      1.1  mrg   fixed_ct++;
   1279      1.1  mrg #endif
   1280      1.1  mrg   for (;;)
   1281      1.1  mrg     {
   1282      1.1  mrg       int ch;
   1283      1.1  mrg 
   1284      1.1  mrg       ch = getc (in_fp);
   1285      1.1  mrg       if (ch == EOF)
   1286      1.1  mrg         break;
   1287      1.1  mrg       ch &= 0xFF; /* all bytes are 8 bits */
   1288      1.1  mrg 
   1289      1.1  mrg       /*  IF we are emitting the output
   1290      1.1  mrg           THEN emit this character, too.
   1291      1.1  mrg       */
   1292      1.1  mrg       if (out_fp != (FILE *) NULL)
   1293      1.1  mrg         putc (ch, out_fp);
   1294      1.1  mrg 
   1295      1.1  mrg       /*  ELSE if this character does not match the original,
   1296      1.1  mrg           THEN now is the time to start the output.
   1297      1.1  mrg       */
   1298      1.1  mrg       else if (ch != *pz_cmp)
   1299      1.1  mrg         {
   1300      1.1  mrg           out_fp = create_file ();
   1301      1.1  mrg 
   1302      1.1  mrg #ifdef DO_STATS
   1303      1.1  mrg           altered_ct++;
   1304      1.1  mrg #endif
   1305      1.1  mrg           /*  IF there are matched data, write the matched part now. */
   1306      1.1  mrg           if ((char*)pz_cmp != pz_curr_data)
   1307      1.1  mrg             fwrite (pz_curr_data, (size_t)((char*)pz_cmp - pz_curr_data),
   1308  1.1.1.3  mrg                     1, out_fp);
   1309      1.1  mrg 
   1310      1.1  mrg           /*  Emit the current unmatching character */
   1311      1.1  mrg           putc (ch, out_fp);
   1312      1.1  mrg         }
   1313      1.1  mrg       else
   1314      1.1  mrg         /*  ELSE the character matches.  Advance the compare ptr */
   1315      1.1  mrg         pz_cmp++;
   1316      1.1  mrg     }
   1317      1.1  mrg 
   1318      1.1  mrg   /*  IF we created the output file, ... */
   1319      1.1  mrg   if (out_fp != (FILE *) NULL)
   1320      1.1  mrg     {
   1321      1.1  mrg       regmatch_t match;
   1322      1.1  mrg 
   1323      1.1  mrg       /* Close the file and see if we have to worry about
   1324      1.1  mrg          `#include "file.h"' constructs.  */
   1325      1.1  mrg       fclose (out_fp);
   1326      1.1  mrg       if (xregexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
   1327      1.1  mrg         extract_quoted_files (pz_curr_data, pz_curr_file, &match);
   1328      1.1  mrg     }
   1329      1.1  mrg 
   1330      1.1  mrg   fclose (in_fp);
   1331      1.1  mrg   close (read_fd);  /* probably redundant, but I'm paranoid */
   1332      1.1  mrg }
   1333      1.1  mrg 
   1334      1.1  mrg 
   1335      1.1  mrg /* * * * * * * * * * * * *
   1336      1.1  mrg 
   1337      1.1  mrg    Process the potential fixes for a particular include file.
   1338      1.1  mrg    Input:  the original text of the file and the file's name
   1339      1.1  mrg    Result: none.  A new file may or may not be created.  */
   1340      1.1  mrg 
   1341      1.1  mrg void
   1342      1.1  mrg process (void)
   1343      1.1  mrg {
   1344      1.1  mrg   tFixDesc *p_fixd = fixDescList;
   1345      1.1  mrg   int todo_ct = FIX_COUNT;
   1346      1.1  mrg   int read_fd = -1;
   1347      1.1  mrg # ifndef SEPARATE_FIX_PROC
   1348      1.1  mrg   int num_children = 0;
   1349      1.1  mrg # else /* is SEPARATE_FIX_PROC */
   1350      1.1  mrg   char* pz_file_source = pz_curr_file;
   1351      1.1  mrg # endif
   1352      1.1  mrg 
   1353      1.1  mrg   if (access (pz_curr_file, R_OK) != 0)
   1354      1.1  mrg     {
   1355  1.1.1.5  mrg       /* It may happens if for e. g. the distro ships some broken symlinks
   1356  1.1.1.5  mrg 	 in /usr/include.  */
   1357  1.1.1.5  mrg 
   1358  1.1.1.5  mrg       /* "INPUT" is exported in fixinc.sh, which is the pwd where fixincl
   1359  1.1.1.5  mrg 	 runs.  It's used instead of getcwd to avoid allocating a buffer
   1360  1.1.1.5  mrg 	 with unknown length.  */
   1361  1.1.1.5  mrg       const char *cwd = getenv ("INPUT");
   1362  1.1.1.5  mrg       if (!cwd)
   1363  1.1.1.5  mrg 	cwd = "the working directory";
   1364  1.1.1.5  mrg 
   1365  1.1.1.5  mrg       fprintf (stderr, "Cannot access %s from %s: %s\n", pz_curr_file, cwd,
   1366  1.1.1.5  mrg 	       xstrerror (errno));
   1367      1.1  mrg       return;
   1368      1.1  mrg     }
   1369      1.1  mrg 
   1370      1.1  mrg   pz_curr_data = load_file (pz_curr_file);
   1371      1.1  mrg   if (pz_curr_data == (char *) NULL)
   1372      1.1  mrg     return;
   1373      1.1  mrg 
   1374      1.1  mrg #ifdef DO_STATS
   1375      1.1  mrg   process_ct++;
   1376      1.1  mrg #endif
   1377      1.1  mrg   if (VLEVEL( VERB_PROGRESS ) && have_tty)
   1378      1.1  mrg     fprintf (stderr, "%6lu %-50s   \r",
   1379  1.1.1.3  mrg              (unsigned long) data_map_size, pz_curr_file);
   1380      1.1  mrg 
   1381      1.1  mrg # ifndef SEPARATE_FIX_PROC
   1382      1.1  mrg   process_chain_head = NOPROCESS;
   1383      1.1  mrg 
   1384      1.1  mrg   /* For every fix in our fix list, ...  */
   1385      1.1  mrg   for (; todo_ct > 0; p_fixd++, todo_ct--)
   1386      1.1  mrg     {
   1387      1.1  mrg       if (! fix_applies (p_fixd))
   1388      1.1  mrg         continue;
   1389      1.1  mrg 
   1390      1.1  mrg       if (VLEVEL( VERB_APPLIES ))
   1391      1.1  mrg         fprintf (stderr, "Applying %-24s to %s\n",
   1392      1.1  mrg                  p_fixd->fix_name, pz_curr_file);
   1393      1.1  mrg 
   1394      1.1  mrg       if (p_fixd->fd_flags & FD_REPLACEMENT)
   1395      1.1  mrg         {
   1396      1.1  mrg           write_replacement (p_fixd);
   1397      1.1  mrg           UNLOAD_DATA();
   1398      1.1  mrg           return;
   1399      1.1  mrg         }
   1400      1.1  mrg 
   1401      1.1  mrg       /*  IF we do not have a read pointer,
   1402      1.1  mrg           THEN this is the first fix for the current file.
   1403      1.1  mrg           Open the source file.  That will be used as stdin for
   1404      1.1  mrg           the first fix.  Any subsequent fixes will use the
   1405      1.1  mrg           stdout descriptor of the previous fix for its stdin.  */
   1406      1.1  mrg 
   1407      1.1  mrg       if (read_fd == -1)
   1408      1.1  mrg         {
   1409      1.1  mrg           read_fd = open (pz_curr_file, O_RDONLY);
   1410      1.1  mrg           if (read_fd < 0)
   1411      1.1  mrg             {
   1412      1.1  mrg               fprintf (stderr, "Error %d (%s) opening %s\n", errno,
   1413      1.1  mrg                        xstrerror (errno), pz_curr_file);
   1414      1.1  mrg               exit (EXIT_FAILURE);
   1415      1.1  mrg             }
   1416      1.1  mrg 
   1417      1.1  mrg           /*  Ensure we do not get duplicate output */
   1418      1.1  mrg 
   1419      1.1  mrg           fflush (stdout);
   1420      1.1  mrg         }
   1421      1.1  mrg 
   1422      1.1  mrg       read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
   1423      1.1  mrg       num_children++;
   1424      1.1  mrg     }
   1425      1.1  mrg 
   1426      1.1  mrg   /*  IF we have a read-back file descriptor,
   1427      1.1  mrg       THEN check for changes and write output if changed.   */
   1428      1.1  mrg 
   1429      1.1  mrg   if (read_fd >= 0)
   1430      1.1  mrg     {
   1431      1.1  mrg       test_for_changes (read_fd);
   1432      1.1  mrg #ifdef DO_STATS
   1433      1.1  mrg       apply_ct += num_children;
   1434      1.1  mrg #endif
   1435      1.1  mrg       /* Wait for child processes created by chain_open()
   1436      1.1  mrg          to avoid leaving zombies.  */
   1437      1.1  mrg       do  {
   1438      1.1  mrg         wait ((int *) NULL);
   1439      1.1  mrg       } while (--num_children > 0);
   1440      1.1  mrg     }
   1441      1.1  mrg 
   1442      1.1  mrg # else /* is SEPARATE_FIX_PROC */
   1443      1.1  mrg 
   1444      1.1  mrg   for (; todo_ct > 0; p_fixd++, todo_ct--)
   1445      1.1  mrg     {
   1446      1.1  mrg       if (! fix_applies (p_fixd))
   1447      1.1  mrg         continue;
   1448      1.1  mrg 
   1449      1.1  mrg       if (VLEVEL( VERB_APPLIES ))
   1450      1.1  mrg         fprintf (stderr, "Applying %-24s to %s\n",
   1451      1.1  mrg                  p_fixd->fix_name, pz_curr_file);
   1452      1.1  mrg 
   1453      1.1  mrg       if (p_fixd->fd_flags & FD_REPLACEMENT)
   1454      1.1  mrg         {
   1455      1.1  mrg           write_replacement (p_fixd);
   1456      1.1  mrg           UNLOAD_DATA();
   1457      1.1  mrg           return;
   1458      1.1  mrg         }
   1459      1.1  mrg       fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
   1460      1.1  mrg       pz_file_source = pz_temp_file;
   1461      1.1  mrg     }
   1462      1.1  mrg 
   1463      1.1  mrg   read_fd = open (pz_temp_file, O_RDONLY);
   1464      1.1  mrg   if (read_fd < 0)
   1465      1.1  mrg     {
   1466      1.1  mrg       if (errno != ENOENT)
   1467      1.1  mrg         fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
   1468      1.1  mrg                  errno, xstrerror (errno), pz_temp_file);
   1469      1.1  mrg     }
   1470      1.1  mrg   else
   1471      1.1  mrg     {
   1472      1.1  mrg       test_for_changes (read_fd);
   1473      1.1  mrg       /* Unlinking a file while it is still open is a Bad Idea on
   1474      1.1  mrg          DOS/Windows.  */
   1475      1.1  mrg       close (read_fd);
   1476      1.1  mrg       unlink (pz_temp_file);
   1477      1.1  mrg     }
   1478      1.1  mrg 
   1479      1.1  mrg # endif
   1480      1.1  mrg   UNLOAD_DATA();
   1481      1.1  mrg }
   1482