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