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