blob: 88fffbd2bd69224c6feddd66a47d8fded07c6d3c [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
3 directory that GNU C will search.
4
Jeff Law3852e8a2000-02-26 13:02:01 -07005 Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
Bruce Korb1f414ac1999-03-03 07:41:52 +00006
7This file is part of GNU CC.
8
9GNU CC is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
13
14GNU CC is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU CC; see the file COPYING. If not, write to
21the Free Software Foundation, 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA. */
23
Bruce Korb5abc1f71999-10-12 14:44:18 +000024#include "fixlib.h"
Bruce Korb1f414ac1999-03-03 07:41:52 +000025
Bruce Korb1e570a62000-09-05 22:28:04 +000026#if defined( HAVE_MMAP_FILE )
Philippe De Muyter99d525c1999-11-01 19:14:50 +010027#include <sys/mman.h>
28#define BAD_ADDR ((void*)-1)
29#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +000030
Bruce Korb0083c901998-10-16 07:00:18 +000031#include <signal.h>
Daniel Berlin283da1d2000-12-02 19:46:32 +000032#ifndef SEPARATE_FIX_PROC
Bruce Korb0083c901998-10-16 07:00:18 +000033#include "server.h"
Bruce Korb62a99402000-08-04 14:16:57 +000034#endif
Bruce Korb0083c901998-10-16 07:00:18 +000035
Bruce Korb5abc1f71999-10-12 14:44:18 +000036/* The contents of this string are not very important. It is mostly
37 just used as part of the "I am alive and working" test. */
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +000038
Bruce Korb5abc1f71999-10-12 14:44:18 +000039static const char program_id[] = "fixincl version 1.1";
Bruce Korb0083c901998-10-16 07:00:18 +000040
Bruce Korbe02ecf32000-07-19 14:10:41 +000041/* This format will be used at the start of every generated file */
42
43static const char z_std_preamble[] =
44"/* DO NOT EDIT THIS FILE.\n\n\
45 It has been auto-edited by fixincludes from:\n\n\
46\t\"%s/%s\"\n\n\
47 This had to be done to correct non-standard usages in the\n\
48 original, manufacturer supplied header file. */\n\n";
49
Bruce Korb1f414ac1999-03-03 07:41:52 +000050/* Working environment strings. Essentially, invocation 'options'. */
Bruce Korbe02ecf32000-07-19 14:10:41 +000051
52#define _ENV_(v,m,n,t) tCC* v = NULL;
53ENV_TABLE
54#undef _ENV_
55
Bruce Korb7d9ccd91999-03-31 11:51:29 +000056int find_base_len = 0;
Bruce Korb0083c901998-10-16 07:00:18 +000057
Bruce Korbb35926b1999-11-11 14:57:55 +000058typedef enum {
59 VERB_SILENT = 0,
60 VERB_FIXES,
61 VERB_APPLIES,
62 VERB_PROGRESS,
63 VERB_TESTS,
64 VERB_EVERYTHING
65} te_verbose;
66
67te_verbose verbose_level = VERB_PROGRESS;
Zack Weinbergd7eb5a41999-12-17 21:49:30 +000068int have_tty = 0;
Bruce Korbb35926b1999-11-11 14:57:55 +000069
John David Anglindbbbbf32001-03-02 21:41:37 +000070#define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
Bruce Korbb35926b1999-11-11 14:57:55 +000071#define NOT_SILENT VLEVEL(VERB_FIXES)
72
Bruce Korb1f414ac1999-03-03 07:41:52 +000073pid_t process_chain_head = (pid_t) -1;
Bruce Korb0083c901998-10-16 07:00:18 +000074
Bruce Korb5abc1f71999-10-12 14:44:18 +000075char* pz_curr_file; /* name of the current file under test/fix */
76char* pz_curr_data; /* original contents of that file */
Bruce Korb62a99402000-08-04 14:16:57 +000077char* pz_temp_file; /* for DOS, a place to stash the temporary
78 fixed data between system(3) calls */
Bruce Korb5abc1f71999-10-12 14:44:18 +000079t_bool curr_data_mapped;
80int data_map_fd;
81size_t data_map_size;
82size_t ttl_data_size = 0;
Bruce Korbe02ecf32000-07-19 14:10:41 +000083
Bruce Korb5abc1f71999-10-12 14:44:18 +000084#ifdef DO_STATS
85int process_ct = 0;
86int apply_ct = 0;
87int fixed_ct = 0;
88int altered_ct = 0;
89#endif /* DO_STATS */
90
Bruce Korb1f414ac1999-03-03 07:41:52 +000091const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
Bruce Korb5abc1f71999-10-12 14:44:18 +000092tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
Bruce Korb1f414ac1999-03-03 07:41:52 +000093regex_t incl_quote_re;
Bruce Korb0083c901998-10-16 07:00:18 +000094
Bruce Korb6864a6c2000-12-02 19:01:16 +000095static void do_version PARAMS((void)) ATTRIBUTE_NORETURN;
Bruce Korb3af556f2000-09-12 14:28:55 +000096char *load_file PARAMS((const char *));
97void run_compiles PARAMS((void));
98void initialize PARAMS((int argc,char** argv));
99void process PARAMS((void));
Bruce Korb5abc1f71999-10-12 14:44:18 +0000100
101/* External Source Code */
Bruce Korb0083c901998-10-16 07:00:18 +0000102
103#include "fixincl.x"
104
Bruce Korb1f414ac1999-03-03 07:41:52 +0000105/* * * * * * * * * * * * * * * * * * *
106 *
107 * MAIN ROUTINE
108 */
Bruce Korb6864a6c2000-12-02 19:01:16 +0000109extern int main PARAMS ((int, char **));
Bruce Korb0083c901998-10-16 07:00:18 +0000110int
111main (argc, argv)
112 int argc;
113 char **argv;
114{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000115 char *file_name_buf;
Bruce Korb0083c901998-10-16 07:00:18 +0000116
Bruce Korb35dfe412000-05-11 13:41:12 +0000117 initialize ( argc, argv );
Bruce Korbd1c6a031999-04-26 10:38:38 +0000118
Zack Weinbergd7eb5a41999-12-17 21:49:30 +0000119 have_tty = isatty (fileno (stderr));
120
Bruce Korb5abc1f71999-10-12 14:44:18 +0000121 /* Before anything else, ensure we can allocate our file name buffer. */
122 file_name_buf = load_file_data (stdin);
123
124 /* Because of the way server shells work, you have to keep stdin, out
125 and err open so that the proper input file does not get closed
126 by accident */
127
128 freopen ("/dev/null", "r", stdin);
129
130 if (file_name_buf == (char *) NULL)
131 {
132 fputs ("No file names listed for fixing\n", stderr);
133 exit (EXIT_FAILURE);
134 }
135
Bruce Korbd1c6a031999-04-26 10:38:38 +0000136 for (;;)
137 {
Bruce Korb5abc1f71999-10-12 14:44:18 +0000138 char* pz_end;
Bruce Korbd1c6a031999-04-26 10:38:38 +0000139
Bruce Korb5abc1f71999-10-12 14:44:18 +0000140 /* skip to start of name, past any "./" prefixes */
Bruce Korbd1c6a031999-04-26 10:38:38 +0000141
Bruce Korb5abc1f71999-10-12 14:44:18 +0000142 while (ISSPACE (*file_name_buf)) file_name_buf++;
143 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
144 file_name_buf += 2;
Bruce Korbd1c6a031999-04-26 10:38:38 +0000145
Bruce Korb5abc1f71999-10-12 14:44:18 +0000146 /* Check for end of list */
Bruce Korbd1c6a031999-04-26 10:38:38 +0000147
Bruce Korb5abc1f71999-10-12 14:44:18 +0000148 if (*file_name_buf == NUL)
149 break;
150
151 /* Set global file name pointer and find end of name */
152
153 pz_curr_file = file_name_buf;
154 pz_end = strchr( pz_curr_file, '\n' );
155 if (pz_end == (char*)NULL)
156 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
157 else
158 file_name_buf = pz_end + 1;
159
160 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
161
162 /* IF no name is found (blank line) or comment marker, skip line */
163
164 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
165 continue;
166 *pz_end = NUL;
167
Bruce Korb5abc1f71999-10-12 14:44:18 +0000168 process ();
Bruce Korb5abc1f71999-10-12 14:44:18 +0000169 } /* for (;;) */
Bruce Korbd1c6a031999-04-26 10:38:38 +0000170
Bruce Korb5abc1f71999-10-12 14:44:18 +0000171#ifdef DO_STATS
Bruce Korbb35926b1999-11-11 14:57:55 +0000172 if (VLEVEL( VERB_PROGRESS )) {
Bruce Korb5abc1f71999-10-12 14:44:18 +0000173 tSCC zFmt[] =
174 "\
175Processed %5d files containing %d bytes \n\
176Applying %5d fixes to %d files\n\
177Altering %5d of them\n";
Bruce Korbd1c6a031999-04-26 10:38:38 +0000178
Bruce Korb5abc1f71999-10-12 14:44:18 +0000179 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
180 fixed_ct, altered_ct);
181 }
182#endif /* DO_STATS */
Bruce Korb62a99402000-08-04 14:16:57 +0000183
Daniel Berlin283da1d2000-12-02 19:46:32 +0000184# ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +0000185 unlink( pz_temp_file );
186# endif
Bruce Korb15fe1a72001-01-05 16:28:58 +0000187 exit (EXIT_SUCCESS);
Bruce Korbd1c6a031999-04-26 10:38:38 +0000188}
189
190
Bruce Korb6864a6c2000-12-02 19:01:16 +0000191static void
Bruce Korb5abc1f71999-10-12 14:44:18 +0000192do_version ()
193{
194 static const char zFmt[] = "echo '%s'";
195 char zBuf[ 1024 ];
196
197 /* The 'version' option is really used to test that:
198 1. The program loads correctly (no missing libraries)
Bruce Korb35dfe412000-05-11 13:41:12 +0000199 2. that we can compile all the regular expressions.
200 3. we can correctly run our server shell process
Bruce Korb5abc1f71999-10-12 14:44:18 +0000201 */
202 run_compiles ();
203 sprintf (zBuf, zFmt, program_id);
Daniel Berlin283da1d2000-12-02 19:46:32 +0000204#ifndef SEPARATE_FIX_PROC
Bruce Korb6b151aa2000-05-04 14:55:00 +0000205 puts (zBuf + 5);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000206 exit (strcmp (run_shell (zBuf), program_id));
Bruce Korb62a99402000-08-04 14:16:57 +0000207#else
208 exit (system (zBuf));
209#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +0000210}
211
Bruce Korbd1c6a031999-04-26 10:38:38 +0000212/* * * * * * * * * * * * */
213
214void
Bruce Korb35dfe412000-05-11 13:41:12 +0000215initialize ( argc, argv )
216 int argc;
217 char** argv;
Bruce Korbd1c6a031999-04-26 10:38:38 +0000218{
219 static const char var_not_found[] =
Bruce Korbe02ecf32000-07-19 14:10:41 +0000220 "fixincl ERROR: %s environment variable not defined\n"
221#ifdef __STDC__
222 "each of these must be defined:\n"
223#define _ENV_(v,m,n,t) "\t" n " - " t "\n"
224ENV_TABLE
225#undef _ENV_
226#endif
227 ;
Bruce Korbd1c6a031999-04-26 10:38:38 +0000228
Bruce Korb878a5792000-07-12 14:45:05 +0000229 xmalloc_set_program_name (argv[0]);
230
Bruce Korb35dfe412000-05-11 13:41:12 +0000231 switch (argc)
232 {
233 case 1:
234 break;
235
236 case 2:
237 if (strcmp (argv[1], "-v") == 0)
238 do_version ();
239 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
240 {
241 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
242 errno, xstrerror (errno), argv[1] );
243 exit (EXIT_FAILURE);
244 }
245 break;
246
247 default:
248 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
249 exit (EXIT_FAILURE);
250 }
251
Bruce Korbe02ecf32000-07-19 14:10:41 +0000252#define _ENV_(v,m,n,t) { tSCC var[] = n; \
253 v = getenv (var); if (m && (v == NULL)) { \
254 fprintf (stderr, var_not_found, var); \
255 exit (EXIT_FAILURE); } }
Bruce Korb0083c901998-10-16 07:00:18 +0000256
Bruce Korbe02ecf32000-07-19 14:10:41 +0000257ENV_TABLE
Bruce Korb0083c901998-10-16 07:00:18 +0000258
Bruce Korbe02ecf32000-07-19 14:10:41 +0000259#undef _ENV_
Bruce Korb0083c901998-10-16 07:00:18 +0000260
Bruce Korb6864a6c2000-12-02 19:01:16 +0000261 if (ISDIGIT ( *pz_verbose ))
Bruce Korbe02ecf32000-07-19 14:10:41 +0000262 verbose_level = (te_verbose)atoi( pz_verbose );
263 else
264 switch (*pz_verbose) {
265 case 's':
266 case 'S':
267 verbose_level = VERB_SILENT; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000268
Bruce Korbe02ecf32000-07-19 14:10:41 +0000269 case 'f':
270 case 'F':
271 verbose_level = VERB_FIXES; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000272
Bruce Korbe02ecf32000-07-19 14:10:41 +0000273 case 'a':
274 case 'A':
275 verbose_level = VERB_APPLIES; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000276
Bruce Korbe02ecf32000-07-19 14:10:41 +0000277 case 'p':
278 case 'P':
279 verbose_level = VERB_PROGRESS; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000280
Bruce Korbe02ecf32000-07-19 14:10:41 +0000281 case 't':
282 case 'T':
283 verbose_level = VERB_TESTS; break;
Bruce Korbb35926b1999-11-11 14:57:55 +0000284
Bruce Korbe02ecf32000-07-19 14:10:41 +0000285 case 'e':
286 case 'E':
287 verbose_level = VERB_EVERYTHING; break;
288 }
Bruce Korbb35926b1999-11-11 14:57:55 +0000289
Bruce Korbe02ecf32000-07-19 14:10:41 +0000290 while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
291 pz_find_base += 2;
292 if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
293 find_base_len = strlen( pz_find_base );
Bruce Korb7d9ccd91999-03-31 11:51:29 +0000294
Bruce Korb1f414ac1999-03-03 07:41:52 +0000295 /* Compile all the regular expressions now.
296 That way, it is done only once for the whole run.
297 */
298 run_compiles ();
Bruce Korb0083c901998-10-16 07:00:18 +0000299
Daniel Berlin283da1d2000-12-02 19:46:32 +0000300# ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +0000301 /* NULL as the first argument to `tempnam' causes it to DTRT
302 wrt the temporary directory where the file will be created. */
303 pz_temp_file = tempnam( NULL, "fxinc" );
304# endif
305
Bruce Korb1f414ac1999-03-03 07:41:52 +0000306 signal (SIGQUIT, SIG_IGN);
Bruce Korb35dfe412000-05-11 13:41:12 +0000307#ifdef SIGIOT
Bruce Korb1f414ac1999-03-03 07:41:52 +0000308 signal (SIGIOT, SIG_IGN);
Bruce Korb35dfe412000-05-11 13:41:12 +0000309#endif
Bruce Korb62a99402000-08-04 14:16:57 +0000310#ifdef SIGPIPE
Bruce Korb1f414ac1999-03-03 07:41:52 +0000311 signal (SIGPIPE, SIG_IGN);
Bruce Korb62a99402000-08-04 14:16:57 +0000312#endif
Bruce Korb1f414ac1999-03-03 07:41:52 +0000313 signal (SIGALRM, SIG_IGN);
314 signal (SIGTERM, SIG_IGN);
Bruce Korbd1c6a031999-04-26 10:38:38 +0000315}
Bruce Korb0083c901998-10-16 07:00:18 +0000316
Bruce Korb1f414ac1999-03-03 07:41:52 +0000317/* * * * * * * * * * * * *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000318
Bruce Korb1f414ac1999-03-03 07:41:52 +0000319 load_file loads all the contents of a file into malloc-ed memory.
320 Its argument is the name of the file to read in; the returned
321 result is the NUL terminated contents of the file. The file
322 is presumed to be an ASCII text file containing no NULs. */
Bruce Korb0083c901998-10-16 07:00:18 +0000323char *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000324load_file ( fname )
325 const char* fname;
Bruce Korb0083c901998-10-16 07:00:18 +0000326{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000327 struct stat stbf;
328 char* res;
Bruce Korb0083c901998-10-16 07:00:18 +0000329
Bruce Korb5abc1f71999-10-12 14:44:18 +0000330 if (stat (fname, &stbf) != 0)
Bruce Korb0083c901998-10-16 07:00:18 +0000331 {
Bruce Korbb35926b1999-11-11 14:57:55 +0000332 if (NOT_SILENT)
333 fprintf (stderr, "error %d (%s) stat-ing %s\n",
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000334 errno, xstrerror (errno), fname );
Bruce Korb5abc1f71999-10-12 14:44:18 +0000335 return (char *) NULL;
336 }
337 if (stbf.st_size == 0)
338 return (char*)NULL;
339
Bruce Korba6efbec2000-09-05 18:29:56 +0000340 /* Make the data map size one larger than the file size for documentation
341 purposes. Truth is that there will be a following NUL character if
342 the file size is not a multiple of the page size. If it is a multiple,
343 then this adjustment sometimes fails anyway. */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000344 data_map_size = stbf.st_size+1;
345 data_map_fd = open (fname, O_RDONLY);
346 ttl_data_size += data_map_size-1;
347
348 if (data_map_fd < 0)
349 {
Bruce Korbb35926b1999-11-11 14:57:55 +0000350 if (NOT_SILENT)
351 fprintf (stderr, "error %d (%s) opening %s for read\n",
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000352 errno, xstrerror (errno), fname);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000353 return (char*)NULL;
Bruce Korb0083c901998-10-16 07:00:18 +0000354 }
355
Zack Weinberg56f02b82000-04-17 17:25:57 +0000356#ifdef HAVE_MMAP_FILE
Bruce Korb5abc1f71999-10-12 14:44:18 +0000357 curr_data_mapped = BOOL_TRUE;
Bruce Korba6efbec2000-09-05 18:29:56 +0000358
359 /* IF the file size is a multiple of the page size,
360 THEN sometimes you will seg fault trying to access a trailing byte */
Bruce Korbdc465052000-09-05 22:26:16 +0000361 if ((stbf.st_size & (getpagesize()-1)) == 0)
Bruce Korba6efbec2000-09-05 18:29:56 +0000362 res = (char*)BAD_ADDR;
363 else
364 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
365 MAP_PRIVATE, data_map_fd, 0);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000366 if (res == (char*)BAD_ADDR)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000367#endif
Bruce Korbca21b4a2001-02-06 22:19:50 +0000368 {
369 FILE* fp = fdopen (data_map_fd, "r");
370 curr_data_mapped = BOOL_FALSE;
371 res = load_file_data (fp);
372 fclose (fp);
373 }
Bruce Korb0083c901998-10-16 07:00:18 +0000374
Bruce Korb5abc1f71999-10-12 14:44:18 +0000375 return res;
Bruce Korb0083c901998-10-16 07:00:18 +0000376}
377
Bruce Korb6864a6c2000-12-02 19:01:16 +0000378static int machine_matches PARAMS ((tFixDesc *));
379static int
Bruce Korb62a99402000-08-04 14:16:57 +0000380machine_matches( p_fixd )
381 tFixDesc *p_fixd;
Bruce Korb0083c901998-10-16 07:00:18 +0000382 {
Daniel Berlin283da1d2000-12-02 19:46:32 +0000383# ifndef SEPARATE_FIX_PROC
Bruce Korb5abc1f71999-10-12 14:44:18 +0000384 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
Philippe De Muyter99d525c1999-11-01 19:14:50 +0100385 tSCC esac_fmt[] =
386 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000387 tSCC skip[] = "skip"; /* 4 bytes */
388 tSCC run[] = "run"; /* 3 bytes */
389 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
390
Bruce Korb1f414ac1999-03-03 07:41:52 +0000391 const char **papz_machs = p_fixd->papz_machs;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000392 char *pz;
Bruce Korb6864a6c2000-12-02 19:01:16 +0000393 const char *pz_sep = "";
Bruce Korb1f414ac1999-03-03 07:41:52 +0000394 tCC *pz_if_true;
395 tCC *pz_if_false;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000396 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
Bruce Korb1f414ac1999-03-03 07:41:52 +0000397
Bruce Korb5abc1f71999-10-12 14:44:18 +0000398 /* Start the case statement */
Bruce Korb1f414ac1999-03-03 07:41:52 +0000399
Bruce Korb5abc1f71999-10-12 14:44:18 +0000400 sprintf (cmd_buf, case_fmt, pz_machine);
401 pz = cmd_buf + strlen (cmd_buf);
Bruce Korb1f414ac1999-03-03 07:41:52 +0000402
Bruce Korb5abc1f71999-10-12 14:44:18 +0000403 /* Determine if a match means to apply the fix or not apply it */
Bruce Korb1f414ac1999-03-03 07:41:52 +0000404
405 if (p_fixd->fd_flags & FD_MACH_IFNOT)
406 {
407 pz_if_true = skip;
408 pz_if_false = run;
409 }
410 else
411 {
412 pz_if_true = run;
413 pz_if_false = skip;
414 }
415
Bruce Korb5abc1f71999-10-12 14:44:18 +0000416 /* Emit all the machine names. If there are more than one,
417 then we will insert " | \\\n" between the names */
Bruce Korb1f414ac1999-03-03 07:41:52 +0000418
419 for (;;)
420 {
421 const char* pz_mach = *(papz_machs++);
422
423 if (pz_mach == (const char*) NULL)
424 break;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000425 sprintf (pz, "%s%s", pz_sep, pz_mach);
Bruce Korb1f414ac1999-03-03 07:41:52 +0000426 pz += strlen (pz);
427 pz_sep = " | \\\n";
428 }
Bruce Korb5abc1f71999-10-12 14:44:18 +0000429
430 /* Now emit the match and not-match actions and the esac */
431
432 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
Bruce Korb1f414ac1999-03-03 07:41:52 +0000433
434 /* Run the script.
435 The result will start either with 's' or 'r'. */
436
Rainer Orth7d032a41999-05-07 11:09:31 +0000437 {
438 int skip;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000439 pz = run_shell (cmd_buf);
Rainer Orth7d032a41999-05-07 11:09:31 +0000440 skip = (*pz == 's');
441 free ( (void*)pz );
442 if (skip)
443 {
444 p_fixd->fd_flags |= FD_SKIP_TEST;
Bruce Korb62a99402000-08-04 14:16:57 +0000445 return BOOL_FALSE;
446 }
447 }
448
449 return BOOL_TRUE;
Daniel Berlin283da1d2000-12-02 19:46:32 +0000450# else /* is SEPARATE_FIX_PROC */
Bruce Korb62a99402000-08-04 14:16:57 +0000451 const char **papz_machs = p_fixd->papz_machs;
452 int invert = (p_fixd->fd_flags & FD_MACH_IFNOT) != 0;
453 for (;;)
454 {
455 const char* pz_mach = *(papz_machs++);
456
457 if (pz_mach == (const char*) NULL)
458 break;
459 if (strstr (pz_mach, "dos") != NULL && !invert)
460 return BOOL_TRUE;
461 }
462
463 p_fixd->fd_flags |= FD_SKIP_TEST;
464 return BOOL_FALSE;
465# endif
466}
467
468/* * * * * * * * * * * * *
469
470 run_compiles run all the regexp compiles for all the fixes once.
471 */
472void
473run_compiles ()
474{
475 tFixDesc *p_fixd = fixDescList;
476 int fix_ct = FIX_COUNT;
Kaveh R. Ghazidd3b81b2000-11-17 04:16:55 +0000477 regex_t *p_re = (regex_t *) xmalloc (REGEX_COUNT * sizeof (regex_t));
Bruce Korb62a99402000-08-04 14:16:57 +0000478
479 /* Make sure compile_re does not stumble across invalid data */
480
481 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
482 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
483
484 compile_re (incl_quote_pat, &incl_quote_re, 1,
485 "quoted include", "run_compiles");
486
487 /* Allow machine name tests to be ignored (testing, mainly) */
488
489 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
490 pz_machine = (char*)NULL;
491
492 /* FOR every fixup, ... */
493 do
494 {
495 tTestDesc *p_test = p_fixd->p_test_desc;
496 int test_ct = p_fixd->test_ct;
497
498 /* IF the machine type pointer is not NULL (we are not in test mode)
499 AND this test is for or not done on particular machines
500 THEN ... */
501
502 if ( (pz_machine != NULL)
503 && (p_fixd->papz_machs != (const char**) NULL)
504 && ! machine_matches (p_fixd) )
505 continue;
Bruce Korb1f414ac1999-03-03 07:41:52 +0000506
507 /* FOR every test for the fixup, ... */
508
509 while (--test_ct >= 0)
510 {
511 switch (p_test->type)
Bruce Korb0083c901998-10-16 07:00:18 +0000512 {
513 case TT_EGREP:
514 case TT_NEGREP:
Bruce Korb1f414ac1999-03-03 07:41:52 +0000515 p_test->p_test_regex = p_re++;
Bruce Korb35dfe412000-05-11 13:41:12 +0000516 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
517 "select test", p_fixd->fix_name);
Bruce Korb3af556f2000-09-12 14:28:55 +0000518 default: break;
Bruce Korb35dfe412000-05-11 13:41:12 +0000519 }
Bruce Korb1f414ac1999-03-03 07:41:52 +0000520 p_test++;
Bruce Korb0083c901998-10-16 07:00:18 +0000521 }
522 }
Bruce Korb1f414ac1999-03-03 07:41:52 +0000523 while (p_fixd++, --fix_ct > 0);
Bruce Korb0083c901998-10-16 07:00:18 +0000524}
525
526
Bruce Korb1f414ac1999-03-03 07:41:52 +0000527/* * * * * * * * * * * * *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000528
Bruce Korb1f414ac1999-03-03 07:41:52 +0000529 create_file Create the output modified file.
530 Input: the name of the file to create
531 Returns: a file pointer to the new, open file */
532
Bruce Korb063174e1999-11-04 14:50:44 +0000533#if defined(S_IRUSR) && defined(S_IWUSR) && \
534 defined(S_IRGRP) && defined(S_IROTH)
535
536# define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
537#else
538# define S_IRALL 0644
539#endif
540
541#if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
542 defined(S_IROTH) && defined(S_IXOTH)
543
544# define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
545#else
546# define S_DIRALL 0755
547#endif
548
Bruce Korb1f414ac1999-03-03 07:41:52 +0000549
Bruce Korb6864a6c2000-12-02 19:01:16 +0000550static FILE *create_file PARAMS ((void));
551static FILE *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000552create_file ()
Bruce Korb0083c901998-10-16 07:00:18 +0000553{
554 int fd;
555 FILE *pf;
556 char fname[MAXPATHLEN];
557
Bruce Korb5abc1f71999-10-12 14:44:18 +0000558 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
Bruce Korb0083c901998-10-16 07:00:18 +0000559
Bruce Korb1f414ac1999-03-03 07:41:52 +0000560 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
Bruce Korb0083c901998-10-16 07:00:18 +0000561
Bruce Korb1f414ac1999-03-03 07:41:52 +0000562 /* We may need to create the directories needed... */
Bruce Korb0083c901998-10-16 07:00:18 +0000563 if ((fd < 0) && (errno == ENOENT))
564 {
Bruce Korb1f414ac1999-03-03 07:41:52 +0000565 char *pz_dir = strchr (fname + 1, '/');
Bruce Korb0083c901998-10-16 07:00:18 +0000566 struct stat stbf;
567
Bruce Korb1f414ac1999-03-03 07:41:52 +0000568 while (pz_dir != (char *) NULL)
Bruce Korb0083c901998-10-16 07:00:18 +0000569 {
Bruce Korb1f414ac1999-03-03 07:41:52 +0000570 *pz_dir = NUL;
Bruce Korb0083c901998-10-16 07:00:18 +0000571 if (stat (fname, &stbf) < 0)
572 {
Bruce Korb063174e1999-11-04 14:50:44 +0000573 mkdir (fname, S_IFDIR | S_DIRALL);
Bruce Korb0083c901998-10-16 07:00:18 +0000574 }
575
Bruce Korb1f414ac1999-03-03 07:41:52 +0000576 *pz_dir = '/';
577 pz_dir = strchr (pz_dir + 1, '/');
Bruce Korb0083c901998-10-16 07:00:18 +0000578 }
Bruce Korb1f414ac1999-03-03 07:41:52 +0000579
580 /* Now, lets try the open again... */
581 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
Bruce Korb0083c901998-10-16 07:00:18 +0000582 }
583 if (fd < 0)
584 {
585 fprintf (stderr, "Error %d (%s) creating %s\n",
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000586 errno, xstrerror (errno), fname);
Bruce Korb0083c901998-10-16 07:00:18 +0000587 exit (EXIT_FAILURE);
588 }
Bruce Korbb35926b1999-11-11 14:57:55 +0000589 if (NOT_SILENT)
590 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
Bruce Korb0083c901998-10-16 07:00:18 +0000591 pf = fdopen (fd, "w");
592
Bruce Korbe02ecf32000-07-19 14:10:41 +0000593 /*
594 * IF pz_machine is NULL, then we are in some sort of test mode.
595 * Do not insert the current directory name. Use a constant string.
596 */
597 fprintf (pf, z_std_preamble,
598 (pz_machine == NULL)
599 ? "fixinc/tests/inc"
600 : pz_input_dir,
601 pz_curr_file);
Bruce Korb0083c901998-10-16 07:00:18 +0000602
Bruce Korb0083c901998-10-16 07:00:18 +0000603 return pf;
604}
605
Bruce Korb1f414ac1999-03-03 07:41:52 +0000606
607/* * * * * * * * * * * * *
608
609 test_test make sure a shell-style test expression passes.
610 Input: a pointer to the descriptor of the test to run and
611 the name of the file that we might want to fix
Bruce Korb5abc1f71999-10-12 14:44:18 +0000612 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
Bruce Korb1f414ac1999-03-03 07:41:52 +0000613 shell script we run. */
Daniel Berlin283da1d2000-12-02 19:46:32 +0000614#ifndef SEPARATE_FIX_PROC
Bruce Korb6864a6c2000-12-02 19:01:16 +0000615static int test_test PARAMS ((tTestDesc *, char *));
616static int
Bruce Korb5abc1f71999-10-12 14:44:18 +0000617test_test (p_test, pz_test_file)
Bruce Korb1f414ac1999-03-03 07:41:52 +0000618 tTestDesc *p_test;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000619 char* pz_test_file;
Bruce Korb0083c901998-10-16 07:00:18 +0000620{
Bruce Korb94db2f71999-05-12 07:32:58 +0000621 tSCC cmd_fmt[] =
622"file=%s\n\
623if ( test %s ) > /dev/null 2>&1\n\
624then echo TRUE\n\
625else echo FALSE\n\
626fi";
627
Bruce Korb1f414ac1999-03-03 07:41:52 +0000628 char *pz_res;
Bruce Korbe9099382000-05-17 14:56:13 +0000629 int res;
Bruce Korb0083c901998-10-16 07:00:18 +0000630
Bruce Korb1f414ac1999-03-03 07:41:52 +0000631 static char cmd_buf[4096];
Bruce Korb0083c901998-10-16 07:00:18 +0000632
Bruce Korb5abc1f71999-10-12 14:44:18 +0000633 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
Bruce Korb1f414ac1999-03-03 07:41:52 +0000634 pz_res = run_shell (cmd_buf);
Bruce Korbe9099382000-05-17 14:56:13 +0000635
636 switch (*pz_res) {
637 case 'T':
Bruce Korb5abc1f71999-10-12 14:44:18 +0000638 res = APPLY_FIX;
Bruce Korbe9099382000-05-17 14:56:13 +0000639 break;
640
641 case 'F':
642 res = SKIP_FIX;
643 break;
644
645 default:
646 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
647 pz_res, cmd_buf );
648 }
649
Bruce Korb1f414ac1999-03-03 07:41:52 +0000650 free ((void *) pz_res);
Bruce Korb0083c901998-10-16 07:00:18 +0000651 return res;
652}
Bruce Korb62a99402000-08-04 14:16:57 +0000653#else
654/*
655 * IF we are in MS-DOS land, then whatever shell-type test is required
656 * will, by definition, fail
657 */
658#define test_test(t,tf) SKIP_FIX
659#endif
Bruce Korb0083c901998-10-16 07:00:18 +0000660
Bruce Korb1f414ac1999-03-03 07:41:52 +0000661/* * * * * * * * * * * * *
Bruce Korb5abc1f71999-10-12 14:44:18 +0000662
Bruce Korb1f414ac1999-03-03 07:41:52 +0000663 egrep_test make sure an egrep expression is found in the file text.
664 Input: a pointer to the descriptor of the test to run and
665 the pointer to the contents of the file under suspicion
Bruce Korb5abc1f71999-10-12 14:44:18 +0000666 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
Bruce Korb1f414ac1999-03-03 07:41:52 +0000667
Bruce Korb5abc1f71999-10-12 14:44:18 +0000668 The caller may choose to reverse meaning if the sense of the test
Bruce Korb1f414ac1999-03-03 07:41:52 +0000669 is inverted. */
670
Bruce Korb6864a6c2000-12-02 19:01:16 +0000671static int egrep_test PARAMS ((char *, tTestDesc *));
672static int
Bruce Korb1f414ac1999-03-03 07:41:52 +0000673egrep_test (pz_data, p_test)
674 char *pz_data;
675 tTestDesc *p_test;
Bruce Korb0083c901998-10-16 07:00:18 +0000676{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000677#ifdef DEBUG
Bruce Korb1f414ac1999-03-03 07:41:52 +0000678 if (p_test->p_test_regex == 0)
679 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
680 p_test->pz_test_text);
Bruce Korb0083c901998-10-16 07:00:18 +0000681#endif
Zack Weinbergb51207a2000-01-17 21:45:29 +0000682 if (regexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000683 return APPLY_FIX;
684 return SKIP_FIX;
Bruce Korb0083c901998-10-16 07:00:18 +0000685}
686
687
Bruce Korb1f414ac1999-03-03 07:41:52 +0000688/* * * * * * * * * * * * *
Bruce Korb94db2f71999-05-12 07:32:58 +0000689
690 quoted_file_exists Make sure that a file exists before we emit
691 the file name. If we emit the name, our invoking shell will try
692 to copy a non-existing file into the destination directory. */
693
Bruce Korb6864a6c2000-12-02 19:01:16 +0000694static int quoted_file_exists PARAMS ((const char *, const char *, const char *));
695static int
Bruce Korb94db2f71999-05-12 07:32:58 +0000696quoted_file_exists (pz_src_path, pz_file_path, pz_file)
Bruce Korb6864a6c2000-12-02 19:01:16 +0000697 const char *pz_src_path;
698 const char *pz_file_path;
699 const char *pz_file;
Bruce Korb94db2f71999-05-12 07:32:58 +0000700{
701 char z[ MAXPATHLEN ];
702 char* pz;
703 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
704 pz = z + strlen ( z );
705
706 for (;;) {
707 char ch = *pz_file++;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000708 if (! ISGRAPH( ch ))
Bruce Korb94db2f71999-05-12 07:32:58 +0000709 return 0;
710 if (ch == '"')
711 break;
712 *pz++ = ch;
713 }
714 *pz = '\0';
715 {
716 struct stat s;
717 if (stat (z, &s) != 0)
718 return 0;
719 return S_ISREG( s.st_mode );
720 }
721}
722
723
724/* * * * * * * * * * * * *
Bruce Korb1f414ac1999-03-03 07:41:52 +0000725 *
726 extract_quoted_files
Bruce Korb5abc1f71999-10-12 14:44:18 +0000727
Bruce Korb1f414ac1999-03-03 07:41:52 +0000728 The syntax, `#include "file.h"' specifies that the compiler is to
729 search the local directory of the current file before the include
730 list. Consequently, if we have modified a header and stored it in
731 another directory, any files that are included by that modified
732 file in that fashion must also be copied into this new directory.
733 This routine finds those flavors of #include and for each one found
734 emits a triple of:
Bruce Korb5abc1f71999-10-12 14:44:18 +0000735
Bruce Korb1f414ac1999-03-03 07:41:52 +0000736 1. source directory of the original file
737 2. the relative path file name of the #includ-ed file
738 3. the full destination path for this file
739
740 Input: the text of the file, the file name and a pointer to the
741 match list where the match information was stored.
742 Result: internally nothing. The results are written to stdout
743 for interpretation by the invoking shell */
Bruce Korb0083c901998-10-16 07:00:18 +0000744
Bruce Korb94db2f71999-05-12 07:32:58 +0000745
Bruce Korb6864a6c2000-12-02 19:01:16 +0000746static void extract_quoted_files PARAMS ((char *, const char *, regmatch_t *));
747static void
Bruce Korb5abc1f71999-10-12 14:44:18 +0000748extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
Bruce Korb1f414ac1999-03-03 07:41:52 +0000749 char *pz_data;
Bruce Korb5abc1f71999-10-12 14:44:18 +0000750 const char *pz_fixed_file;
Bruce Korb1f414ac1999-03-03 07:41:52 +0000751 regmatch_t *p_re_match;
Bruce Korb0083c901998-10-16 07:00:18 +0000752{
Bruce Korb5abc1f71999-10-12 14:44:18 +0000753 char *pz_dir_end = strrchr (pz_fixed_file, '/');
Bruce Korb1f414ac1999-03-03 07:41:52 +0000754 char *pz_incl_quot = pz_data;
Bruce Korb0083c901998-10-16 07:00:18 +0000755
Bruce Korbb35926b1999-11-11 14:57:55 +0000756 if (VLEVEL( VERB_APPLIES ))
757 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
Bruce Korb0083c901998-10-16 07:00:18 +0000758
Bruce Korb5abc1f71999-10-12 14:44:18 +0000759 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
Bruce Korb94db2f71999-05-12 07:32:58 +0000760 If there is none, then it is in our current directory, ".". */
Bruce Korb1f414ac1999-03-03 07:41:52 +0000761
762 if (pz_dir_end == (char *) NULL)
Bruce Korb5abc1f71999-10-12 14:44:18 +0000763 pz_fixed_file = ".";
Bruce Korb0083c901998-10-16 07:00:18 +0000764 else
Bruce Korb1f414ac1999-03-03 07:41:52 +0000765 *pz_dir_end = '\0';
Bruce Korb0083c901998-10-16 07:00:18 +0000766
767 for (;;)
768 {
Bruce Korb1f414ac1999-03-03 07:41:52 +0000769 pz_incl_quot += p_re_match->rm_so;
Bruce Korb0083c901998-10-16 07:00:18 +0000770
Bruce Korb1f414ac1999-03-03 07:41:52 +0000771 /* Skip forward to the included file name */
Zack Weinbergf6bbde22000-12-08 03:00:26 +0000772 while (*pz_incl_quot != '"')
Bruce Korb1f414ac1999-03-03 07:41:52 +0000773 pz_incl_quot++;
Bruce Korb0083c901998-10-16 07:00:18 +0000774
Bruce Korb5abc1f71999-10-12 14:44:18 +0000775 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
Bruce Korb94db2f71999-05-12 07:32:58 +0000776 {
777 /* Print the source directory and the subdirectory
778 of the file in question. */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000779 printf ("%s %s/", pz_src_dir, pz_fixed_file);
Bruce Korb94db2f71999-05-12 07:32:58 +0000780 pz_dir_end = pz_incl_quot;
Bruce Korb0083c901998-10-16 07:00:18 +0000781
Bruce Korb94db2f71999-05-12 07:32:58 +0000782 /* Append to the directory the relative path of the desired file */
783 while (*pz_incl_quot != '"')
784 putc (*pz_incl_quot++, stdout);
Bruce Korb0083c901998-10-16 07:00:18 +0000785
Bruce Korb94db2f71999-05-12 07:32:58 +0000786 /* Now print the destination directory appended with the
787 relative path of the desired file */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000788 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
Bruce Korb94db2f71999-05-12 07:32:58 +0000789 while (*pz_dir_end != '"')
790 putc (*pz_dir_end++, stdout);
Bruce Korb0083c901998-10-16 07:00:18 +0000791
Bruce Korb94db2f71999-05-12 07:32:58 +0000792 /* End of entry */
793 putc ('\n', stdout);
794 }
Bruce Korb0083c901998-10-16 07:00:18 +0000795
Bruce Korb1f414ac1999-03-03 07:41:52 +0000796 /* Find the next entry */
797 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
Bruce Korb0083c901998-10-16 07:00:18 +0000798 break;
799 }
800}
801
802
Bruce Korb5abc1f71999-10-12 14:44:18 +0000803/* * * * * * * * * * * * *
804
805 Somebody wrote a *_fix subroutine that we must call.
806 */
Daniel Berlin283da1d2000-12-02 19:46:32 +0000807#ifndef SEPARATE_FIX_PROC
Bruce Korb6864a6c2000-12-02 19:01:16 +0000808static int internal_fix PARAMS ((int, tFixDesc *));
809static int
Bruce Korb5abc1f71999-10-12 14:44:18 +0000810internal_fix (read_fd, p_fixd)
811 int read_fd;
812 tFixDesc* p_fixd;
813{
814 int fd[2];
815
816 if (pipe( fd ) != 0)
817 {
818 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
819 exit (EXIT_FAILURE);
820 }
821
822 for (;;)
823 {
824 pid_t childid = fork();
825
826 switch (childid)
827 {
828 case -1:
829 break;
830
831 case 0:
832 close (fd[0]);
833 goto do_child_task;
834
835 default:
836 /*
837 * Parent process
838 */
839 close (read_fd);
840 close (fd[1]);
841 return fd[0];
842 }
843
844 /*
845 * Parent in error
846 */
Zack Weinbergf95e46b2000-02-27 00:10:15 +0000847 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
Bruce Korb5abc1f71999-10-12 14:44:18 +0000848 p_fixd->fix_name);
849 {
850 static int failCt = 0;
851 if ((errno != EAGAIN) || (++failCt > 10))
852 exit (EXIT_FAILURE);
853 sleep (1);
854 }
855 } do_child_task:;
856
857 /*
858 * Close our current stdin and stdout
859 */
860 close (STDIN_FILENO);
861 close (STDOUT_FILENO);
862 UNLOAD_DATA();
863
864 /*
865 * Make the fd passed in the stdin, and the write end of
866 * the new pipe become the stdout.
867 */
868 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
869 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000870
Bruce Korb35dfe412000-05-11 13:41:12 +0000871 apply_fix (p_fixd, pz_curr_file);
Bruce Korb5abc1f71999-10-12 14:44:18 +0000872 exit (0);
873}
Daniel Berlin283da1d2000-12-02 19:46:32 +0000874#endif /* !SEPARATE_FIX_PROC */
Bruce Korb5abc1f71999-10-12 14:44:18 +0000875
Bruce Korbbb786201999-06-02 07:08:54 +0000876
Daniel Berlin283da1d2000-12-02 19:46:32 +0000877#ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +0000878static void
879fix_with_system (p_fixd, pz_fix_file, pz_file_source, pz_temp_file)
880 tFixDesc* p_fixd;
881 tCC* pz_fix_file;
882 tCC* pz_file_source;
883 tCC* pz_temp_file;
884{
885 char* pz_cmd;
886 char* pz_scan;
887 size_t argsize;
888
889 if (p_fixd->fd_flags & FD_SUBROUTINE)
890 {
891 tSCC z_applyfix_prog[] = "/fixinc/applyfix";
892
893 argsize = 32
894 + strlen( pz_orig_dir )
895 + sizeof( z_applyfix_prog )
896 + strlen( pz_fix_file )
897 + strlen( pz_file_source )
898 + strlen( pz_temp_file );
899
900 pz_cmd = (char*)xmalloc( argsize );
901
902 strcpy( pz_cmd, pz_orig_dir );
903 pz_scan = pz_cmd + strlen( pz_orig_dir );
904 strcpy( pz_scan, z_applyfix_prog );
905 pz_scan += sizeof( z_applyfix_prog ) - 1;
906 *(pz_scan++) = ' ';
907
908 /*
909 * Now add the fix number and file names that may be needed
910 */
911 sprintf (pz_scan, "%ld %s %s %s", p_fixd - fixDescList,
912 pz_fix_file, pz_file_source, pz_temp_file);
913 }
914 else /* NOT an "internal" fix: */
915 {
916 size_t parg_size;
Daniel Berlin283da1d2000-12-02 19:46:32 +0000917#ifdef __MSDOS__
Bruce Korb62a99402000-08-04 14:16:57 +0000918 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
Daniel Berlin283da1d2000-12-02 19:46:32 +0000919 dst is a temporary file anyway, so we know there's no other
920 file by that name; and DOS's system(3) doesn't mind to
Eli Zaretskiidc13bad2000-08-21 19:28:18 +0300921 clobber existing file in redirection. Besides, with DOS 8+3
922 limited file namespace, we can easily lose if dst already has
923 an extension that is 3 or more characters long.
Daniel Berlin283da1d2000-12-02 19:46:32 +0000924
925 I do not think the 8+3 issue is relevant because all the files
926 we operate on are named "*.h", making 8+2 adequate. Anyway,
927 the following bizarre use of 'cat' only works on DOS boxes.
928 It causes the file to be dropped into a temporary file for
Eli Zaretskiidc13bad2000-08-21 19:28:18 +0300929 'cat' to read (pipes do not work on DOS). */
930 tSCC z_cmd_fmt[] = " %s | cat > %s";
Daniel Berlin283da1d2000-12-02 19:46:32 +0000931#else
932 /* Don't use positional formatting arguments because some lame-o
933 implementations cannot cope :-(. */
934 tSCC z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
935#endif
Bruce Korb62a99402000-08-04 14:16:57 +0000936 tCC** ppArgs = p_fixd->patch_args;
937
938 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
939 + strlen( pz_file_source );
940 parg_size = argsize;
941
942
943 /*
944 * Compute the size of the command line. Add lotsa extra space
945 * because some of the args to sed use lotsa single quotes.
946 * (This requires three extra bytes per quote. Here we allow
947 * for up to 8 single quotes for each argument, including the
948 * command name "sed" itself. Nobody will *ever* need more. :)
949 */
950 for (;;)
951 {
952 tCC* p_arg = *(ppArgs++);
953 if (p_arg == NULL)
954 break;
955 argsize += 24 + strlen( p_arg );
956 }
957
958 /* Estimated buffer size we will need. */
959 pz_scan = pz_cmd = (char*)xmalloc( argsize );
960 /* How much of it do we allot to the program name and its
961 arguments. */
962 parg_size = argsize - parg_size;
963
964 ppArgs = p_fixd->patch_args;
965
966 /*
967 * Copy the program name, unquoted
968 */
969 {
970 tCC* pArg = *(ppArgs++);
971 for (;;)
972 {
973 char ch = *(pArg++);
974 if (ch == NUL)
975 break;
976 *(pz_scan++) = ch;
977 }
978 }
979
980 /*
981 * Copy the program arguments, quoted
982 */
983 for (;;)
984 {
985 tCC* pArg = *(ppArgs++);
986 char* pz_scan_save;
987 if (pArg == NULL)
988 break;
989 *(pz_scan++) = ' ';
990 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
991 parg_size - (pz_scan - pz_cmd) );
992 /*
993 * Make sure we don't overflow the buffer due to sloppy
994 * size estimation.
995 */
996 while (pz_scan == (char*)NULL)
997 {
998 size_t already_filled = pz_scan_save - pz_cmd;
999 pz_cmd = (char*)xrealloc( pz_cmd, argsize += 100 );
1000 pz_scan_save = pz_scan = pz_cmd + already_filled;
1001 parg_size += 100;
1002 pz_scan = make_raw_shell_str( pz_scan, pArg,
1003 parg_size - (pz_scan - pz_cmd) );
1004 }
1005 }
1006
1007 /*
1008 * add the file machinations.
1009 */
Bruce Korb6047d502000-12-07 01:32:11 +00001010#ifdef __MSDOS__
Daniel Berlin283da1d2000-12-02 19:46:32 +00001011 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
1012#else
1013 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
1014 pz_temp_file, pz_temp_file, pz_temp_file);
1015#endif
Bruce Korb62a99402000-08-04 14:16:57 +00001016 }
1017 system( pz_cmd );
1018 free( (void*)pz_cmd );
1019}
1020
Bruce Korbbb786201999-06-02 07:08:54 +00001021/* * * * * * * * * * * * *
1022
1023 This loop should only cycle for 1/2 of one loop.
1024 "chain_open" starts a process that uses "read_fd" as
1025 its stdin and returns the new fd this process will use
1026 for stdout. */
1027
Daniel Berlin283da1d2000-12-02 19:46:32 +00001028#else /* is *NOT* SEPARATE_FIX_PROC */
Bruce Korb6864a6c2000-12-02 19:01:16 +00001029static int start_fixer PARAMS ((int, tFixDesc *, char *));
1030static int
Bruce Korb5abc1f71999-10-12 14:44:18 +00001031start_fixer (read_fd, p_fixd, pz_fix_file)
Bruce Korbbb786201999-06-02 07:08:54 +00001032 int read_fd;
1033 tFixDesc* p_fixd;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001034 char* pz_fix_file;
Bruce Korbbb786201999-06-02 07:08:54 +00001035{
Bruce Korbbb786201999-06-02 07:08:54 +00001036 tCC* pz_cmd_save;
1037 char* pz_cmd;
1038
Bruce Korb5abc1f71999-10-12 14:44:18 +00001039 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1040 return internal_fix (read_fd, p_fixd);
1041
Bruce Korbbb786201999-06-02 07:08:54 +00001042 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1043 pz_cmd = (char*)NULL;
1044 else
1045 {
1046 tSCC z_cmd_fmt[] = "file='%s'\n%s";
Kaveh R. Ghazidd3b81b2000-11-17 04:16:55 +00001047 pz_cmd = (char*) xmalloc (strlen (p_fixd->patch_args[2])
1048 + sizeof( z_cmd_fmt )
1049 + strlen( pz_fix_file ));
Bruce Korb5abc1f71999-10-12 14:44:18 +00001050 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
Bruce Korbbb786201999-06-02 07:08:54 +00001051 pz_cmd_save = p_fixd->patch_args[2];
1052 p_fixd->patch_args[2] = pz_cmd;
1053 }
1054
Bruce Korbb35926b1999-11-11 14:57:55 +00001055 /* Start a fix process, handing off the previous read fd for its
1056 stdin and getting a new fd that reads from the fix process' stdout.
1057 We normally will not loop, but we will up to 10 times if we keep
1058 getting "EAGAIN" errors.
1059
1060 */
Bruce Korbbb786201999-06-02 07:08:54 +00001061 for (;;)
1062 {
1063 static int failCt = 0;
1064 int fd;
1065
1066 fd = chain_open (read_fd,
Bruce Korb2629a112000-12-13 20:07:46 +00001067 (tCC **) p_fixd->patch_args,
Bruce Korbbb786201999-06-02 07:08:54 +00001068 (process_chain_head == -1)
1069 ? &process_chain_head : (pid_t *) NULL);
1070
1071 if (fd != -1)
1072 {
1073 read_fd = fd;
1074 break;
1075 }
1076
Zack Weinbergf95e46b2000-02-27 00:10:15 +00001077 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
Bruce Korbbb786201999-06-02 07:08:54 +00001078 p_fixd->fix_name);
1079
1080 if ((errno != EAGAIN) || (++failCt > 10))
1081 exit (EXIT_FAILURE);
1082 sleep (1);
1083 }
1084
Bruce Korbb35926b1999-11-11 14:57:55 +00001085 /* IF we allocated a shell script command,
1086 THEN free it and restore the command format to the fix description */
Bruce Korbbb786201999-06-02 07:08:54 +00001087 if (pz_cmd != (char*)NULL)
1088 {
1089 free ((void*)pz_cmd);
1090 p_fixd->patch_args[2] = pz_cmd_save;
1091 }
1092
1093 return read_fd;
1094}
Bruce Korb62a99402000-08-04 14:16:57 +00001095#endif
Bruce Korbbb786201999-06-02 07:08:54 +00001096
Bruce Korb5abc1f71999-10-12 14:44:18 +00001097
1098/* * * * * * * * * * * * *
1099
1100 Process the potential fixes for a particular include file.
1101 Input: the original text of the file and the file's name
1102 Result: none. A new file may or may not be created. */
1103
Bruce Korb6864a6c2000-12-02 19:01:16 +00001104static t_bool fix_applies PARAMS ((tFixDesc *));
1105static t_bool
Bruce Korb5abc1f71999-10-12 14:44:18 +00001106fix_applies (p_fixd)
1107 tFixDesc *p_fixd;
1108{
Zack Weinbergae5c8392000-01-22 20:55:18 +00001109 const char *pz_fname = pz_curr_file;
1110 const char *pz_scan = p_fixd->file_list;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001111 int test_ct;
1112 tTestDesc *p_test;
1113
Daniel Berlin283da1d2000-12-02 19:46:32 +00001114# ifdef SEPARATE_FIX_PROC
Bruce Korb62a99402000-08-04 14:16:57 +00001115 /*
1116 * There is only one fix that uses a shell script as of this writing.
1117 * I hope to nuke it anyway, it does not apply to DOS and it would
1118 * be painful to implement. Therefore, no "shell" fixes for DOS.
1119 */
1120 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
1121 return BOOL_FALSE;
1122# else
Bruce Korb5abc1f71999-10-12 14:44:18 +00001123 if (p_fixd->fd_flags & FD_SKIP_TEST)
1124 return BOOL_FALSE;
Bruce Korb62a99402000-08-04 14:16:57 +00001125# endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001126
1127 /* IF there is a file name restriction,
1128 THEN ensure the current file name matches one in the pattern */
1129
Zack Weinbergae5c8392000-01-22 20:55:18 +00001130 if (pz_scan != (char *) NULL)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001131 {
Bruce Korb5abc1f71999-10-12 14:44:18 +00001132 size_t name_len;
1133
1134 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1135 pz_fname += 2;
1136 name_len = strlen (pz_fname);
1137
1138 for (;;)
1139 {
1140 pz_scan = strstr (pz_scan + 1, pz_fname);
1141 /* IF we can't match the string at all,
1142 THEN bail */
Bruce Korb62a99402000-08-04 14:16:57 +00001143 if (pz_scan == (char *) NULL)
Bruce Korb5abc1f71999-10-12 14:44:18 +00001144 return BOOL_FALSE;
1145
1146 /* IF the match is surrounded by the '|' markers,
1147 THEN we found a full match -- time to run the tests */
1148
1149 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1150 break;
1151 }
1152 }
1153
1154 /* FOR each test, see if it fails.
1155 IF it does fail, then we go on to the next test */
1156
1157 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1158 test_ct-- > 0;
1159 p_test++)
1160 {
1161 switch (p_test->type)
1162 {
1163 case TT_TEST:
Bruce Korbb35926b1999-11-11 14:57:55 +00001164 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1165#ifdef DEBUG
1166 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001167 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1168 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001169#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001170 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001171 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001172 break;
1173
1174 case TT_EGREP:
Bruce Korbb35926b1999-11-11 14:57:55 +00001175 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1176#ifdef DEBUG
1177 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001178 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1179 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001180#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001181 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001182 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001183 break;
1184
1185 case TT_NEGREP:
Bruce Korbb35926b1999-11-11 14:57:55 +00001186 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1187#ifdef DEBUG
1188 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001189 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1190 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001191#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001192 /* Negated sense */
1193 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001194 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001195 break;
1196
1197 case TT_FUNCTION:
1198 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
Bruce Korbb35926b1999-11-11 14:57:55 +00001199 != APPLY_FIX) {
1200#ifdef DEBUG
1201 if (VLEVEL( VERB_EVERYTHING ))
Bruce Korbe9099382000-05-17 14:56:13 +00001202 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1203 pz_fname, p_fixd->test_ct - test_ct);
Bruce Korbb35926b1999-11-11 14:57:55 +00001204#endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001205 return BOOL_FALSE;
Bruce Korbb35926b1999-11-11 14:57:55 +00001206 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001207 break;
1208 }
1209 }
1210
1211 return BOOL_TRUE;
1212}
1213
1214
1215/* * * * * * * * * * * * *
1216
1217 Write out a replacement file */
1218
Bruce Korb6864a6c2000-12-02 19:01:16 +00001219static void write_replacement PARAMS ((tFixDesc *));
1220static void
Bruce Korb5abc1f71999-10-12 14:44:18 +00001221write_replacement (p_fixd)
1222 tFixDesc *p_fixd;
1223{
1224 const char* pz_text = p_fixd->patch_args[0];
1225
1226 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1227 return;
1228
1229 {
Bruce Korb6864a6c2000-12-02 19:01:16 +00001230 FILE* out_fp = create_file ();
Bruce Korb5abc1f71999-10-12 14:44:18 +00001231 fputs (pz_text, out_fp);
1232 fclose (out_fp);
1233 }
1234}
1235
1236
1237/* * * * * * * * * * * * *
1238
1239 We have work to do. Read back in the output
1240 of the filtering chain. Compare each byte as we read it with
1241 the contents of the original file. As soon as we find any
1242 difference, we will create the output file, write out all
1243 the matched text and then copy any remaining data from the
1244 output of the filter chain.
1245 */
Bruce Korb6864a6c2000-12-02 19:01:16 +00001246static void test_for_changes PARAMS ((int));
1247static void
Bruce Korb5abc1f71999-10-12 14:44:18 +00001248test_for_changes (read_fd)
1249 int read_fd;
1250{
1251 FILE *in_fp = fdopen (read_fd, "r");
1252 FILE *out_fp = (FILE *) NULL;
1253 char *pz_cmp = pz_curr_data;
1254
1255#ifdef DO_STATS
1256 fixed_ct++;
1257#endif
1258 for (;;)
1259 {
1260 int ch;
1261
1262 ch = getc (in_fp);
1263 if (ch == EOF)
1264 break;
1265
1266 /* IF we are emitting the output
1267 THEN emit this character, too.
1268 */
1269 if (out_fp != (FILE *) NULL)
1270 putc (ch, out_fp);
1271
1272 /* ELSE if this character does not match the original,
1273 THEN now is the time to start the output.
1274 */
1275 else if (ch != *pz_cmp)
1276 {
Bruce Korb6864a6c2000-12-02 19:01:16 +00001277 out_fp = create_file ();
Bruce Korb5abc1f71999-10-12 14:44:18 +00001278
1279#ifdef DO_STATS
1280 altered_ct++;
1281#endif
1282 /* IF there are matched data, write the matched part now. */
1283 if (pz_cmp != pz_curr_data)
1284 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1285
1286 /* Emit the current unmatching character */
1287 putc (ch, out_fp);
1288 }
1289 else
1290 /* ELSE the character matches. Advance the compare ptr */
1291 pz_cmp++;
1292 }
1293
1294 /* IF we created the output file, ... */
1295 if (out_fp != (FILE *) NULL)
1296 {
1297 regmatch_t match;
1298
1299 /* Close the file and see if we have to worry about
1300 `#include "file.h"' constructs. */
1301 fclose (out_fp);
1302 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1303 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1304 }
1305
1306 fclose (in_fp);
1307 close (read_fd); /* probably redundant, but I'm paranoid */
1308}
1309
1310
Bruce Korb1f414ac1999-03-03 07:41:52 +00001311/* * * * * * * * * * * * *
1312
1313 Process the potential fixes for a particular include file.
1314 Input: the original text of the file and the file's name
1315 Result: none. A new file may or may not be created. */
1316
Bruce Korb0083c901998-10-16 07:00:18 +00001317void
Bruce Korb5abc1f71999-10-12 14:44:18 +00001318process ()
Bruce Korb0083c901998-10-16 07:00:18 +00001319{
Bruce Korb1f414ac1999-03-03 07:41:52 +00001320 tFixDesc *p_fixd = fixDescList;
1321 int todo_ct = FIX_COUNT;
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +00001322 int read_fd = -1;
Daniel Berlin283da1d2000-12-02 19:46:32 +00001323# ifndef SEPARATE_FIX_PROC
Rainer Orth9f8eec31999-05-17 12:39:19 +00001324 int num_children = 0;
Daniel Berlin283da1d2000-12-02 19:46:32 +00001325# else /* is SEPARATE_FIX_PROC */
Bruce Korb62a99402000-08-04 14:16:57 +00001326 char* pz_file_source = pz_curr_file;
1327# endif
Bruce Korb1f414ac1999-03-03 07:41:52 +00001328
Bruce Korb5abc1f71999-10-12 14:44:18 +00001329 if (access (pz_curr_file, R_OK) != 0)
1330 {
1331 int erno = errno;
1332 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1333 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
Zack Weinbergf95e46b2000-02-27 00:10:15 +00001334 erno, xstrerror (erno));
Bruce Korb5abc1f71999-10-12 14:44:18 +00001335 return;
1336 }
1337
1338 pz_curr_data = load_file (pz_curr_file);
1339 if (pz_curr_data == (char *) NULL)
1340 return;
1341
1342#ifdef DO_STATS
1343 process_ct++;
1344#endif
Zack Weinbergd7eb5a41999-12-17 21:49:30 +00001345 if (VLEVEL( VERB_PROGRESS ) && have_tty)
Bruce Korbb35926b1999-11-11 14:57:55 +00001346 fprintf (stderr, "%6d %-50s \r", data_map_size, pz_curr_file );
Bruce Korb5abc1f71999-10-12 14:44:18 +00001347
Daniel Berlin283da1d2000-12-02 19:46:32 +00001348# ifndef SEPARATE_FIX_PROC
Bruce Korb1f414ac1999-03-03 07:41:52 +00001349 process_chain_head = NOPROCESS;
Bruce Korb5abc1f71999-10-12 14:44:18 +00001350
Bruce Korb1f414ac1999-03-03 07:41:52 +00001351 /* For every fix in our fix list, ... */
1352 for (; todo_ct > 0; p_fixd++, todo_ct--)
Bruce Korb0083c901998-10-16 07:00:18 +00001353 {
Bruce Korb5abc1f71999-10-12 14:44:18 +00001354 if (! fix_applies (p_fixd))
Bruce Korb0083c901998-10-16 07:00:18 +00001355 continue;
1356
Bruce Korbb35926b1999-11-11 14:57:55 +00001357 if (VLEVEL( VERB_APPLIES ))
1358 fprintf (stderr, "Applying %-24s to %s\n",
1359 p_fixd->fix_name, pz_curr_file);
Bruce Korb5abc1f71999-10-12 14:44:18 +00001360
1361 if (p_fixd->fd_flags & FD_REPLACEMENT)
1362 {
1363 write_replacement (p_fixd);
1364 UNLOAD_DATA();
1365 return;
1366 }
Bruce Korb1f414ac1999-03-03 07:41:52 +00001367
1368 /* IF we do not have a read pointer,
1369 THEN this is the first fix for the current file.
1370 Open the source file. That will be used as stdin for
1371 the first fix. Any subsequent fixes will use the
Bruce Korb5abc1f71999-10-12 14:44:18 +00001372 stdout descriptor of the previous fix for its stdin. */
Bruce Korb1f414ac1999-03-03 07:41:52 +00001373
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +00001374 if (read_fd == -1)
Bruce Korb0083c901998-10-16 07:00:18 +00001375 {
Bruce Korb5abc1f71999-10-12 14:44:18 +00001376 read_fd = open (pz_curr_file, O_RDONLY);
Alexandre Oliva48ac9ce1999-05-20 07:10:41 +00001377 if (read_fd < 0)
Bruce Korb0083c901998-10-16 07:00:18 +00001378 {
Bruce Korb1f414ac1999-03-03 07:41:52 +00001379 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
Zack Weinbergf95e46b2000-02-27 00:10:15 +00001380 xstrerror (errno), pz_curr_file);
Bruce Korb1f414ac1999-03-03 07:41:52 +00001381 exit (EXIT_FAILURE);
Bruce Korb0083c901998-10-16 07:00:18 +00001382 }
Bruce Korb5abc1f71999-10-12 14:44:18 +00001383
1384 /* Ensure we do not get duplicate output */
1385
1386 fflush (stdout);
Bruce Korb0083c901998-10-16 07:00:18 +00001387 }
1388
Bruce Korb5abc1f71999-10-12 14:44:18 +00001389 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
Bruce Korbbb786201999-06-02 07:08:54 +00001390 num_children++;
Bruce Korb0083c901998-10-16 07:00:18 +00001391 }
1392
Bruce Korb5abc1f71999-10-12 14:44:18 +00001393 /* IF we have a read-back file descriptor,
1394 THEN check for changes and write output if changed. */
Bruce Korb1f414ac1999-03-03 07:41:52 +00001395
Bruce Korb5abc1f71999-10-12 14:44:18 +00001396 if (read_fd >= 0)
1397 {
1398 test_for_changes (read_fd);
1399#ifdef DO_STATS
1400 apply_ct += num_children;
1401#endif
1402 /* Wait for child processes created by chain_open()
1403 to avoid leaving zombies. */
1404 do {
1405 wait ((int *) NULL);
1406 } while (--num_children > 0);
1407 }
Bruce Korb0083c901998-10-16 07:00:18 +00001408
Daniel Berlin283da1d2000-12-02 19:46:32 +00001409# else /* is SEPARATE_FIX_PROC */
Bruce Korb62a99402000-08-04 14:16:57 +00001410
1411 for (; todo_ct > 0; p_fixd++, todo_ct--)
1412 {
1413 if (! fix_applies (p_fixd))
1414 continue;
1415
1416 if (VLEVEL( VERB_APPLIES ))
1417 fprintf (stderr, "Applying %-24s to %s\n",
1418 p_fixd->fix_name, pz_curr_file);
1419
1420 if (p_fixd->fd_flags & FD_REPLACEMENT)
1421 {
1422 write_replacement (p_fixd);
1423 UNLOAD_DATA();
1424 return;
1425 }
1426 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
1427 pz_file_source = pz_temp_file;
1428 }
1429
Daniel Berlin283da1d2000-12-02 19:46:32 +00001430 read_fd = open (pz_temp_file, O_RDONLY);
1431 if (read_fd < 0)
1432 {
Bruce Korbca21b4a2001-02-06 22:19:50 +00001433 if (errno != ENOENT)
1434 fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
1435 errno, xstrerror (errno), pz_temp_file);
Daniel Berlin283da1d2000-12-02 19:46:32 +00001436 }
1437 else
1438 {
1439 test_for_changes (read_fd);
1440 /* Unlinking a file while it is still open is a Bad Idea on
1441 DOS/Windows. */
1442 close (read_fd);
1443 unlink (pz_temp_file);
1444 }
Bruce Korb62a99402000-08-04 14:16:57 +00001445
1446# endif
Bruce Korb5abc1f71999-10-12 14:44:18 +00001447 UNLOAD_DATA();
Bruce Korb0083c901998-10-16 07:00:18 +00001448}