blob: fecfb19e1b1aa119787ea6aee3f5a87f513486b8 [file] [log] [blame]
Bruce Korb1f414ac1999-03-03 07:41:52 +00001/* Install modified versions of certain ANSI-incompatible system header
2 files which are fixed to work correctly with ANSI C and placed in a
Nathanael Nerode6e6a1682003-05-23 20:48:48 +00003 directory that GCC will search.
Bruce Korb1f414ac1999-03-03 07:41:52 +00004
Jakub Jelinek748086b2009-04-09 17:00:19 +02005 Copyright (C) 1997, 1998, 1999, 2000, 2004, 2009
6 Free Software Foundation, Inc.
Bruce Korb1f414ac1999-03-03 07:41:52 +00007
Nathanael Nerode6e6a1682003-05-23 20:48:48 +00008This file is part of GCC.
Bruce Korb1f414ac1999-03-03 07:41:52 +00009
Nathanael Nerode6e6a1682003-05-23 20:48:48 +000010GCC is free software; you can redistribute it and/or modify
Bruce Korb1f414ac1999-03-03 07:41:52 +000011it under the terms of the GNU General Public License as published by
Jakub Jelinek748086b2009-04-09 17:00:19 +020012the Free Software Foundation; either version 3, or (at your option)
Bruce Korb1f414ac1999-03-03 07:41:52 +000013any later version.
14
Nathanael Nerode6e6a1682003-05-23 20:48:48 +000015GCC is distributed in the hope that it will be useful,
Bruce Korb1f414ac1999-03-03 07:41:52 +000016but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Jakub Jelinek748086b2009-04-09 17:00:19 +020018GNU General Public License for more details.
Bruce Korb1f414ac1999-03-03 07:41:52 +000019
20You should have received a copy of the GNU General Public License
Jakub Jelinek748086b2009-04-09 17:00:19 +020021along with GCC; see the file COPYING3. If not see
22<http://www.gnu.org/licenses/>. */
Bruce Korb1f414ac1999-03-03 07:41:52 +000023
Bruce Korb5abc1f71999-10-12 14:44:18 +000024#include "fixlib.h"
Bruce Korb1f414ac1999-03-03 07:41:52 +000025
Bruce Korb401be4b2007-01-06 18:03:50 +000026#include <fnmatch.h>
Paolo Bonziniad643a72004-10-15 07:58:38 +000027#include <sys/stat.h>
Danny Smith8ba8f7e2005-05-22 17:01:02 +000028#ifndef SEPARATE_FIX_PROC
Gabriel Dos Reis03a9fcb2005-05-15 18:28:36 +000029#include <sys/wait.h>
Danny Smith8ba8f7e2005-05-22 17:01:02 +000030#endif
Paolo Bonziniad643a72004-10-15 07:58:38 +000031
Bruce Korb1e570a62000-09-05 22:28:04 +000032#if defined( HAVE_MMAP_FILE )
Philippe De Muyter99d525c1999-11-01 19:14:50 +010033#include <sys/mman.h>
34#define BAD_ADDR ((void*)-1)
35#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +000036
Daniel Berlin283da1d2000-12-02 19:46:32 +000037#ifndef SEPARATE_FIX_PROC
Bruce Korb0083c901998-10-16 07:00:18 +000038#include "server.h"
Bruce Korb62a99402000-08-04 14:16:57 +000039#endif
Bruce Korb0083c901998-10-16 07:00:18 +000040
Bruce Korb5abc1f71999-10-12 14:44:18 +000041/* The contents of this string are not very important. It is mostly
42 just used as part of the "I am alive and working" test. */
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +000043
Bruce Korb5abc1f71999-10-12 14:44:18 +000044static const char program_id[] = "fixincl version 1.1";
Bruce Korb0083c901998-10-16 07:00:18 +000045
Bruce Korbe02ecf32000-07-19 14:10:41 +000046/* This format will be used at the start of every generated file */
47
48static const char z_std_preamble[] =
49"/* DO NOT EDIT THIS FILE.\n\n\
50 It has been auto-edited by fixincludes from:\n\n\
51\t\"%s/%s\"\n\n\
52 This had to be done to correct non-standard usages in the\n\
53 original, manufacturer supplied header file. */\n\n";
54
Bruce Korb7d9ccd91999-03-31 11:51:29 +000055int find_base_len = 0;
Zack Weinbergd7eb5a41999-12-17 21:49:30 +000056int have_tty = 0;
Bruce Korbb35926b1999-11-11 14:57:55 +000057
Bruce Korb1f414ac1999-03-03 07:41:52 +000058pid_t process_chain_head = (pid_t) -1;
Bruce Korb0083c901998-10-16 07:00:18 +000059
Bruce Korb5abc1f71999-10-12 14:44:18 +000060char* pz_curr_file; /* name of the current file under test/fix */
61char* pz_curr_data; /* original contents of that file */
Bruce Korb62a99402000-08-04 14:16:57 +000062char* pz_temp_file; /* for DOS, a place to stash the temporary
63 fixed data between system(3) calls */
Bruce Korb5abc1f71999-10-12 14:44:18 +000064t_bool curr_data_mapped;
65int data_map_fd;
66size_t data_map_size;
67size_t ttl_data_size = 0;
Bruce Korbe02ecf32000-07-19 14:10:41 +000068
Bruce Korb5abc1f71999-10-12 14:44:18 +000069#ifdef DO_STATS
70int process_ct = 0;
71int apply_ct = 0;
72int fixed_ct = 0;
73int altered_ct = 0;
74#endif /* DO_STATS */
75
Bruce Korb1f414ac1999-03-03 07:41:52 +000076const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
Bruce Korb5abc1f71999-10-12 14:44:18 +000077tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
Bruce Korb1f414ac1999-03-03 07:41:52 +000078regex_t incl_quote_re;
Bruce Korb0083c901998-10-16 07:00:18 +000079
Nathanael Nerodef4dbf932003-08-01 23:07:04 +000080static void do_version (void) ATTRIBUTE_NORETURN;
81char *load_file (const char *);
82void run_compiles (void);
83void initialize (int argc, char** argv);
84void process (void);
Bruce Korb5abc1f71999-10-12 14:44:18 +000085
86/* External Source Code */
Bruce Korb0083c901998-10-16 07:00:18 +000087
88#include "fixincl.x"
89
Bruce Korb1f414ac1999-03-03 07:41:52 +000090/* * * * * * * * * * * * * * * * * * *
91 *
92 * MAIN ROUTINE
93 */
Nathanael Nerodef4dbf932003-08-01 23:07:04 +000094extern int main (int, char **);
Bruce Korb0083c901998-10-16 07:00:18 +000095int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +000096main (int argc, char** argv)
Bruce Korb0083c901998-10-16 07:00:18 +000097{
Bruce Korb5abc1f71999-10-12 14:44:18 +000098 char *file_name_buf;
Bruce Korb0083c901998-10-16 07:00:18 +000099
Bruce Korb35dfe412000-05-11 13:41:12 +0000100 initialize ( argc, argv );
Bruce Korbd1c6a031999-04-26 10:38:38 +0000101
Zack Weinbergd7eb5a41999-12-17 21:49:30 +0000102 have_tty = isatty (fileno (stderr));
103
Bruce Korb5abc1f71999-10-12 14:44:18 +0000104 /* Before anything else, ensure we can allocate our file name buffer. */
105 file_name_buf = load_file_data (stdin);
106
107 /* Because of the way server shells work, you have to keep stdin, out
108 and err open so that the proper input file does not get closed
109 by accident */
110
111 freopen ("/dev/null", "r", stdin);
112
113 if (file_name_buf == (char *) NULL)
114 {
115 fputs ("No file names listed for fixing\n", stderr);
116 exit (EXIT_FAILURE);
117 }
118
Bruce Korbd1c6a031999-04-26 10:38:38 +0000119 for (;;)
120 {
Bruce Korb5abc1f71999-10-12 14:44:18 +0000121 char* pz_end;
Bruce Korbd1c6a031999-04-26 10:38:38 +0000122
Bruce Korb5abc1f71999-10-12 14:44:18 +0000123 /* skip to start of name, past any "./" prefixes */
Bruce Korbd1c6a031999-04-26 10:38:38 +0000124
Bruce Korb5abc1f71999-10-12 14:44:18 +0000125 while (ISSPACE (*file_name_buf)) file_name_buf++;
126 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
127 file_name_buf += 2;
Bruce Korbd1c6a031999-04-26 10:38:38 +0000128
Bruce Korb5abc1f71999-10-12 14:44:18 +0000129 /* Check for end of list */
Bruce Korbd1c6a031999-04-26 10:38:38 +0000130
Bruce Korb5abc1f71999-10-12 14:44:18 +0000131 if (*file_name_buf == NUL)
132 break;
133
134 /* Set global file name pointer and find end of name */
135
136 pz_curr_file = file_name_buf;
137 pz_end = strchr( pz_curr_file, '\n' );
138 if (pz_end == (char*)NULL)
139 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
140 else
141 file_name_buf = pz_end + 1;
142
143 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
144
145 /* IF no name is found (blank line) or comment marker, skip line */
146
147 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
148 continue;
149 *pz_end = NUL;
150
Bruce Korb5abc1f71999-10-12 14:44:18 +0000151 process ();
Bruce Korb5abc1f71999-10-12 14:44:18 +0000152 } /* for (;;) */
Bruce Korbd1c6a031999-04-26 10:38:38 +0000153
Bruce Korb5abc1f71999-10-12 14:44:18 +0000154#ifdef DO_STATS
Bruce Korbb35926b1999-11-11 14:57:55 +0000155 if (VLEVEL( VERB_PROGRESS )) {
Bruce Korb5abc1f71999-10-12 14:44:18 +0000156 tSCC zFmt[] =
157 "\
158Processed %5d files containing %d bytes \n\
159Applying %5d fixes to %d files\n\
160Altering %5d of them\n";
Bruce Korbd1c6a031999-04-26 10:38:38 +0000161
Bruce Korb5abc1f71999-10-12 14:44:18 +0000162 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
163 fixed_ct, altered_ct);
164 }
165#endif /* DO_STATS */
Bruce Korb62a99402000-08-04 14:16:57 +0000166
Daniel Berlin283da1d2000-12-02 19:46:32 +0000167# ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +0000168 unlink( pz_temp_file );
169# endif
Bruce Korb15fe1a72001-01-05 16:28:58 +0000170 exit (EXIT_SUCCESS);
Bruce Korbd1c6a031999-04-26 10:38:38 +0000171}
172
173
Bruce Korb6864a6c2000-12-02 19:01:16 +0000174static void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000175do_version (void)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000176{
177 static const char zFmt[] = "echo '%s'";
178 char zBuf[ 1024 ];
179
180 /* The 'version' option is really used to test that:
181 1. The program loads correctly (no missing libraries)
Bruce Korb35dfe412000-05-11 13:41:12 +0000182 2. that we can compile all the regular expressions.
183 3. we can correctly run our server shell process
Bruce Korb5abc1f71999-10-12 14:44:18 +0000184 */
185 run_compiles ();
186 sprintf (zBuf, zFmt, program_id);
Daniel Berlin283da1d2000-12-02 19:46:32 +0000187#ifndef SEPARATE_FIX_PROC
Bruce Korb6b151aa2000-05-04 14:55:00 +0000188 puts (zBuf + 5);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000189 exit (strcmp (run_shell (zBuf), program_id));
Bruce Korb62a99402000-08-04 14:16:57 +0000190#else
191 exit (system (zBuf));
192#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +0000193}
194
Bruce Korbd1c6a031999-04-26 10:38:38 +0000195/* * * * * * * * * * * * */
196
197void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000198initialize ( int argc, char** argv )
Bruce Korbd1c6a031999-04-26 10:38:38 +0000199{
Bruce Korb878a5792000-07-12 14:45:05 +0000200 xmalloc_set_program_name (argv[0]);
201
Bruce Korb35dfe412000-05-11 13:41:12 +0000202 switch (argc)
203 {
204 case 1:
205 break;
206
207 case 2:
208 if (strcmp (argv[1], "-v") == 0)
209 do_version ();
210 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
211 {
212 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
213 errno, xstrerror (errno), argv[1] );
214 exit (EXIT_FAILURE);
215 }
216 break;
217
218 default:
219 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
220 exit (EXIT_FAILURE);
221 }
222
Bruce Korb798bdf72001-03-16 00:58:40 +0000223#ifdef SIGCHLD
224 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
225 receive the signal. A different setting is inheritable */
226 signal (SIGCHLD, SIG_DFL);
227#endif
228
Paolo Bonziniad643a72004-10-15 07:58:38 +0000229 initialize_opts ();
Bruce Korb0083c901998-10-16 07:00:18 +0000230
Bruce Korb6864a6c2000-12-02 19:01:16 +0000231 if (ISDIGIT ( *pz_verbose ))
Bruce Korbe02ecf32000-07-19 14:10:41 +0000232 verbose_level = (te_verbose)atoi( pz_verbose );
233 else
234 switch (*pz_verbose) {
235 case 's':
236 case 'S':
237 verbose_level = VERB_SILENT; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000238
Bruce Korbe02ecf32000-07-19 14:10:41 +0000239 case 'f':
240 case 'F':
241 verbose_level = VERB_FIXES; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000242
Bruce Korbe02ecf32000-07-19 14:10:41 +0000243 case 'a':
244 case 'A':
245 verbose_level = VERB_APPLIES; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000246
DJ Delorie7a9cdb12003-03-22 16:51:04 -0500247 default:
Bruce Korbe02ecf32000-07-19 14:10:41 +0000248 case 'p':
249 case 'P':
250 verbose_level = VERB_PROGRESS; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000251
Bruce Korbe02ecf32000-07-19 14:10:41 +0000252 case 't':
253 case 'T':
254 verbose_level = VERB_TESTS; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000255
Bruce Korbe02ecf32000-07-19 14:10:41 +0000256 case 'e':
257 case 'E':
258 verbose_level = VERB_EVERYTHING; break;
259 }
DJ Delorie7a9cdb12003-03-22 16:51:04 -0500260 if (verbose_level >= VERB_EVERYTHING) {
261 verbose_level = VERB_EVERYTHING;
262 fputs ("fixinc verbosity: EVERYTHING\n", stderr);
263 }
264 while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
265 pz_find_base += 2;
266 if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
267 find_base_len = strlen( pz_find_base );
Bruce Korb7d9ccd91999-03-31 11:51:29 +0000268
Bruce Korb1f414ac1999-03-03 07:41:52 +0000269 /* Compile all the regular expressions now.
270 That way, it is done only once for the whole run.
271 */
272 run_compiles ();
Bruce Korb0083c901998-10-16 07:00:18 +0000273
Daniel Berlin283da1d2000-12-02 19:46:32 +0000274# ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +0000275 /* NULL as the first argument to `tempnam' causes it to DTRT
276 wrt the temporary directory where the file will be created. */
277 pz_temp_file = tempnam( NULL, "fxinc" );
278# endif
279
Bruce Korb1f414ac1999-03-03 07:41:52 +0000280 signal (SIGQUIT, SIG_IGN);
281 signal (SIGIOT, SIG_IGN);
282 signal (SIGPIPE, SIG_IGN);
283 signal (SIGALRM, SIG_IGN);
284 signal (SIGTERM, SIG_IGN);
Bruce Korbd1c6a031999-04-26 10:38:38 +0000285}
Bruce Korb0083c901998-10-16 07:00:18 +0000286
Bruce Korb1f414ac1999-03-03 07:41:52 +0000287/* * * * * * * * * * * * *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000288
Bruce Korb1f414ac1999-03-03 07:41:52 +0000289 load_file loads all the contents of a file into malloc-ed memory.
290 Its argument is the name of the file to read in; the returned
291 result is the NUL terminated contents of the file. The file
292 is presumed to be an ASCII text file containing no NULs. */
Bruce Korb0083c901998-10-16 07:00:18 +0000293char *
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000294load_file ( const char* fname )
Bruce Korb0083c901998-10-16 07:00:18 +0000295{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000296 struct stat stbf;
297 char* res;
Bruce Korb0083c901998-10-16 07:00:18 +0000298
Bruce Korb5abc1f71999-10-12 14:44:18 +0000299 if (stat (fname, &stbf) != 0)
Bruce Korb0083c901998-10-16 07:00:18 +0000300 {
Bruce Korbb35926b1999-11-11 14:57:55 +0000301 if (NOT_SILENT)
302 fprintf (stderr, "error %d (%s) stat-ing %s\n",
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000303 errno, xstrerror (errno), fname );
Bruce Korb5abc1f71999-10-12 14:44:18 +0000304 return (char *) NULL;
305 }
306 if (stbf.st_size == 0)
307 return (char*)NULL;
308
Bruce Korba6efbec2000-09-05 18:29:56 +0000309 /* Make the data map size one larger than the file size for documentation
310 purposes. Truth is that there will be a following NUL character if
311 the file size is not a multiple of the page size. If it is a multiple,
312 then this adjustment sometimes fails anyway. */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000313 data_map_size = stbf.st_size+1;
314 data_map_fd = open (fname, O_RDONLY);
315 ttl_data_size += data_map_size-1;
316
317 if (data_map_fd < 0)
318 {
Bruce Korbb35926b1999-11-11 14:57:55 +0000319 if (NOT_SILENT)
320 fprintf (stderr, "error %d (%s) opening %s for read\n",
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000321 errno, xstrerror (errno), fname);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000322 return (char*)NULL;
Bruce Korb0083c901998-10-16 07:00:18 +0000323 }
324
Zack Weinberg56f02b82000-04-17 17:25:57 +0000325#ifdef HAVE_MMAP_FILE
Bruce Korb5abc1f71999-10-12 14:44:18 +0000326 curr_data_mapped = BOOL_TRUE;
Bruce Korba6efbec2000-09-05 18:29:56 +0000327
328 /* IF the file size is a multiple of the page size,
329 THEN sometimes you will seg fault trying to access a trailing byte */
Bruce Korbdc465052000-09-05 22:26:16 +0000330 if ((stbf.st_size & (getpagesize()-1)) == 0)
Bruce Korba6efbec2000-09-05 18:29:56 +0000331 res = (char*)BAD_ADDR;
332 else
333 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
334 MAP_PRIVATE, data_map_fd, 0);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000335 if (res == (char*)BAD_ADDR)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000336#endif
Bruce Korbca21b4a2001-02-06 22:19:50 +0000337 {
338 FILE* fp = fdopen (data_map_fd, "r");
339 curr_data_mapped = BOOL_FALSE;
340 res = load_file_data (fp);
341 fclose (fp);
342 }
Bruce Korb0083c901998-10-16 07:00:18 +0000343
Bruce Korb5abc1f71999-10-12 14:44:18 +0000344 return res;
Bruce Korb0083c901998-10-16 07:00:18 +0000345}
346
Bruce Korb6864a6c2000-12-02 19:01:16 +0000347static int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000348machine_matches( tFixDesc* p_fixd )
Bruce Korb401be4b2007-01-06 18:03:50 +0000349{
350 char const ** papz_machs = p_fixd->papz_machs;
351 int have_match = BOOL_FALSE;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000352
Bruce Korb62a99402000-08-04 14:16:57 +0000353 for (;;)
354 {
Bruce Korb401be4b2007-01-06 18:03:50 +0000355 char const * pz_mpat = *(papz_machs++);
356 if (pz_mpat == NULL)
Bruce Korb62a99402000-08-04 14:16:57 +0000357 break;
Bruce Korb401be4b2007-01-06 18:03:50 +0000358 if (fnmatch(pz_mpat, pz_machine, 0) == 0)
359 {
360 have_match = BOOL_TRUE;
361 break;
362 }
Bruce Korb62a99402000-08-04 14:16:57 +0000363 }
364
Bruce Korb2f82a972007-01-06 20:02:22 +0000365 /* Check for sense inversion then set the "skip test" flag, if needed */
Bruce Korb401be4b2007-01-06 18:03:50 +0000366 if (p_fixd->fd_flags & FD_MACH_IFNOT)
Bruce Korb2f82a972007-01-06 20:02:22 +0000367 have_match = ! have_match;
368
369 if (! have_match)
370 p_fixd->fd_flags |= FD_SKIP_TEST;
371
Bruce Korb401be4b2007-01-06 18:03:50 +0000372 return have_match;
Bruce Korb62a99402000-08-04 14:16:57 +0000373}
374
375/* * * * * * * * * * * * *
Bruce Korb401be4b2007-01-06 18:03:50 +0000376 *
377 * run_compiles run all the regexp compiles for all the fixes once.
378 */
Bruce Korb62a99402000-08-04 14:16:57 +0000379void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000380run_compiles (void)
Bruce Korb62a99402000-08-04 14:16:57 +0000381{
382 tFixDesc *p_fixd = fixDescList;
383 int fix_ct = FIX_COUNT;
Gabriel Dos Reis03a9fcb2005-05-15 18:28:36 +0000384 regex_t *p_re = XCNEWVEC (regex_t, REGEX_COUNT);
Bruce Korb62a99402000-08-04 14:16:57 +0000385
386 /* Make sure compile_re does not stumble across invalid data */
387
Kaveh R. Ghazic68b0a82003-07-19 16:09:51 +0000388 memset (&incl_quote_re, '\0', sizeof (regex_t));
Bruce Korb62a99402000-08-04 14:16:57 +0000389
390 compile_re (incl_quote_pat, &incl_quote_re, 1,
391 "quoted include", "run_compiles");
392
393 /* Allow machine name tests to be ignored (testing, mainly) */
394
395 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
396 pz_machine = (char*)NULL;
397
398 /* FOR every fixup, ... */
399 do
400 {
Bruce Korb7e416542012-10-29 16:44:34 +0000401 tTestDesc *p_test;
402 int test_ct;
403
404 if (fixinc_mode && (p_fixd->fd_flags & FD_REPLACEMENT))
405 {
406 p_fixd->fd_flags |= FD_SKIP_TEST;
407 continue;
408 }
409
410 p_test = p_fixd->p_test_desc;
411 test_ct = p_fixd->test_ct;
Bruce Korb62a99402000-08-04 14:16:57 +0000412
413 /* IF the machine type pointer is not NULL (we are not in test mode)
414 AND this test is for or not done on particular machines
415 THEN ... */
416
417 if ( (pz_machine != NULL)
418 && (p_fixd->papz_machs != (const char**) NULL)
419 && ! machine_matches (p_fixd) )
420 continue;
Bruce Korb1f414ac1999-03-03 07:41:52 +0000421
422 /* FOR every test for the fixup, ... */
423
424 while (--test_ct >= 0)
425 {
426 switch (p_test->type)
Bruce Korb0083c901998-10-16 07:00:18 +0000427 {
428 case TT_EGREP:
429 case TT_NEGREP:
Bruce Korb1f414ac1999-03-03 07:41:52 +0000430 p_test->p_test_regex = p_re++;
Bruce Korb35dfe412000-05-11 13:41:12 +0000431 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
432 "select test", p_fixd->fix_name);
Bruce Korb3af556f2000-09-12 14:28:55 +0000433 default: break;
Bruce Korb35dfe412000-05-11 13:41:12 +0000434 }
Bruce Korb1f414ac1999-03-03 07:41:52 +0000435 p_test++;
Bruce Korb0083c901998-10-16 07:00:18 +0000436 }
437 }
Bruce Korb1f414ac1999-03-03 07:41:52 +0000438 while (p_fixd++, --fix_ct > 0);
Bruce Korb0083c901998-10-16 07:00:18 +0000439}
440
441
Bruce Korb1f414ac1999-03-03 07:41:52 +0000442/* * * * * * * * * * * * *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000443
Bruce Korb1f414ac1999-03-03 07:41:52 +0000444 create_file Create the output modified file.
445 Input: the name of the file to create
446 Returns: a file pointer to the new, open file */
447
Bruce Korb063174e1999-11-04 14:50:44 +0000448#if defined(S_IRUSR) && defined(S_IWUSR) && \
449 defined(S_IRGRP) && defined(S_IROTH)
450
451# define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
452#else
453# define S_IRALL 0644
454#endif
455
456#if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
457 defined(S_IROTH) && defined(S_IXOTH)
458
459# define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
460#else
461# define S_DIRALL 0755
462#endif
463
Bruce Korb1f414ac1999-03-03 07:41:52 +0000464
Bruce Korb6864a6c2000-12-02 19:01:16 +0000465static FILE *
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000466create_file (void)
Bruce Korb0083c901998-10-16 07:00:18 +0000467{
468 int fd;
469 FILE *pf;
470 char fname[MAXPATHLEN];
471
Bruce Korb5abc1f71999-10-12 14:44:18 +0000472 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
Bruce Korb0083c901998-10-16 07:00:18 +0000473
Bruce Korb1f414ac1999-03-03 07:41:52 +0000474 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
Bruce Korb0083c901998-10-16 07:00:18 +0000475
Bruce Korb1f414ac1999-03-03 07:41:52 +0000476 /* We may need to create the directories needed... */
Bruce Korb0083c901998-10-16 07:00:18 +0000477 if ((fd < 0) && (errno == ENOENT))
478 {
Bruce Korb1f414ac1999-03-03 07:41:52 +0000479 char *pz_dir = strchr (fname + 1, '/');
Bruce Korb0083c901998-10-16 07:00:18 +0000480 struct stat stbf;
481
Bruce Korb1f414ac1999-03-03 07:41:52 +0000482 while (pz_dir != (char *) NULL)
Bruce Korb0083c901998-10-16 07:00:18 +0000483 {
Bruce Korb1f414ac1999-03-03 07:41:52 +0000484 *pz_dir = NUL;
Bruce Korb0083c901998-10-16 07:00:18 +0000485 if (stat (fname, &stbf) < 0)
486 {
Aaron W. LaFramboisef4a8f272004-10-20 02:21:09 -0600487#ifdef _WIN32
488 mkdir (fname);
489#else
Bruce Korb063174e1999-11-04 14:50:44 +0000490 mkdir (fname, S_IFDIR | S_DIRALL);
Aaron W. LaFramboisef4a8f272004-10-20 02:21:09 -0600491#endif
Bruce Korb0083c901998-10-16 07:00:18 +0000492 }
493
Bruce Korb1f414ac1999-03-03 07:41:52 +0000494 *pz_dir = '/';
495 pz_dir = strchr (pz_dir + 1, '/');
Bruce Korb0083c901998-10-16 07:00:18 +0000496 }
Bruce Korb1f414ac1999-03-03 07:41:52 +0000497
498 /* Now, lets try the open again... */
499 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
Bruce Korb0083c901998-10-16 07:00:18 +0000500 }
501 if (fd < 0)
502 {
503 fprintf (stderr, "Error %d (%s) creating %s\n",
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000504 errno, xstrerror (errno), fname);
Bruce Korb0083c901998-10-16 07:00:18 +0000505 exit (EXIT_FAILURE);
506 }
Bruce Korbb35926b1999-11-11 14:57:55 +0000507 if (NOT_SILENT)
508 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
Bruce Korb0083c901998-10-16 07:00:18 +0000509 pf = fdopen (fd, "w");
510
Bruce Korbe02ecf32000-07-19 14:10:41 +0000511 /*
512 * IF pz_machine is NULL, then we are in some sort of test mode.
513 * Do not insert the current directory name. Use a constant string.
514 */
515 fprintf (pf, z_std_preamble,
516 (pz_machine == NULL)
517 ? "fixinc/tests/inc"
518 : pz_input_dir,
519 pz_curr_file);
Bruce Korb0083c901998-10-16 07:00:18 +0000520
Bruce Korb0083c901998-10-16 07:00:18 +0000521 return pf;
522}
523
Bruce Korb1f414ac1999-03-03 07:41:52 +0000524
525/* * * * * * * * * * * * *
526
527 test_test make sure a shell-style test expression passes.
528 Input: a pointer to the descriptor of the test to run and
529 the name of the file that we might want to fix
Bruce Korb5abc1f71999-10-12 14:44:18 +0000530 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
Bruce Korb1f414ac1999-03-03 07:41:52 +0000531 shell script we run. */
Daniel Berlin283da1d2000-12-02 19:46:32 +0000532#ifndef SEPARATE_FIX_PROC
Bruce Korb6864a6c2000-12-02 19:01:16 +0000533static int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000534test_test (tTestDesc* p_test, char* pz_test_file)
Bruce Korb0083c901998-10-16 07:00:18 +0000535{
Bruce Korb94db2f71999-05-12 07:32:58 +0000536 tSCC cmd_fmt[] =
537"file=%s\n\
538if ( test %s ) > /dev/null 2>&1\n\
539then echo TRUE\n\
540else echo FALSE\n\
541fi";
542
Bruce Korb1f414ac1999-03-03 07:41:52 +0000543 char *pz_res;
Bruce Korbe9099382000-05-17 14:56:13 +0000544 int res;
Bruce Korb0083c901998-10-16 07:00:18 +0000545
Bruce Korb1f414ac1999-03-03 07:41:52 +0000546 static char cmd_buf[4096];
Bruce Korb0083c901998-10-16 07:00:18 +0000547
Bruce Korb5abc1f71999-10-12 14:44:18 +0000548 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
Bruce Korb1f414ac1999-03-03 07:41:52 +0000549 pz_res = run_shell (cmd_buf);
Bruce Korbe9099382000-05-17 14:56:13 +0000550
551 switch (*pz_res) {
552 case 'T':
Bruce Korb5abc1f71999-10-12 14:44:18 +0000553 res = APPLY_FIX;
Bruce Korbe9099382000-05-17 14:56:13 +0000554 break;
555
556 case 'F':
557 res = SKIP_FIX;
558 break;
559
560 default:
561 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
562 pz_res, cmd_buf );
James A. Morrison9cdfc8e2004-01-27 19:10:10 +0000563 res = SKIP_FIX;
Bruce Korbe9099382000-05-17 14:56:13 +0000564 }
565
Bruce Korb1f414ac1999-03-03 07:41:52 +0000566 free ((void *) pz_res);
Bruce Korb0083c901998-10-16 07:00:18 +0000567 return res;
568}
Bruce Korb62a99402000-08-04 14:16:57 +0000569#else
570/*
571 * IF we are in MS-DOS land, then whatever shell-type test is required
572 * will, by definition, fail
573 */
574#define test_test(t,tf) SKIP_FIX
575#endif
Bruce Korb0083c901998-10-16 07:00:18 +0000576
Bruce Korb1f414ac1999-03-03 07:41:52 +0000577/* * * * * * * * * * * * *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000578
Bruce Korb1f414ac1999-03-03 07:41:52 +0000579 egrep_test make sure an egrep expression is found in the file text.
580 Input: a pointer to the descriptor of the test to run and
581 the pointer to the contents of the file under suspicion
Bruce Korb5abc1f71999-10-12 14:44:18 +0000582 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
Bruce Korb1f414ac1999-03-03 07:41:52 +0000583
Bruce Korb5abc1f71999-10-12 14:44:18 +0000584 The caller may choose to reverse meaning if the sense of the test
Bruce Korb1f414ac1999-03-03 07:41:52 +0000585 is inverted. */
586
Bruce Korb6864a6c2000-12-02 19:01:16 +0000587static int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000588egrep_test (char* pz_data, tTestDesc* p_test)
Bruce Korb0083c901998-10-16 07:00:18 +0000589{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000590#ifdef DEBUG
Bruce Korb1f414ac1999-03-03 07:41:52 +0000591 if (p_test->p_test_regex == 0)
592 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
593 p_test->pz_test_text);
Bruce Korb0083c901998-10-16 07:00:18 +0000594#endif
Zack Weinbergab747402003-07-08 20:42:19 +0000595 if (xregexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000596 return APPLY_FIX;
597 return SKIP_FIX;
Bruce Korb0083c901998-10-16 07:00:18 +0000598}
599
600
Bruce Korb1f414ac1999-03-03 07:41:52 +0000601/* * * * * * * * * * * * *
Bruce Korb94db2f71999-05-12 07:32:58 +0000602
603 quoted_file_exists Make sure that a file exists before we emit
604 the file name. If we emit the name, our invoking shell will try
605 to copy a non-existing file into the destination directory. */
606
Bruce Korb6864a6c2000-12-02 19:01:16 +0000607static int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000608quoted_file_exists (const char* pz_src_path,
609 const char* pz_file_path,
610 const char* pz_file)
Bruce Korb94db2f71999-05-12 07:32:58 +0000611{
612 char z[ MAXPATHLEN ];
613 char* pz;
614 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
615 pz = z + strlen ( z );
616
617 for (;;) {
618 char ch = *pz_file++;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000619 if (! ISGRAPH( ch ))
Bruce Korb94db2f71999-05-12 07:32:58 +0000620 return 0;
621 if (ch == '"')
622 break;
623 *pz++ = ch;
624 }
625 *pz = '\0';
626 {
627 struct stat s;
628 if (stat (z, &s) != 0)
629 return 0;
630 return S_ISREG( s.st_mode );
631 }
632}
633
634
635/* * * * * * * * * * * * *
Bruce Korb1f414ac1999-03-03 07:41:52 +0000636 *
637 extract_quoted_files
Bruce Korb5abc1f71999-10-12 14:44:18 +0000638
Bruce Korb1f414ac1999-03-03 07:41:52 +0000639 The syntax, `#include "file.h"' specifies that the compiler is to
640 search the local directory of the current file before the include
641 list. Consequently, if we have modified a header and stored it in
642 another directory, any files that are included by that modified
643 file in that fashion must also be copied into this new directory.
644 This routine finds those flavors of #include and for each one found
645 emits a triple of:
Bruce Korb5abc1f71999-10-12 14:44:18 +0000646
Bruce Korb1f414ac1999-03-03 07:41:52 +0000647 1. source directory of the original file
648 2. the relative path file name of the #includ-ed file
649 3. the full destination path for this file
650
651 Input: the text of the file, the file name and a pointer to the
652 match list where the match information was stored.
653 Result: internally nothing. The results are written to stdout
654 for interpretation by the invoking shell */
Bruce Korb0083c901998-10-16 07:00:18 +0000655
Bruce Korb94db2f71999-05-12 07:32:58 +0000656
Bruce Korb6864a6c2000-12-02 19:01:16 +0000657static void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000658extract_quoted_files (char* pz_data,
659 const char* pz_fixed_file,
660 regmatch_t* p_re_match)
Bruce Korb0083c901998-10-16 07:00:18 +0000661{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000662 char *pz_dir_end = strrchr (pz_fixed_file, '/');
Bruce Korb1f414ac1999-03-03 07:41:52 +0000663 char *pz_incl_quot = pz_data;
Bruce Korb0083c901998-10-16 07:00:18 +0000664
Bruce Korbb35926b1999-11-11 14:57:55 +0000665 if (VLEVEL( VERB_APPLIES ))
666 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
Bruce Korb0083c901998-10-16 07:00:18 +0000667
Bruce Korb5abc1f71999-10-12 14:44:18 +0000668 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
Bruce Korb94db2f71999-05-12 07:32:58 +0000669 If there is none, then it is in our current directory, ".". */
Bruce Korb1f414ac1999-03-03 07:41:52 +0000670
671 if (pz_dir_end == (char *) NULL)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000672 pz_fixed_file = ".";
Bruce Korb0083c901998-10-16 07:00:18 +0000673 else
Bruce Korb1f414ac1999-03-03 07:41:52 +0000674 *pz_dir_end = '\0';
Bruce Korb0083c901998-10-16 07:00:18 +0000675
676 for (;;)
677 {
Bruce Korb1f414ac1999-03-03 07:41:52 +0000678 pz_incl_quot += p_re_match->rm_so;
Bruce Korb0083c901998-10-16 07:00:18 +0000679
Bruce Korb1f414ac1999-03-03 07:41:52 +0000680 /* Skip forward to the included file name */
Zack Weinbergf6bbde22000-12-08 03:00:26 +0000681 while (*pz_incl_quot != '"')
Bruce Korb1f414ac1999-03-03 07:41:52 +0000682 pz_incl_quot++;
Bruce Korb0083c901998-10-16 07:00:18 +0000683
Bruce Korb5abc1f71999-10-12 14:44:18 +0000684 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
Bruce Korb94db2f71999-05-12 07:32:58 +0000685 {
686 /* Print the source directory and the subdirectory
687 of the file in question. */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000688 printf ("%s %s/", pz_src_dir, pz_fixed_file);
Bruce Korb94db2f71999-05-12 07:32:58 +0000689 pz_dir_end = pz_incl_quot;
Bruce Korb0083c901998-10-16 07:00:18 +0000690
Bruce Korb94db2f71999-05-12 07:32:58 +0000691 /* Append to the directory the relative path of the desired file */
692 while (*pz_incl_quot != '"')
693 putc (*pz_incl_quot++, stdout);
Bruce Korb0083c901998-10-16 07:00:18 +0000694
Bruce Korb94db2f71999-05-12 07:32:58 +0000695 /* Now print the destination directory appended with the
696 relative path of the desired file */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000697 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
Bruce Korb94db2f71999-05-12 07:32:58 +0000698 while (*pz_dir_end != '"')
699 putc (*pz_dir_end++, stdout);
Bruce Korb0083c901998-10-16 07:00:18 +0000700
Bruce Korb94db2f71999-05-12 07:32:58 +0000701 /* End of entry */
702 putc ('\n', stdout);
703 }
Bruce Korb0083c901998-10-16 07:00:18 +0000704
Bruce Korb1f414ac1999-03-03 07:41:52 +0000705 /* Find the next entry */
Zack Weinbergab747402003-07-08 20:42:19 +0000706 if (xregexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
Bruce Korb0083c901998-10-16 07:00:18 +0000707 break;
708 }
709}
710
711
Bruce Korb5abc1f71999-10-12 14:44:18 +0000712/* * * * * * * * * * * * *
713
714 Somebody wrote a *_fix subroutine that we must call.
715 */
Daniel Berlin283da1d2000-12-02 19:46:32 +0000716#ifndef SEPARATE_FIX_PROC
Bruce Korb6864a6c2000-12-02 19:01:16 +0000717static int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000718internal_fix (int read_fd, tFixDesc* p_fixd)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000719{
720 int fd[2];
721
722 if (pipe( fd ) != 0)
723 {
724 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
725 exit (EXIT_FAILURE);
726 }
727
728 for (;;)
729 {
730 pid_t childid = fork();
731
732 switch (childid)
733 {
734 case -1:
735 break;
736
737 case 0:
738 close (fd[0]);
739 goto do_child_task;
740
741 default:
742 /*
743 * Parent process
744 */
745 close (read_fd);
746 close (fd[1]);
747 return fd[0];
748 }
749
750 /*
751 * Parent in error
752 */
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000753 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
Bruce Korb5abc1f71999-10-12 14:44:18 +0000754 p_fixd->fix_name);
755 {
756 static int failCt = 0;
757 if ((errno != EAGAIN) || (++failCt > 10))
758 exit (EXIT_FAILURE);
759 sleep (1);
760 }
761 } do_child_task:;
762
763 /*
764 * Close our current stdin and stdout
765 */
766 close (STDIN_FILENO);
767 close (STDOUT_FILENO);
768 UNLOAD_DATA();
769
770 /*
771 * Make the fd passed in the stdin, and the write end of
772 * the new pipe become the stdout.
773 */
Aaron W. LaFramboisef4a8f272004-10-20 02:21:09 -0600774 dup2 (fd[1], STDOUT_FILENO);
775 dup2 (read_fd, STDIN_FILENO);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000776
Bruce Korb35dfe412000-05-11 13:41:12 +0000777 apply_fix (p_fixd, pz_curr_file);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000778 exit (0);
779}
Daniel Berlin283da1d2000-12-02 19:46:32 +0000780#endif /* !SEPARATE_FIX_PROC */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000781
Bruce Korbbb786201999-06-02 07:08:54 +0000782
Daniel Berlin283da1d2000-12-02 19:46:32 +0000783#ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +0000784static void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000785fix_with_system (tFixDesc* p_fixd,
786 tCC* pz_fix_file,
787 tCC* pz_file_source,
788 tCC* pz_temp_file)
Bruce Korb62a99402000-08-04 14:16:57 +0000789{
790 char* pz_cmd;
791 char* pz_scan;
792 size_t argsize;
793
794 if (p_fixd->fd_flags & FD_SUBROUTINE)
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000795 {
796 static const char z_applyfix_prog[] =
797 "/../fixincludes/applyfix" EXE_EXT;
Bruce Korb62a99402000-08-04 14:16:57 +0000798
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000799 struct stat buf;
800 argsize = 32
801 + strlen (pz_orig_dir)
802 + sizeof (z_applyfix_prog)
803 + strlen (pz_fix_file)
804 + strlen (pz_file_source)
805 + strlen (pz_temp_file);
Bruce Korb62a99402000-08-04 14:16:57 +0000806
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000807 /* Allocate something sure to be big enough for our purposes */
Gabriel Dos Reis03a9fcb2005-05-15 18:28:36 +0000808 pz_cmd = XNEWVEC (char, argsize);
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000809 strcpy (pz_cmd, pz_orig_dir);
810 pz_scan = pz_cmd + strlen (pz_orig_dir);
Bruce Korb62a99402000-08-04 14:16:57 +0000811
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000812 strcpy (pz_scan, z_applyfix_prog);
Bruce Korb62a99402000-08-04 14:16:57 +0000813
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000814 /* IF we can't find the "applyfix" executable file at the first guess,
815 try one level higher up */
816 if (stat (pz_cmd, &buf) == -1)
817 {
818 strcpy (pz_scan, "/..");
819 strcpy (pz_scan+3, z_applyfix_prog);
820 }
821
822 pz_scan += strlen (pz_scan);
823
824 /*
825 * Now add the fix number and file names that may be needed
826 */
Tristan Gingoldc1041242012-04-24 09:24:55 +0000827 sprintf (pz_scan, " %ld '%s' '%s' '%s'", (long) (p_fixd - fixDescList),
Bruce Korb43c1b5d2004-11-17 04:20:36 +0000828 pz_fix_file, pz_file_source, pz_temp_file);
829 }
Bruce Korb62a99402000-08-04 14:16:57 +0000830 else /* NOT an "internal" fix: */
831 {
832 size_t parg_size;
Daniel Berlin283da1d2000-12-02 19:46:32 +0000833#ifdef __MSDOS__
Bruce Korb62a99402000-08-04 14:16:57 +0000834 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
Daniel Berlin283da1d2000-12-02 19:46:32 +0000835 dst is a temporary file anyway, so we know there's no other
836 file by that name; and DOS's system(3) doesn't mind to
Eli Zaretskiidc13bad2000-08-21 19:28:18 +0300837 clobber existing file in redirection. Besides, with DOS 8+3
838 limited file namespace, we can easily lose if dst already has
839 an extension that is 3 or more characters long.
Daniel Berlin283da1d2000-12-02 19:46:32 +0000840
841 I do not think the 8+3 issue is relevant because all the files
842 we operate on are named "*.h", making 8+2 adequate. Anyway,
843 the following bizarre use of 'cat' only works on DOS boxes.
844 It causes the file to be dropped into a temporary file for
Eli Zaretskiidc13bad2000-08-21 19:28:18 +0300845 'cat' to read (pipes do not work on DOS). */
Bruce Korbecb0d202004-11-17 05:06:41 +0000846 tSCC z_cmd_fmt[] = " '%s' | cat > '%s'";
Daniel Berlin283da1d2000-12-02 19:46:32 +0000847#else
848 /* Don't use positional formatting arguments because some lame-o
849 implementations cannot cope :-(. */
850 tSCC z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
851#endif
Bruce Korb62a99402000-08-04 14:16:57 +0000852 tCC** ppArgs = p_fixd->patch_args;
853
854 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
855 + strlen( pz_file_source );
856 parg_size = argsize;
857
858
859 /*
860 * Compute the size of the command line. Add lotsa extra space
861 * because some of the args to sed use lotsa single quotes.
862 * (This requires three extra bytes per quote. Here we allow
863 * for up to 8 single quotes for each argument, including the
864 * command name "sed" itself. Nobody will *ever* need more. :)
865 */
866 for (;;)
867 {
868 tCC* p_arg = *(ppArgs++);
869 if (p_arg == NULL)
870 break;
871 argsize += 24 + strlen( p_arg );
872 }
873
874 /* Estimated buffer size we will need. */
Gabriel Dos Reis03a9fcb2005-05-15 18:28:36 +0000875 pz_scan = pz_cmd = XNEWVEC (char, argsize);
Bruce Korb62a99402000-08-04 14:16:57 +0000876 /* How much of it do we allot to the program name and its
877 arguments. */
878 parg_size = argsize - parg_size;
879
880 ppArgs = p_fixd->patch_args;
881
882 /*
883 * Copy the program name, unquoted
884 */
885 {
886 tCC* pArg = *(ppArgs++);
887 for (;;)
888 {
889 char ch = *(pArg++);
890 if (ch == NUL)
891 break;
892 *(pz_scan++) = ch;
893 }
894 }
895
896 /*
897 * Copy the program arguments, quoted
898 */
899 for (;;)
900 {
901 tCC* pArg = *(ppArgs++);
902 char* pz_scan_save;
903 if (pArg == NULL)
904 break;
905 *(pz_scan++) = ' ';
906 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
907 parg_size - (pz_scan - pz_cmd) );
908 /*
909 * Make sure we don't overflow the buffer due to sloppy
910 * size estimation.
911 */
912 while (pz_scan == (char*)NULL)
913 {
914 size_t already_filled = pz_scan_save - pz_cmd;
Kaveh R. Ghazic68b0a82003-07-19 16:09:51 +0000915 pz_cmd = xrealloc (pz_cmd, argsize += 100);
Bruce Korb62a99402000-08-04 14:16:57 +0000916 pz_scan_save = pz_scan = pz_cmd + already_filled;
917 parg_size += 100;
918 pz_scan = make_raw_shell_str( pz_scan, pArg,
919 parg_size - (pz_scan - pz_cmd) );
920 }
921 }
922
923 /*
924 * add the file machinations.
925 */
Bruce Korb6047d502000-12-07 01:32:11 +0000926#ifdef __MSDOS__
Daniel Berlin283da1d2000-12-02 19:46:32 +0000927 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
928#else
929 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
930 pz_temp_file, pz_temp_file, pz_temp_file);
931#endif
Bruce Korb62a99402000-08-04 14:16:57 +0000932 }
933 system( pz_cmd );
934 free( (void*)pz_cmd );
935}
936
Bruce Korbbb786201999-06-02 07:08:54 +0000937/* * * * * * * * * * * * *
938
939 This loop should only cycle for 1/2 of one loop.
940 "chain_open" starts a process that uses "read_fd" as
941 its stdin and returns the new fd this process will use
942 for stdout. */
943
Daniel Berlin283da1d2000-12-02 19:46:32 +0000944#else /* is *NOT* SEPARATE_FIX_PROC */
Bruce Korb6864a6c2000-12-02 19:01:16 +0000945static int
Nathanael Nerodef4dbf932003-08-01 23:07:04 +0000946start_fixer (int read_fd, tFixDesc* p_fixd, char* pz_fix_file)
Bruce Korbbb786201999-06-02 07:08:54 +0000947{
Bruce Korbbb786201999-06-02 07:08:54 +0000948 tCC* pz_cmd_save;
949 char* pz_cmd;
950
Bruce Korb5abc1f71999-10-12 14:44:18 +0000951 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
952 return internal_fix (read_fd, p_fixd);
953
Bruce Korbbb786201999-06-02 07:08:54 +0000954 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
James A. Morrison9cdfc8e2004-01-27 19:10:10 +0000955 {
956 pz_cmd = NULL;
957 pz_cmd_save = NULL;
958 }
Bruce Korbbb786201999-06-02 07:08:54 +0000959 else
960 {
961 tSCC z_cmd_fmt[] = "file='%s'\n%s";
Gabriel Dos Reis03a9fcb2005-05-15 18:28:36 +0000962 pz_cmd = XNEWVEC (char, strlen (p_fixd->patch_args[2])
Kaveh R. Ghazic68b0a82003-07-19 16:09:51 +0000963 + sizeof (z_cmd_fmt) + strlen (pz_fix_file));
Bruce Korb5abc1f71999-10-12 14:44:18 +0000964 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
Bruce Korbbb786201999-06-02 07:08:54 +0000965 pz_cmd_save = p_fixd->patch_args[2];
966 p_fixd->patch_args[2] = pz_cmd;
967 }
968
Bruce Korbb35926b1999-11-11 14:57:55 +0000969 /* Start a fix process, handing off the previous read fd for its
970 stdin and getting a new fd that reads from the fix process' stdout.
971 We normally will not loop, but we will up to 10 times if we keep
972 getting "EAGAIN" errors.
973
974 */
Bruce Korbbb786201999-06-02 07:08:54 +0000975 for (;;)
976 {
977 static int failCt = 0;
978 int fd;
979
980 fd = chain_open (read_fd,
Bruce Korb2629a112000-12-13 20:07:46 +0000981 (tCC **) p_fixd->patch_args,
Bruce Korbbb786201999-06-02 07:08:54 +0000982 (process_chain_head == -1)
983 ? &process_chain_head : (pid_t *) NULL);
984
985 if (fd != -1)
986 {
987 read_fd = fd;
988 break;
989 }
990
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000991 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
Bruce Korbbb786201999-06-02 07:08:54 +0000992 p_fixd->fix_name);
993
994 if ((errno != EAGAIN) || (++failCt > 10))
995 exit (EXIT_FAILURE);
996 sleep (1);
997 }
998
Bruce Korbb35926b1999-11-11 14:57:55 +0000999 /* IF we allocated a shell script command,
1000 THEN free it and restore the command format to the fix description */
Bruce Korbbb786201999-06-02 07:08:54 +00001001 if (pz_cmd != (char*)NULL)
1002 {
1003 free ((void*)pz_cmd);
1004 p_fixd->patch_args[2] = pz_cmd_save;
1005 }
1006
1007 return read_fd;
1008}
Bruce Korb62a99402000-08-04 14:16:57 +00001009#endif
Bruce Korbbb786201999-06-02 07:08:54 +00001010
Bruce Korb5abc1f71999-10-12 14:44:18 +00001011
1012/* * * * * * * * * * * * *
Bruce Korb401be4b2007-01-06 18:03:50 +00001013 *
1014 * Process the potential fixes for a particular include file.
1015 * Input: the original text of the file and the file's name
1016 * Result: none. A new file may or may not be created.
1017 */
Bruce Korb6864a6c2000-12-02 19:01:16 +00001018static t_bool
Nathanael Nerodef4dbf932003-08-01 23:07:04 +00001019fix_applies (tFixDesc* p_fixd)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001020{
Zack Weinbergae5c8392000-01-22 20:55:18 +00001021 const char *pz_fname = pz_curr_file;
1022 const char *pz_scan = p_fixd->file_list;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001023 int test_ct;
1024 tTestDesc *p_test;
1025
Bruce Korb401be4b2007-01-06 18:03:50 +00001026#ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +00001027 /*
1028 * There is only one fix that uses a shell script as of this writing.
1029 * I hope to nuke it anyway, it does not apply to DOS and it would
1030 * be painful to implement. Therefore, no "shell" fixes for DOS.
1031 */
1032 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
1033 return BOOL_FALSE;
Bruce Korb401be4b2007-01-06 18:03:50 +00001034#else
Bruce Korb5abc1f71999-10-12 14:44:18 +00001035 if (p_fixd->fd_flags & FD_SKIP_TEST)
1036 return BOOL_FALSE;
Bruce Korb401be4b2007-01-06 18:03:50 +00001037#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001038
1039 /* IF there is a file name restriction,
1040 THEN ensure the current file name matches one in the pattern */
1041
Zack Weinbergae5c8392000-01-22 20:55:18 +00001042 if (pz_scan != (char *) NULL)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001043 {
Bruce Korb5abc1f71999-10-12 14:44:18 +00001044 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1045 pz_fname += 2;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001046
1047 for (;;)
1048 {
Bruce Korb401be4b2007-01-06 18:03:50 +00001049 if (fnmatch (pz_scan, pz_fname, 0) == 0)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001050 break;
Bruce Korb401be4b2007-01-06 18:03:50 +00001051 pz_scan += strlen (pz_scan) + 1;
1052 if (*pz_scan == NUL)
1053 return BOOL_FALSE;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001054 }
1055 }
1056
1057 /* FOR each test, see if it fails.
1058 IF it does fail, then we go on to the next test */
1059
1060 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1061 test_ct-- > 0;
1062 p_test++)
1063 {
1064 switch (p_test->type)
1065 {
1066 case TT_TEST:
Bruce Korbb35926b1999-11-11 14:57:55 +00001067 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1068#ifdef DEBUG
1069 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001070 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1071 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001072#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001073 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001074 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001075 break;
1076
1077 case TT_EGREP:
Bruce Korbb35926b1999-11-11 14:57:55 +00001078 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1079#ifdef DEBUG
1080 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001081 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1082 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001083#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001084 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001085 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001086 break;
1087
1088 case TT_NEGREP:
Bruce Korbb35926b1999-11-11 14:57:55 +00001089 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1090#ifdef DEBUG
1091 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001092 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1093 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001094#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001095 /* Negated sense */
1096 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001097 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001098 break;
1099
1100 case TT_FUNCTION:
1101 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
Bruce Korbb35926b1999-11-11 14:57:55 +00001102 != APPLY_FIX) {
1103#ifdef DEBUG
1104 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001105 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1106 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001107#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001108 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001109 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001110 break;
1111 }
1112 }
1113
1114 return BOOL_TRUE;
1115}
1116
1117
1118/* * * * * * * * * * * * *
1119
1120 Write out a replacement file */
1121
Bruce Korb6864a6c2000-12-02 19:01:16 +00001122static void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +00001123write_replacement (tFixDesc* p_fixd)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001124{
1125 const char* pz_text = p_fixd->patch_args[0];
1126
1127 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1128 return;
1129
1130 {
Bruce Korb6864a6c2000-12-02 19:01:16 +00001131 FILE* out_fp = create_file ();
Bruce Korb66f788b2005-11-25 05:57:10 +00001132 size_t sz = strlen (pz_text);
1133 fwrite (pz_text, sz, 1, out_fp);
1134 if (pz_text[ sz-1 ] != '\n')
1135 fputc ('\n', out_fp);
Bruce Korb5abc1f71999-10-12 14:44:18 +00001136 fclose (out_fp);
1137 }
1138}
1139
1140
1141/* * * * * * * * * * * * *
1142
1143 We have work to do. Read back in the output
1144 of the filtering chain. Compare each byte as we read it with
1145 the contents of the original file. As soon as we find any
1146 difference, we will create the output file, write out all
1147 the matched text and then copy any remaining data from the
1148 output of the filter chain.
1149 */
Bruce Korb6864a6c2000-12-02 19:01:16 +00001150static void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +00001151test_for_changes (int read_fd)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001152{
1153 FILE *in_fp = fdopen (read_fd, "r");
1154 FILE *out_fp = (FILE *) NULL;
Bruce Korb90376ae2001-07-21 04:08:29 +00001155 unsigned char *pz_cmp = (unsigned char*)pz_curr_data;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001156
1157#ifdef DO_STATS
1158 fixed_ct++;
1159#endif
1160 for (;;)
1161 {
1162 int ch;
1163
1164 ch = getc (in_fp);
1165 if (ch == EOF)
1166 break;
Bruce Korb90376ae2001-07-21 04:08:29 +00001167 ch &= 0xFF; /* all bytes are 8 bits */
Bruce Korb5abc1f71999-10-12 14:44:18 +00001168
1169 /* IF we are emitting the output
1170 THEN emit this character, too.
1171 */
1172 if (out_fp != (FILE *) NULL)
1173 putc (ch, out_fp);
1174
1175 /* ELSE if this character does not match the original,
1176 THEN now is the time to start the output.
1177 */
1178 else if (ch != *pz_cmp)
1179 {
Bruce Korb6864a6c2000-12-02 19:01:16 +00001180 out_fp = create_file ();
Bruce Korb5abc1f71999-10-12 14:44:18 +00001181
1182#ifdef DO_STATS
1183 altered_ct++;
1184#endif
1185 /* IF there are matched data, write the matched part now. */
Bruce Korbc8b0c192001-07-21 04:20:08 +00001186 if ((char*)pz_cmp != pz_curr_data)
1187 fwrite (pz_curr_data, (size_t)((char*)pz_cmp - pz_curr_data),
1188 1, out_fp);
Bruce Korb5abc1f71999-10-12 14:44:18 +00001189
1190 /* Emit the current unmatching character */
1191 putc (ch, out_fp);
1192 }
1193 else
1194 /* ELSE the character matches. Advance the compare ptr */
1195 pz_cmp++;
1196 }
1197
1198 /* IF we created the output file, ... */
1199 if (out_fp != (FILE *) NULL)
1200 {
1201 regmatch_t match;
1202
1203 /* Close the file and see if we have to worry about
1204 `#include "file.h"' constructs. */
1205 fclose (out_fp);
Zack Weinbergab747402003-07-08 20:42:19 +00001206 if (xregexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001207 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1208 }
1209
1210 fclose (in_fp);
1211 close (read_fd); /* probably redundant, but I'm paranoid */
1212}
1213
1214
Bruce Korb1f414ac1999-03-03 07:41:52 +00001215/* * * * * * * * * * * * *
1216
1217 Process the potential fixes for a particular include file.
1218 Input: the original text of the file and the file's name
1219 Result: none. A new file may or may not be created. */
1220
Bruce Korb0083c901998-10-16 07:00:18 +00001221void
Nathanael Nerodef4dbf932003-08-01 23:07:04 +00001222process (void)
Bruce Korb0083c901998-10-16 07:00:18 +00001223{
Bruce Korb1f414ac1999-03-03 07:41:52 +00001224 tFixDesc *p_fixd = fixDescList;
1225 int todo_ct = FIX_COUNT;
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +00001226 int read_fd = -1;
Daniel Berlin283da1d2000-12-02 19:46:32 +00001227# ifndef SEPARATE_FIX_PROC
Rainer Orth9f8eec31999-05-17 12:39:19 +00001228 int num_children = 0;
Daniel Berlin283da1d2000-12-02 19:46:32 +00001229# else /* is SEPARATE_FIX_PROC */
Bruce Korb62a99402000-08-04 14:16:57 +00001230 char* pz_file_source = pz_curr_file;
1231# endif
Bruce Korb1f414ac1999-03-03 07:41:52 +00001232
Bruce Korb5abc1f71999-10-12 14:44:18 +00001233 if (access (pz_curr_file, R_OK) != 0)
1234 {
1235 int erno = errno;
1236 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1237 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
Zack Weinbergf95e46b2000-02-27 00:10:15 +00001238 erno, xstrerror (erno));
Bruce Korb5abc1f71999-10-12 14:44:18 +00001239 return;
1240 }
1241
1242 pz_curr_data = load_file (pz_curr_file);
1243 if (pz_curr_data == (char *) NULL)
1244 return;
1245
1246#ifdef DO_STATS
1247 process_ct++;
1248#endif
Zack Weinbergd7eb5a41999-12-17 21:49:30 +00001249 if (VLEVEL( VERB_PROGRESS ) && have_tty)
Richard Henderson1c99d802003-01-21 17:02:51 -08001250 fprintf (stderr, "%6lu %-50s \r",
1251 (unsigned long) data_map_size, pz_curr_file);
Bruce Korb5abc1f71999-10-12 14:44:18 +00001252
Daniel Berlin283da1d2000-12-02 19:46:32 +00001253# ifndef SEPARATE_FIX_PROC
Bruce Korb1f414ac1999-03-03 07:41:52 +00001254 process_chain_head = NOPROCESS;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001255
Bruce Korb1f414ac1999-03-03 07:41:52 +00001256 /* For every fix in our fix list, ... */
1257 for (; todo_ct > 0; p_fixd++, todo_ct--)
Bruce Korb0083c901998-10-16 07:00:18 +00001258 {
Bruce Korb5abc1f71999-10-12 14:44:18 +00001259 if (! fix_applies (p_fixd))
Bruce Korb0083c901998-10-16 07:00:18 +00001260 continue;
1261
Bruce Korbb35926b1999-11-11 14:57:55 +00001262 if (VLEVEL( VERB_APPLIES ))
1263 fprintf (stderr, "Applying %-24s to %s\n",
1264 p_fixd->fix_name, pz_curr_file);
Bruce Korb5abc1f71999-10-12 14:44:18 +00001265
1266 if (p_fixd->fd_flags & FD_REPLACEMENT)
1267 {
1268 write_replacement (p_fixd);
1269 UNLOAD_DATA();
1270 return;
1271 }
Bruce Korb1f414ac1999-03-03 07:41:52 +00001272
1273 /* IF we do not have a read pointer,
1274 THEN this is the first fix for the current file.
1275 Open the source file. That will be used as stdin for
1276 the first fix. Any subsequent fixes will use the
Bruce Korb5abc1f71999-10-12 14:44:18 +00001277 stdout descriptor of the previous fix for its stdin. */
Bruce Korb1f414ac1999-03-03 07:41:52 +00001278
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +00001279 if (read_fd == -1)
Bruce Korb0083c901998-10-16 07:00:18 +00001280 {
Bruce Korb5abc1f71999-10-12 14:44:18 +00001281 read_fd = open (pz_curr_file, O_RDONLY);
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +00001282 if (read_fd < 0)
Bruce Korb0083c901998-10-16 07:00:18 +00001283 {
Bruce Korb1f414ac1999-03-03 07:41:52 +00001284 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
Zack Weinbergf95e46b2000-02-27 00:10:15 +00001285 xstrerror (errno), pz_curr_file);
Bruce Korb1f414ac1999-03-03 07:41:52 +00001286 exit (EXIT_FAILURE);
Bruce Korb0083c901998-10-16 07:00:18 +00001287 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001288
1289 /* Ensure we do not get duplicate output */
1290
1291 fflush (stdout);
Bruce Korb0083c901998-10-16 07:00:18 +00001292 }
1293
Bruce Korb5abc1f71999-10-12 14:44:18 +00001294 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
Bruce Korbbb786201999-06-02 07:08:54 +00001295 num_children++;
Bruce Korb0083c901998-10-16 07:00:18 +00001296 }
1297
Bruce Korb5abc1f71999-10-12 14:44:18 +00001298 /* IF we have a read-back file descriptor,
1299 THEN check for changes and write output if changed. */
Bruce Korb1f414ac1999-03-03 07:41:52 +00001300
Bruce Korb5abc1f71999-10-12 14:44:18 +00001301 if (read_fd >= 0)
1302 {
1303 test_for_changes (read_fd);
1304#ifdef DO_STATS
1305 apply_ct += num_children;
1306#endif
1307 /* Wait for child processes created by chain_open()
1308 to avoid leaving zombies. */
1309 do {
1310 wait ((int *) NULL);
1311 } while (--num_children > 0);
1312 }
Bruce Korb0083c901998-10-16 07:00:18 +00001313
Daniel Berlin283da1d2000-12-02 19:46:32 +00001314# else /* is SEPARATE_FIX_PROC */
Bruce Korb62a99402000-08-04 14:16:57 +00001315
1316 for (; todo_ct > 0; p_fixd++, todo_ct--)
1317 {
1318 if (! fix_applies (p_fixd))
1319 continue;
1320
1321 if (VLEVEL( VERB_APPLIES ))
1322 fprintf (stderr, "Applying %-24s to %s\n",
1323 p_fixd->fix_name, pz_curr_file);
1324
1325 if (p_fixd->fd_flags & FD_REPLACEMENT)
1326 {
1327 write_replacement (p_fixd);
1328 UNLOAD_DATA();
1329 return;
1330 }
1331 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
1332 pz_file_source = pz_temp_file;
1333 }
1334
Daniel Berlin283da1d2000-12-02 19:46:32 +00001335 read_fd = open (pz_temp_file, O_RDONLY);
1336 if (read_fd < 0)
1337 {
Bruce Korbca21b4a2001-02-06 22:19:50 +00001338 if (errno != ENOENT)
1339 fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
1340 errno, xstrerror (errno), pz_temp_file);
Daniel Berlin283da1d2000-12-02 19:46:32 +00001341 }
1342 else
1343 {
1344 test_for_changes (read_fd);
1345 /* Unlinking a file while it is still open is a Bad Idea on
1346 DOS/Windows. */
1347 close (read_fd);
1348 unlink (pz_temp_file);
1349 }
Bruce Korb62a99402000-08-04 14:16:57 +00001350
1351# endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001352 UNLOAD_DATA();
Bruce Korb0083c901998-10-16 07:00:18 +00001353}