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