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