]> gcc.gnu.org Git - gcc.git/blame - gcc/fixinc/fixincl.c
c-parse.in (string action): Do not warn about ANSI string concatenation in system...
[gcc.git] / gcc / fixinc / fixincl.c
CommitLineData
0083c904 1
1f414ac4
BK
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
6 Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
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
5abc1f74
BK
25#include "fixlib.h"
26
99d525c9
PDM
27#if HAVE_MMAP
28#include <sys/mman.h>
29#define BAD_ADDR ((void*)-1)
30#endif
1f414ac4 31
0083c904 32#include <signal.h>
0083c904 33
0083c904
BK
34#include "server.h"
35
5abc1f74 36/* Quality Assurance Marker :-)
1f414ac4 37
5abc1f74
BK
38 Any file that contains this string is presumed to have
39 been carefully constructed and will not be fixed */
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
1f414ac4 46/* Test Descriptor
0083c904 47
1f414ac4
BK
48 Each fix may have associated tests that determine
49 whether the fix needs to be applied or not.
50 Each test has a type (from the te_test_type enumeration);
51 associated test text; and, if the test is TT_EGREP or
52 the negated form TT_NEGREP, a pointer to the compiled
53 version of the text string.
54
55 */
0083c904 56typedef enum
1f414ac4 57{
5abc1f74 58 TT_TEST, TT_EGREP, TT_NEGREP, TT_FUNCTION
1f414ac4 59} te_test_type;
0083c904
BK
60
61typedef struct test_desc tTestDesc;
62
63struct test_desc
1f414ac4
BK
64{
65 te_test_type type;
66 const char *pz_test_text;
67 regex_t *p_test_regex;
68};
0083c904
BK
69
70typedef struct patch_desc tPatchDesc;
71
1f414ac4
BK
72/* Fix Descriptor
73
74 Everything you ever wanted to know about how to apply
75 a particular fix (which files, how to qualify them,
76 how to actually make the fix, etc...)
77
5abc1f74
BK
78 NB: the FD_ defines are BIT FLAGS
79
1f414ac4 80 */
0083c904
BK
81#define FD_MACH_ONLY 0x0000
82#define FD_MACH_IFNOT 0x0001
bb786201 83#define FD_SHELL_SCRIPT 0x0002
5abc1f74
BK
84#define FD_SUBROUTINE 0x0004
85#define FD_REPLACEMENT 0x0008
0083c904
BK
86#define FD_SKIP_TEST 0x8000
87
88typedef struct fix_desc tFixDesc;
89struct fix_desc
1f414ac4
BK
90{
91 const char* fix_name; /* Name of the fix */
92 const char* file_list; /* List of files it applies to */
93 const char** papz_machs; /* List of machine/os-es it applies to */
94 regex_t* unused;
95 int test_ct;
96 int fd_flags;
97 tTestDesc* p_test_desc;
98 const char** patch_args;
99};
100
101/* Working environment strings. Essentially, invocation 'options'. */
102char *pz_dest_dir = NULL;
103char *pz_src_dir = NULL;
104char *pz_machine = NULL;
7d9ccd90 105int find_base_len = 0;
1f414ac4 106
b35926b9
BK
107typedef enum {
108 VERB_SILENT = 0,
109 VERB_FIXES,
110 VERB_APPLIES,
111 VERB_PROGRESS,
112 VERB_TESTS,
113 VERB_EVERYTHING
114} te_verbose;
115
116te_verbose verbose_level = VERB_PROGRESS;
117
118#define VLEVEL(l) (verbose_level >= l)
119#define NOT_SILENT VLEVEL(VERB_FIXES)
120
1f414ac4
BK
121pid_t process_chain_head = (pid_t) -1;
122
5abc1f74
BK
123char* pz_curr_file; /* name of the current file under test/fix */
124char* pz_curr_data; /* original contents of that file */
125t_bool curr_data_mapped;
126int data_map_fd;
127size_t data_map_size;
128size_t ttl_data_size = 0;
129#ifdef DO_STATS
130int process_ct = 0;
131int apply_ct = 0;
132int fixed_ct = 0;
133int altered_ct = 0;
134#endif /* DO_STATS */
135
136#ifdef HAVE_MMAP
137#define UNLOAD_DATA() do { if (curr_data_mapped) { \
138 munmap ((void*)pz_curr_data, data_map_size); close (data_map_fd); } \
139 else free ((void*)pz_curr_data); } while(0)
140#else
141#define UNLOAD_DATA() free ((void*)pz_curr_data)
142#endif
143
1f414ac4 144const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
5abc1f74 145tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
1f414ac4
BK
146regex_t incl_quote_re;
147
5abc1f74 148void do_version ();
94db2f71
BK
149char *load_file _P_((const char *));
150void process _P_((char *, const char *));
d1c6a037 151void run_compiles ();
d1c6a037 152void initialize ();
5abc1f74
BK
153void process ();
154
155/* External Source Code */
0083c904
BK
156
157#include "fixincl.x"
5abc1f74
BK
158#include "fixtests.c"
159#include "fixfixes.c"
0083c904 160
1f414ac4
BK
161/* * * * * * * * * * * * * * * * * * *
162 *
163 * MAIN ROUTINE
164 */
0083c904
BK
165int
166main (argc, argv)
167 int argc;
168 char **argv;
169{
5abc1f74 170 char *file_name_buf;
0083c904 171
1f414ac4
BK
172 switch (argc)
173 {
174 case 1:
175 break;
176
177 case 2:
0083c904 178 if (strcmp (argv[1], "-v") == 0)
5abc1f74
BK
179 do_version ();
180 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
0083c904 181 {
5abc1f74
BK
182 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
183 errno, strerror (errno), argv[1] );
184 exit (EXIT_FAILURE);
0083c904 185 }
1f414ac4
BK
186 break;
187
188 default:
189 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
190 exit (EXIT_FAILURE);
0083c904
BK
191 }
192
d1c6a037
BK
193 initialize ();
194
5abc1f74
BK
195 /* Before anything else, ensure we can allocate our file name buffer. */
196 file_name_buf = load_file_data (stdin);
197
198 /* Because of the way server shells work, you have to keep stdin, out
199 and err open so that the proper input file does not get closed
200 by accident */
201
202 freopen ("/dev/null", "r", stdin);
203
204 if (file_name_buf == (char *) NULL)
205 {
206 fputs ("No file names listed for fixing\n", stderr);
207 exit (EXIT_FAILURE);
208 }
209
d1c6a037
BK
210 for (;;)
211 {
5abc1f74 212 char* pz_end;
d1c6a037 213
5abc1f74 214 /* skip to start of name, past any "./" prefixes */
d1c6a037 215
5abc1f74
BK
216 while (ISSPACE (*file_name_buf)) file_name_buf++;
217 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
218 file_name_buf += 2;
d1c6a037 219
5abc1f74
BK
220 /* Check for end of list */
221
222 if (*file_name_buf == NUL)
223 break;
224
225 /* Set global file name pointer and find end of name */
226
227 pz_curr_file = file_name_buf;
228 pz_end = strchr( pz_curr_file, '\n' );
229 if (pz_end == (char*)NULL)
230 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
231 else
232 file_name_buf = pz_end + 1;
233
234 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
235
236 /* IF no name is found (blank line) or comment marker, skip line */
237
238 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
239 continue;
240 *pz_end = NUL;
d1c6a037 241
5abc1f74
BK
242#ifdef NO_BOGOSITY
243 process ();
244#else
245 /* Prevent duplicate output by child process */
d1c6a037 246
94db2f71
BK
247 fflush (stdout);
248 fflush (stderr);
249
d1c6a037 250 {
5abc1f74 251 void wait_for_pid _P_(( pid_t ));
d1c6a037
BK
252 pid_t child = fork ();
253 if (child == NULLPROCESS)
5abc1f74
BK
254 {
255 process ();
256 return EXIT_SUCCESS;
257 }
d1c6a037
BK
258
259 if (child == NOPROCESS)
260 {
261 fprintf (stderr, "Error %d (%s) forking in main\n",
262 errno, strerror (errno));
263 exit (EXIT_FAILURE);
264 }
265
5abc1f74 266 wait_for_pid( child );
d1c6a037 267 }
d1c6a037 268#endif
5abc1f74 269 } /* for (;;) */
d1c6a037 270
5abc1f74 271#ifdef DO_STATS
b35926b9 272 if (VLEVEL( VERB_PROGRESS )) {
5abc1f74
BK
273 tSCC zFmt[] =
274 "\
275Processed %5d files containing %d bytes \n\
276Applying %5d fixes to %d files\n\
277Altering %5d of them\n";
278
279 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
280 fixed_ct, altered_ct);
281 }
282#endif /* DO_STATS */
d1c6a037
BK
283 return EXIT_SUCCESS;
284}
285
286
5abc1f74
BK
287void
288do_version ()
289{
290 static const char zFmt[] = "echo '%s'";
291 char zBuf[ 1024 ];
292
293 /* The 'version' option is really used to test that:
294 1. The program loads correctly (no missing libraries)
295 2. we can correctly run our server shell process
296 3. that we can compile all the regular expressions.
297 */
298 run_compiles ();
299 sprintf (zBuf, zFmt, program_id);
300 fputs (zBuf + 5, stdout);
301 exit (strcmp (run_shell (zBuf), program_id));
302}
303
d1c6a037
BK
304/* * * * * * * * * * * * */
305
306void
5abc1f74 307initialize ()
d1c6a037
BK
308{
309 static const char var_not_found[] =
5abc1f74
BK
310 "fixincl ERROR: %s environment variable not defined\n\
311\tTARGET_MACHINE, DESTDIR, SRCDIR and FIND_BASE are required\n";
d1c6a037 312
0083c904 313 {
1f414ac4
BK
314 static const char var[] = "TARGET_MACHINE";
315 pz_machine = getenv (var);
316 if (pz_machine == (char *) NULL)
0083c904 317 {
1f414ac4 318 fprintf (stderr, var_not_found, var);
0083c904
BK
319 exit (EXIT_FAILURE);
320 }
321 }
322
323 {
1f414ac4
BK
324 static const char var[] = "DESTDIR";
325 pz_dest_dir = getenv (var);
326 if (pz_dest_dir == (char *) NULL)
0083c904 327 {
1f414ac4 328 fprintf (stderr, var_not_found, var);
0083c904
BK
329 exit (EXIT_FAILURE);
330 }
331 }
332
333 {
1f414ac4
BK
334 static const char var[] = "SRCDIR";
335 pz_src_dir = getenv (var);
336 if (pz_src_dir == (char *) NULL)
0083c904 337 {
1f414ac4 338 fprintf (stderr, var_not_found, var);
0083c904
BK
339 exit (EXIT_FAILURE);
340 }
341 }
342
b35926b9
BK
343 {
344 static const char var[] = "VERBOSE";
345 char* pz = getenv (var);
346 if (pz != (char *) NULL)
347 {
348 if (isdigit( *pz ))
349 verbose_level = (te_verbose)atoi( pz );
350 else
351 switch (*pz) {
352 case 's':
353 case 'S':
354 verbose_level = VERB_SILENT; break;
355
356 case 'f':
357 case 'F':
358 verbose_level = VERB_FIXES; break;
359
360 case 'a':
361 case 'A':
362 verbose_level = VERB_APPLIES; break;
363
364 case 'p':
365 case 'P':
366 verbose_level = VERB_PROGRESS; break;
367
368 case 't':
369 case 'T':
370 verbose_level = VERB_TESTS; break;
371
372 case 'e':
373 case 'E':
374 verbose_level = VERB_EVERYTHING; break;
375 }
376 }
377 }
378
7d9ccd90
BK
379 {
380 static const char var[] = "FIND_BASE";
5abc1f74
BK
381 char *pz = getenv (var);
382 if (pz == (char *) NULL)
7d9ccd90
BK
383 {
384 fprintf (stderr, var_not_found, var);
385 exit (EXIT_FAILURE);
386 }
5abc1f74
BK
387 while ((pz[0] == '.') && (pz[1] == '/'))
388 pz += 2;
389 if ((pz[0] != '.') || (pz[1] != NUL))
390 find_base_len = strlen( pz );
7d9ccd90
BK
391 }
392
1f414ac4
BK
393 /* Compile all the regular expressions now.
394 That way, it is done only once for the whole run.
395 */
396 run_compiles ();
0083c904 397
1f414ac4
BK
398 signal (SIGQUIT, SIG_IGN);
399 signal (SIGIOT, SIG_IGN);
400 signal (SIGPIPE, SIG_IGN);
401 signal (SIGALRM, SIG_IGN);
402 signal (SIGTERM, SIG_IGN);
5abc1f74 403#ifndef NO_BOGOSITY
d1c6a037
BK
404 /*
405 Make sure that if we opened a server process, we close it now.
406 This is the grandparent process. We don't need the server anymore
407 and our children should make their own. */
0083c904 408
d1c6a037
BK
409 close_server ();
410 (void)wait ( (int*)NULL );
5abc1f74 411#endif
d1c6a037 412}
0083c904 413
5abc1f74 414#ifndef NO_BOGOSITY
d1c6a037 415/* * * * * * * * * * * * *
5abc1f74 416
d1c6a037
BK
417 wait_for_pid - Keep calling `wait(2)' until it returns
418 the process id we are looking for. Not every system has
419 `waitpid(2)'. We also ensure that the children exit with success. */
7d9ccd90 420
d1c6a037 421void
5abc1f74 422wait_for_pid(child)
48ac9ce2 423 pid_t child;
d1c6a037 424{
d1c6a037
BK
425 for (;;) {
426 int status;
427 pid_t dead_kid = wait (&status);
7d9ccd90 428
d1c6a037
BK
429 if (dead_kid == child)
430 {
431 if (! WIFEXITED( status ))
432 {
b35926b9
BK
433 if (NOT_SILENT)
434 fprintf (stderr, "child process %d is hung on signal %d\n",
435 child, WSTOPSIG( status ));
d1c6a037
BK
436 exit (EXIT_FAILURE);
437 }
438 if (WEXITSTATUS( status ) != 0)
439 {
b35926b9
BK
440 if (NOT_SILENT)
441 fprintf (stderr, "child process %d exited with status %d\n",
442 child, WEXITSTATUS( status ));
d1c6a037
BK
443 exit (EXIT_FAILURE);
444 }
d1c6a037
BK
445 break; /* normal child completion */
446 }
1f414ac4 447
d1c6a037
BK
448 /*
449 IF there is an error, THEN see if it is retryable.
450 If it is not retryable, then break out of this loop. */
451 if (dead_kid == NOPROCESS)
452 {
453 switch (errno) {
454 case EINTR:
455 case EAGAIN:
456 break;
457
458 default:
b35926b9
BK
459 if (NOT_SILENT)
460 fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
461 errno, strerror( errno ), child );
d1c6a037
BK
462 /* FALLTHROUGH */
463
464 case ECHILD: /* no children to wait for?? */
465 return;
0083c904 466 }
d1c6a037
BK
467 }
468 } done_waiting:;
0083c904 469}
5abc1f74 470#endif /* NO_BOGOSITY */
0083c904 471
1f414ac4 472/* * * * * * * * * * * * *
5abc1f74 473
1f414ac4
BK
474 load_file loads all the contents of a file into malloc-ed memory.
475 Its argument is the name of the file to read in; the returned
476 result is the NUL terminated contents of the file. The file
477 is presumed to be an ASCII text file containing no NULs. */
0083c904 478char *
5abc1f74
BK
479load_file ( fname )
480 const char* fname;
0083c904 481{
5abc1f74
BK
482 struct stat stbf;
483 char* res;
0083c904 484
5abc1f74 485 if (stat (fname, &stbf) != 0)
0083c904 486 {
b35926b9
BK
487 if (NOT_SILENT)
488 fprintf (stderr, "error %d (%s) stat-ing %s\n",
489 errno, strerror (errno), fname );
5abc1f74 490 return (char *) NULL;
0083c904 491 }
5abc1f74
BK
492 if (stbf.st_size == 0)
493 return (char*)NULL;
0083c904 494
5abc1f74
BK
495 data_map_size = stbf.st_size+1;
496 data_map_fd = open (fname, O_RDONLY);
497 ttl_data_size += data_map_size-1;
0083c904 498
5abc1f74
BK
499 if (data_map_fd < 0)
500 {
b35926b9
BK
501 if (NOT_SILENT)
502 fprintf (stderr, "error %d (%s) opening %s for read\n",
503 errno, strerror (errno), fname);
5abc1f74
BK
504 return (char*)NULL;
505 }
0083c904 506
5abc1f74
BK
507#ifdef HAVE_MMAP
508 curr_data_mapped = BOOL_TRUE;
509 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE,
510 data_map_fd, 0);
511 if (res == (char*)BAD_ADDR)
512 {
513 curr_data_mapped = BOOL_FALSE;
514 res = load_file_data ( fdopen (data_map_fd, "r"));
515 }
516#else
517 curr_data_mapped = BOOL_FALSE;
518 res = load_file_data ( fdopen (data_map_fd, "r"));
519#endif
0083c904 520
5abc1f74 521 return res;
0083c904
BK
522}
523
524
1f414ac4 525/* * * * * * * * * * * * *
5abc1f74 526
1f414ac4
BK
527 run_compiles run all the regexp compiles for all the fixes once.
528 */
0083c904 529void
1f414ac4 530run_compiles ()
0083c904 531{
94db2f71
BK
532 tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\
533\texpr = `%s'\n\terror %s\n";
1f414ac4
BK
534 tFixDesc *p_fixd = fixDescList;
535 int fix_ct = FIX_COUNT;
536 tTestDesc *p_test;
537 int test_ct;
538 int re_ct = REGEX_COUNT;
539 const char *pz_err;
540 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
541
542 if (p_re == (regex_t *) NULL)
0083c904
BK
543 {
544 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
545 REGEX_COUNT * sizeof (regex_t));
546 exit (EXIT_FAILURE);
547 }
548
d1c6a037
BK
549 /* Make sure re_compile_pattern does not stumble across invalid
550 data */
551
552 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
553 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
554
1f414ac4
BK
555 /* The patterns we search for are all egrep patterns.
556 In the shell version of this program, we invoke egrep
557 with the supplied pattern. Here, we will run
558 re_compile_pattern, but it must be using the same rules. */
559
0083c904 560 re_set_syntax (RE_SYNTAX_EGREP);
1f414ac4
BK
561 pz_err = re_compile_pattern (incl_quote_pat, sizeof (incl_quote_pat)-1,
562 &incl_quote_re);
563 if (pz_err != (char *) NULL)
0083c904 564 {
1f414ac4
BK
565 fprintf (stderr, z_bad_comp, "quoted include", "run_compiles",
566 incl_quote_pat, pz_err);
0083c904
BK
567 exit (EXIT_FAILURE);
568 }
569
1f414ac4 570 /* FOR every fixup, ... */
0083c904
BK
571 do
572 {
1f414ac4
BK
573 p_test = p_fixd->p_test_desc;
574 test_ct = p_fixd->test_ct;
0083c904 575
1f414ac4
BK
576 /* IF the machine type pointer is not NULL (we are not in test mode)
577 AND this test is for or not done on particular machines
578 THEN ... */
579
580 if ( (pz_machine != NULL)
581 && (p_fixd->papz_machs != (const char**) NULL) )
582 {
5abc1f74 583 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
99d525c9
PDM
584 tSCC esac_fmt[] =
585 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
5abc1f74
BK
586 tSCC skip[] = "skip"; /* 4 bytes */
587 tSCC run[] = "run"; /* 3 bytes */
588 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
589
1f414ac4 590 const char **papz_machs = p_fixd->papz_machs;
5abc1f74 591 char *pz;
1f414ac4
BK
592 char *pz_sep = "";
593 tCC *pz_if_true;
594 tCC *pz_if_false;
5abc1f74 595 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
1f414ac4 596
5abc1f74 597 /* Start the case statement */
1f414ac4 598
5abc1f74
BK
599 sprintf (cmd_buf, case_fmt, pz_machine);
600 pz = cmd_buf + strlen (cmd_buf);
1f414ac4 601
5abc1f74 602 /* Determine if a match means to apply the fix or not apply it */
1f414ac4
BK
603
604 if (p_fixd->fd_flags & FD_MACH_IFNOT)
605 {
606 pz_if_true = skip;
607 pz_if_false = run;
608 }
609 else
610 {
611 pz_if_true = run;
612 pz_if_false = skip;
613 }
614
5abc1f74
BK
615 /* Emit all the machine names. If there are more than one,
616 then we will insert " | \\\n" between the names */
1f414ac4
BK
617
618 for (;;)
619 {
620 const char* pz_mach = *(papz_machs++);
621
622 if (pz_mach == (const char*) NULL)
623 break;
5abc1f74 624 sprintf (pz, "%s%s", pz_sep, pz_mach);
1f414ac4
BK
625 pz += strlen (pz);
626 pz_sep = " | \\\n";
627 }
5abc1f74
BK
628
629 /* Now emit the match and not-match actions and the esac */
630
631 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
1f414ac4
BK
632
633 /* Run the script.
634 The result will start either with 's' or 'r'. */
635
7d032a4f
RO
636 {
637 int skip;
5abc1f74 638 pz = run_shell (cmd_buf);
7d032a4f
RO
639 skip = (*pz == 's');
640 free ( (void*)pz );
641 if (skip)
642 {
643 p_fixd->fd_flags |= FD_SKIP_TEST;
644 continue;
645 }
646 }
0083c904 647 }
0083c904 648
1f414ac4
BK
649 /* FOR every test for the fixup, ... */
650
651 while (--test_ct >= 0)
0083c904 652 {
1f414ac4 653 switch (p_test->type)
0083c904
BK
654 {
655 case TT_EGREP:
656 case TT_NEGREP:
1f414ac4
BK
657 /* You might consider putting the following under #ifdef.
658 The number of re's used is computed by autogen.
659 So, it is static and known at compile time. */
660
661 if (--re_ct < 0)
0083c904
BK
662 {
663 fputs ("out of RE's\n", stderr);
664 exit (EXIT_FAILURE);
665 }
666
1f414ac4
BK
667 p_test->p_test_regex = p_re++;
668 pz_err = re_compile_pattern (p_test->pz_test_text,
669 strlen (p_test->pz_test_text),
670 p_test->p_test_regex);
671 if (pz_err != (char *) NULL)
0083c904 672 {
1f414ac4
BK
673 fprintf (stderr, z_bad_comp, "select test", p_fixd->fix_name,
674 p_test->pz_test_text, pz_err);
0083c904
BK
675 exit (EXIT_FAILURE);
676 }
677 }
1f414ac4 678 p_test++;
0083c904
BK
679 }
680 }
1f414ac4 681 while (p_fixd++, --fix_ct > 0);
0083c904
BK
682}
683
684
1f414ac4 685/* * * * * * * * * * * * *
5abc1f74 686
1f414ac4
BK
687 create_file Create the output modified file.
688 Input: the name of the file to create
689 Returns: a file pointer to the new, open file */
690
063174ee
BK
691#if defined(S_IRUSR) && defined(S_IWUSR) && \
692 defined(S_IRGRP) && defined(S_IROTH)
693
694# define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
695#else
696# define S_IRALL 0644
697#endif
698
699#if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
700 defined(S_IROTH) && defined(S_IXOTH)
701
702# define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
703#else
704# define S_DIRALL 0755
705#endif
706
1f414ac4 707
0083c904 708FILE *
5abc1f74 709create_file ()
0083c904
BK
710{
711 int fd;
712 FILE *pf;
713 char fname[MAXPATHLEN];
714
5abc1f74 715 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
0083c904 716
1f414ac4 717 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
0083c904 718
1f414ac4 719 /* We may need to create the directories needed... */
0083c904
BK
720 if ((fd < 0) && (errno == ENOENT))
721 {
1f414ac4 722 char *pz_dir = strchr (fname + 1, '/');
0083c904
BK
723 struct stat stbf;
724
1f414ac4 725 while (pz_dir != (char *) NULL)
0083c904 726 {
1f414ac4 727 *pz_dir = NUL;
0083c904
BK
728 if (stat (fname, &stbf) < 0)
729 {
063174ee 730 mkdir (fname, S_IFDIR | S_DIRALL);
0083c904
BK
731 }
732
1f414ac4
BK
733 *pz_dir = '/';
734 pz_dir = strchr (pz_dir + 1, '/');
0083c904 735 }
1f414ac4
BK
736
737 /* Now, lets try the open again... */
738 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
0083c904
BK
739 }
740 if (fd < 0)
741 {
742 fprintf (stderr, "Error %d (%s) creating %s\n",
743 errno, strerror (errno), fname);
744 exit (EXIT_FAILURE);
745 }
b35926b9
BK
746 if (NOT_SILENT)
747 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
0083c904
BK
748 pf = fdopen (fd, "w");
749
750#ifdef LATER
751 {
1f414ac4
BK
752 static const char hdr[] =
753 "/* DO NOT EDIT THIS FILE.\n\n"
754 " It has been auto-edited by fixincludes from /usr/include/%s\n"
755 " This had to be done to correct non-standard usages in the\n"
756 " original, manufacturer supplied header file. */\n\n";
757
5abc1f74 758 fprintf (pf, hdr, pz_curr_file);
0083c904
BK
759 }
760#endif
761 return pf;
762}
763
0083c904 764
1f414ac4 765/* * * * * * * * * * * * *
0083c904 766
1f414ac4
BK
767 test_test make sure a shell-style test expression passes.
768 Input: a pointer to the descriptor of the test to run and
769 the name of the file that we might want to fix
5abc1f74 770 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
1f414ac4
BK
771 shell script we run. */
772
5abc1f74
BK
773int
774test_test (p_test, pz_test_file)
1f414ac4 775 tTestDesc *p_test;
5abc1f74 776 char* pz_test_file;
1f414ac4 777{
94db2f71
BK
778 tSCC cmd_fmt[] =
779"file=%s\n\
780if ( test %s ) > /dev/null 2>&1\n\
781then echo TRUE\n\
782else echo FALSE\n\
783fi";
784
1f414ac4 785 char *pz_res;
5abc1f74 786 int res = SKIP_FIX;
1f414ac4
BK
787
788 static char cmd_buf[4096];
1f414ac4 789
5abc1f74 790 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
1f414ac4
BK
791 pz_res = run_shell (cmd_buf);
792 if (*pz_res == 'T')
5abc1f74 793 res = APPLY_FIX;
1f414ac4 794 free ((void *) pz_res);
0083c904
BK
795 return res;
796}
797
798
1f414ac4 799/* * * * * * * * * * * * *
5abc1f74 800
1f414ac4
BK
801 egrep_test make sure an egrep expression is found in the file text.
802 Input: a pointer to the descriptor of the test to run and
803 the pointer to the contents of the file under suspicion
5abc1f74 804 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
1f414ac4 805
5abc1f74 806 The caller may choose to reverse meaning if the sense of the test
1f414ac4
BK
807 is inverted. */
808
5abc1f74 809int
1f414ac4
BK
810egrep_test (pz_data, p_test)
811 char *pz_data;
812 tTestDesc *p_test;
0083c904
BK
813{
814 regmatch_t match;
1f414ac4 815
5abc1f74 816#ifdef DEBUG
1f414ac4
BK
817 if (p_test->p_test_regex == 0)
818 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
819 p_test->pz_test_text);
0083c904 820#endif
1f414ac4 821 if (regexec (p_test->p_test_regex, pz_data, 1, &match, 0) == 0)
5abc1f74
BK
822 return APPLY_FIX;
823 return SKIP_FIX;
0083c904
BK
824}
825
826
94db2f71
BK
827/* * * * * * * * * * * * *
828
829 quoted_file_exists Make sure that a file exists before we emit
830 the file name. If we emit the name, our invoking shell will try
831 to copy a non-existing file into the destination directory. */
832
833int
834quoted_file_exists (pz_src_path, pz_file_path, pz_file)
835 char* pz_src_path;
836 char* pz_file_path;
837 char* pz_file;
838{
839 char z[ MAXPATHLEN ];
840 char* pz;
841 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
842 pz = z + strlen ( z );
843
844 for (;;) {
845 char ch = *pz_file++;
5abc1f74 846 if (! ISGRAPH( ch ))
94db2f71
BK
847 return 0;
848 if (ch == '"')
849 break;
850 *pz++ = ch;
851 }
852 *pz = '\0';
853 {
854 struct stat s;
855 if (stat (z, &s) != 0)
856 return 0;
857 return S_ISREG( s.st_mode );
858 }
859}
860
861
1f414ac4
BK
862/* * * * * * * * * * * * *
863 *
864 extract_quoted_files
5abc1f74 865
1f414ac4
BK
866 The syntax, `#include "file.h"' specifies that the compiler is to
867 search the local directory of the current file before the include
868 list. Consequently, if we have modified a header and stored it in
869 another directory, any files that are included by that modified
870 file in that fashion must also be copied into this new directory.
871 This routine finds those flavors of #include and for each one found
872 emits a triple of:
5abc1f74 873
1f414ac4
BK
874 1. source directory of the original file
875 2. the relative path file name of the #includ-ed file
876 3. the full destination path for this file
877
878 Input: the text of the file, the file name and a pointer to the
879 match list where the match information was stored.
880 Result: internally nothing. The results are written to stdout
881 for interpretation by the invoking shell */
0083c904 882
94db2f71 883
0083c904 884void
5abc1f74 885extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
1f414ac4 886 char *pz_data;
5abc1f74 887 const char *pz_fixed_file;
1f414ac4 888 regmatch_t *p_re_match;
0083c904 889{
5abc1f74 890 char *pz_dir_end = strrchr (pz_fixed_file, '/');
1f414ac4 891 char *pz_incl_quot = pz_data;
0083c904 892
b35926b9
BK
893 if (VLEVEL( VERB_APPLIES ))
894 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
0083c904 895
5abc1f74 896 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
94db2f71 897 If there is none, then it is in our current directory, ".". */
1f414ac4
BK
898
899 if (pz_dir_end == (char *) NULL)
5abc1f74 900 pz_fixed_file = ".";
0083c904 901 else
1f414ac4 902 *pz_dir_end = '\0';
0083c904
BK
903
904 for (;;)
905 {
1f414ac4
BK
906 pz_incl_quot += p_re_match->rm_so;
907
908 /* Skip forward to the included file name */
92a438d1 909 while (ISSPACE (*pz_incl_quot))
1f414ac4 910 pz_incl_quot++;
92a438d1 911 /* ISSPACE() may evaluate is argument more than once! */
5abc1f74 912 while (++pz_incl_quot, ISSPACE (*pz_incl_quot))
1f414ac4
BK
913 ;
914 pz_incl_quot += sizeof ("include") - 1;
915 while (*pz_incl_quot++ != '"')
916 ;
917
5abc1f74 918 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
94db2f71
BK
919 {
920 /* Print the source directory and the subdirectory
921 of the file in question. */
5abc1f74 922 printf ("%s %s/", pz_src_dir, pz_fixed_file);
94db2f71
BK
923 pz_dir_end = pz_incl_quot;
924
925 /* Append to the directory the relative path of the desired file */
926 while (*pz_incl_quot != '"')
927 putc (*pz_incl_quot++, stdout);
928
929 /* Now print the destination directory appended with the
930 relative path of the desired file */
5abc1f74 931 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
94db2f71
BK
932 while (*pz_dir_end != '"')
933 putc (*pz_dir_end++, stdout);
934
935 /* End of entry */
936 putc ('\n', stdout);
937 }
0083c904 938
1f414ac4
BK
939 /* Find the next entry */
940 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
0083c904
BK
941 break;
942 }
943}
944
945
5abc1f74
BK
946/* * * * * * * * * * * * *
947
948 Somebody wrote a *_fix subroutine that we must call.
949 */
950
951int
952internal_fix (read_fd, p_fixd)
953 int read_fd;
954 tFixDesc* p_fixd;
955{
956 int fd[2];
957
958 if (pipe( fd ) != 0)
959 {
960 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
961 exit (EXIT_FAILURE);
962 }
963
964 for (;;)
965 {
966 pid_t childid = fork();
967
968 switch (childid)
969 {
970 case -1:
971 break;
972
973 case 0:
974 close (fd[0]);
975 goto do_child_task;
976
977 default:
978 /*
979 * Parent process
980 */
981 close (read_fd);
982 close (fd[1]);
983 return fd[0];
984 }
985
986 /*
987 * Parent in error
988 */
989 fprintf (stderr, z_fork_err, errno, strerror (errno),
990 p_fixd->fix_name);
991 {
992 static int failCt = 0;
993 if ((errno != EAGAIN) || (++failCt > 10))
994 exit (EXIT_FAILURE);
995 sleep (1);
996 }
997 } do_child_task:;
998
999 /*
1000 * Close our current stdin and stdout
1001 */
1002 close (STDIN_FILENO);
1003 close (STDOUT_FILENO);
1004 UNLOAD_DATA();
1005
1006 /*
1007 * Make the fd passed in the stdin, and the write end of
1008 * the new pipe become the stdout.
1009 */
1010 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
1011 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
1012 fdopen (STDIN_FILENO, "r");
1013 fdopen (STDOUT_FILENO, "w");
1014
1015 apply_fix (p_fixd->patch_args[0], pz_curr_file);
1016 exit (0);
1017}
1018
bb786201
BK
1019
1020/* * * * * * * * * * * * *
1021
1022 This loop should only cycle for 1/2 of one loop.
1023 "chain_open" starts a process that uses "read_fd" as
1024 its stdin and returns the new fd this process will use
1025 for stdout. */
1026
1027int
5abc1f74 1028start_fixer (read_fd, p_fixd, pz_fix_file)
bb786201
BK
1029 int read_fd;
1030 tFixDesc* p_fixd;
5abc1f74 1031 char* pz_fix_file;
bb786201 1032{
bb786201
BK
1033 tCC* pz_cmd_save;
1034 char* pz_cmd;
1035
5abc1f74
BK
1036 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1037 return internal_fix (read_fd, p_fixd);
1038
bb786201
BK
1039 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1040 pz_cmd = (char*)NULL;
1041 else
1042 {
1043 tSCC z_cmd_fmt[] = "file='%s'\n%s";
5abc1f74 1044 pz_cmd = (char*)malloc (strlen (p_fixd->patch_args[2])
bb786201 1045 + sizeof( z_cmd_fmt )
5abc1f74
BK
1046 + strlen( pz_fix_file ));
1047 if (pz_cmd == (char*)NULL)
1048 {
1049 fputs ("allocation failure\n", stderr);
1050 exit (EXIT_FAILURE);
1051 }
1052 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
bb786201
BK
1053 pz_cmd_save = p_fixd->patch_args[2];
1054 p_fixd->patch_args[2] = pz_cmd;
1055 }
1056
b35926b9
BK
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 */
bb786201
BK
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
5abc1f74 1079 fprintf (stderr, z_fork_err, errno, strerror (errno),
bb786201
BK
1080 p_fixd->fix_name);
1081
1082 if ((errno != EAGAIN) || (++failCt > 10))
1083 exit (EXIT_FAILURE);
1084 sleep (1);
1085 }
1086
b35926b9
BK
1087 /* IF we allocated a shell script command,
1088 THEN free it and restore the command format to the fix description */
bb786201
BK
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}
1097
5abc1f74 1098
1f414ac4
BK
1099/* * * * * * * * * * * * *
1100
1101 Process the potential fixes for a particular include file.
1102 Input: the original text of the file and the file's name
1103 Result: none. A new file may or may not be created. */
1104
5abc1f74
BK
1105t_bool
1106fix_applies (p_fixd)
1107 tFixDesc *p_fixd;
0083c904 1108{
b35926b9
BK
1109#ifdef DEBUG
1110 static const char z_failed[] = "not applying %s to %s - test %d failed\n";
1111#endif
5abc1f74
BK
1112 int test_ct;
1113 tTestDesc *p_test;
0083c904 1114
5abc1f74
BK
1115 if (p_fixd->fd_flags & FD_SKIP_TEST)
1116 return BOOL_FALSE;
0083c904 1117
5abc1f74
BK
1118 /* IF there is a file name restriction,
1119 THEN ensure the current file name matches one in the pattern */
1120
1121 if (p_fixd->file_list != (char *) NULL)
1122 {
1123 const char *pz_fname = pz_curr_file;
1124 const char *pz_scan = p_fixd->file_list;
1125 size_t name_len;
0083c904 1126
5abc1f74
BK
1127 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1128 pz_fname += 2;
1129 name_len = strlen (pz_fname);
1f414ac4 1130
5abc1f74 1131 for (;;)
0083c904 1132 {
5abc1f74
BK
1133 pz_scan = strstr (pz_scan + 1, pz_fname);
1134 /* IF we can't match the string at all,
1135 THEN bail */
b35926b9
BK
1136 if (pz_scan == (char *) NULL) {
1137#ifdef DEBUG
1138 if (VLEVEL( VERB_EVERYTHING ))
1139 fprintf (stderr, "file %s not in list for %s\n",
1140 pz_fname, p_fixd->fix_name );
1141#endif
5abc1f74 1142 return BOOL_FALSE;
b35926b9 1143 }
0083c904 1144
5abc1f74
BK
1145 /* IF the match is surrounded by the '|' markers,
1146 THEN we found a full match -- time to run the tests */
0083c904 1147
5abc1f74
BK
1148 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1149 break;
1150 }
1151 }
0083c904 1152
5abc1f74
BK
1153 /* FOR each test, see if it fails.
1154 IF it does fail, then we go on to the next test */
1f414ac4 1155
5abc1f74
BK
1156 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1157 test_ct-- > 0;
1158 p_test++)
1159 {
1160 switch (p_test->type)
1161 {
1162 case TT_TEST:
b35926b9
BK
1163 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1164#ifdef DEBUG
1165 if (VLEVEL( VERB_EVERYTHING ))
1166 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1167 p_fixd->test_ct - test_ct);
1168#endif
5abc1f74 1169 return BOOL_FALSE;
b35926b9 1170 }
5abc1f74
BK
1171 break;
1172
1173 case TT_EGREP:
b35926b9
BK
1174 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1175#ifdef DEBUG
1176 if (VLEVEL( VERB_EVERYTHING ))
1177 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1178 p_fixd->test_ct - test_ct);
1179#endif
5abc1f74 1180 return BOOL_FALSE;
b35926b9 1181 }
5abc1f74
BK
1182 break;
1183
1184 case TT_NEGREP:
b35926b9
BK
1185 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1186#ifdef DEBUG
1187 if (VLEVEL( VERB_EVERYTHING ))
1188 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1189 p_fixd->test_ct - test_ct);
1190#endif
5abc1f74
BK
1191 /* Negated sense */
1192 return BOOL_FALSE;
b35926b9 1193 }
5abc1f74
BK
1194 break;
1195
1196 case TT_FUNCTION:
1197 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
b35926b9
BK
1198 != APPLY_FIX) {
1199#ifdef DEBUG
1200 if (VLEVEL( VERB_EVERYTHING ))
1201 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1202 p_fixd->test_ct - test_ct);
1203#endif
5abc1f74 1204 return BOOL_FALSE;
b35926b9 1205 }
5abc1f74 1206 break;
0083c904 1207 }
5abc1f74 1208 }
0083c904 1209
5abc1f74
BK
1210 return BOOL_TRUE;
1211}
0083c904 1212
0083c904 1213
5abc1f74
BK
1214/* * * * * * * * * * * * *
1215
1216 Write out a replacement file */
1217
1218void
1219write_replacement (p_fixd)
1220 tFixDesc *p_fixd;
1221{
1222 const char* pz_text = p_fixd->patch_args[0];
1223
1224 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1225 return;
1226
1227 {
1228 FILE* out_fp = create_file (pz_curr_file);
1229 fputs (pz_text, out_fp);
1230 fclose (out_fp);
1231 }
1232}
1233
1234
1235/* * * * * * * * * * * * *
1236
1237 We have work to do. Read back in the output
1238 of the filtering chain. Compare each byte as we read it with
1239 the contents of the original file. As soon as we find any
1240 difference, we will create the output file, write out all
1241 the matched text and then copy any remaining data from the
1242 output of the filter chain.
1243 */
1244void
1245test_for_changes (read_fd)
1246 int read_fd;
1247{
1248 FILE *in_fp = fdopen (read_fd, "r");
1249 FILE *out_fp = (FILE *) NULL;
1250 char *pz_cmp = pz_curr_data;
1251
1252#ifdef DO_STATS
1253 fixed_ct++;
1f414ac4 1254#endif
5abc1f74
BK
1255 for (;;)
1256 {
1257 int ch;
0083c904 1258
5abc1f74
BK
1259 ch = getc (in_fp);
1260 if (ch == EOF)
1261 break;
1262
1263 /* IF we are emitting the output
1264 THEN emit this character, too.
1265 */
1266 if (out_fp != (FILE *) NULL)
1267 putc (ch, out_fp);
1268
1269 /* ELSE if this character does not match the original,
1270 THEN now is the time to start the output.
1271 */
1272 else if (ch != *pz_cmp)
1273 {
1274 out_fp = create_file (pz_curr_file);
1275
1276#ifdef DO_STATS
1277 altered_ct++;
1f414ac4 1278#endif
5abc1f74
BK
1279 /* IF there are matched data, write the matched part now. */
1280 if (pz_cmp != pz_curr_data)
1281 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1282
1283 /* Emit the current unmatching character */
1284 putc (ch, out_fp);
0083c904 1285 }
5abc1f74
BK
1286 else
1287 /* ELSE the character matches. Advance the compare ptr */
1288 pz_cmp++;
1289 }
1290
1291 /* IF we created the output file, ... */
1292 if (out_fp != (FILE *) NULL)
1293 {
1294 regmatch_t match;
1295
1296 /* Close the file and see if we have to worry about
1297 `#include "file.h"' constructs. */
1298 fclose (out_fp);
1299 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1300 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1301 }
1302
1303 fclose (in_fp);
1304 close (read_fd); /* probably redundant, but I'm paranoid */
1305}
1306
1307
1308/* * * * * * * * * * * * *
1309
1310 Process the potential fixes for a particular include file.
1311 Input: the original text of the file and the file's name
1312 Result: none. A new file may or may not be created. */
1313
1314void
1315process ()
1316{
1317 static char env_current_file[1024];
1318 tFixDesc *p_fixd = fixDescList;
1319 int todo_ct = FIX_COUNT;
1320 int read_fd = -1;
1321 int num_children = 0;
1322
1323 if (access (pz_curr_file, R_OK) != 0)
1324 {
1325 int erno = errno;
1326 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1327 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1328 erno, strerror (erno));
1329 return;
1330 }
1331
1332 pz_curr_data = load_file (pz_curr_file);
1333 if (pz_curr_data == (char *) NULL)
1334 return;
1335
1336#ifdef DO_STATS
1337 process_ct++;
1338#endif
b35926b9
BK
1339 if (VLEVEL( VERB_PROGRESS ))
1340 fprintf (stderr, "%6d %-50s \r", data_map_size, pz_curr_file );
5abc1f74
BK
1341
1342 process_chain_head = NOPROCESS;
1343
1344 /* For every fix in our fix list, ... */
1345 for (; todo_ct > 0; p_fixd++, todo_ct--)
1346 {
1347 if (! fix_applies (p_fixd))
1348 continue;
0083c904 1349
b35926b9
BK
1350 if (VLEVEL( VERB_APPLIES ))
1351 fprintf (stderr, "Applying %-24s to %s\n",
1352 p_fixd->fix_name, pz_curr_file);
5abc1f74
BK
1353
1354 if (p_fixd->fd_flags & FD_REPLACEMENT)
1355 {
1356 write_replacement (p_fixd);
1357 UNLOAD_DATA();
1358 return;
1359 }
1f414ac4
BK
1360
1361 /* IF we do not have a read pointer,
1362 THEN this is the first fix for the current file.
1363 Open the source file. That will be used as stdin for
1364 the first fix. Any subsequent fixes will use the
5abc1f74 1365 stdout descriptor of the previous fix for its stdin. */
0083c904 1366
48ac9ce2 1367 if (read_fd == -1)
1f414ac4 1368 {
5abc1f74 1369 read_fd = open (pz_curr_file, O_RDONLY);
48ac9ce2 1370 if (read_fd < 0)
0083c904 1371 {
1f414ac4 1372 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
5abc1f74 1373 strerror (errno), pz_curr_file);
1f414ac4 1374 exit (EXIT_FAILURE);
0083c904 1375 }
5abc1f74
BK
1376
1377 /* Ensure we do not get duplicate output */
1378
1379 fflush (stdout);
1f414ac4 1380 }
0083c904 1381
5abc1f74 1382 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
bb786201 1383 num_children++;
0083c904
BK
1384 }
1385
5abc1f74
BK
1386 /* IF we have a read-back file descriptor,
1387 THEN check for changes and write output if changed. */
1f414ac4 1388
5abc1f74
BK
1389 if (read_fd >= 0)
1390 {
1391 test_for_changes (read_fd);
1392#ifdef DO_STATS
1393 apply_ct += num_children;
1394#endif
1395 /* Wait for child processes created by chain_open()
1396 to avoid leaving zombies. */
1397 do {
1398 wait ((int *) NULL);
1399 } while (--num_children > 0);
1400 }
9f8eec39 1401
5abc1f74 1402 UNLOAD_DATA();
0083c904 1403}
This page took 0.412425 seconds and 5 git commands to generate.