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