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.
6 Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
8 This file is part of GNU CC.
10 GNU CC is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
15 GNU CC is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with GNU CC; see the file COPYING. If not, write to
22 the Free Software Foundation, 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
29 #define BAD_ADDR ((void*)-1)
36 /* The contents of this string are not very important. It is mostly
37 just used as part of the "I am alive and working" test. */
39 static const char program_id[] = "fixincl version 1.1";
41 /* Working environment strings. Essentially, invocation 'options'. */
42 char *pz_dest_dir = NULL;
43 char *pz_src_dir = NULL;
44 char *pz_machine = NULL;
45 int find_base_len = 0;
56 te_verbose verbose_level = VERB_PROGRESS;
59 #define VLEVEL(l) (verbose_level >= l)
60 #define NOT_SILENT VLEVEL(VERB_FIXES)
62 pid_t process_chain_head = (pid_t) -1;
64 char* pz_curr_file; /* name of the current file under test/fix */
65 char* pz_curr_data; /* original contents of that file */
66 t_bool curr_data_mapped;
69 size_t ttl_data_size = 0;
78 #define UNLOAD_DATA() do { if (curr_data_mapped) { \
79 munmap ((void*)pz_curr_data, data_map_size); close (data_map_fd); } \
80 else free ((void*)pz_curr_data); } while(0)
82 #define UNLOAD_DATA() free ((void*)pz_curr_data)
85 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
86 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
87 regex_t incl_quote_re;
90 char *load_file _P_((const char *));
91 void process _P_((char *, const char *));
93 void initialize _P_((int argc,char** argv));
96 /* External Source Code */
100 /* * * * * * * * * * * * * * * * * * *
111 initialize ( argc, argv );
113 have_tty = isatty (fileno (stderr));
115 /* Before anything else, ensure we can allocate our file name buffer. */
116 file_name_buf = load_file_data (stdin);
118 /* Because of the way server shells work, you have to keep stdin, out
119 and err open so that the proper input file does not get closed
122 freopen ("/dev/null", "r", stdin);
124 if (file_name_buf == (char *) NULL)
126 fputs ("No file names listed for fixing\n", stderr);
134 /* skip to start of name, past any "./" prefixes */
136 while (ISSPACE (*file_name_buf)) file_name_buf++;
137 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
140 /* Check for end of list */
142 if (*file_name_buf == NUL)
145 /* Set global file name pointer and find end of name */
147 pz_curr_file = file_name_buf;
148 pz_end = strchr( pz_curr_file, '\n' );
149 if (pz_end == (char*)NULL)
150 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
152 file_name_buf = pz_end + 1;
154 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
156 /* IF no name is found (blank line) or comment marker, skip line */
158 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
166 if (VLEVEL( VERB_PROGRESS )) {
169 Processed %5d files containing %d bytes \n\
170 Applying %5d fixes to %d files\n\
171 Altering %5d of them\n";
173 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
174 fixed_ct, altered_ct);
176 #endif /* DO_STATS */
184 static const char zFmt[] = "echo '%s'";
187 /* The 'version' option is really used to test that:
188 1. The program loads correctly (no missing libraries)
189 2. that we can compile all the regular expressions.
190 3. we can correctly run our server shell process
193 sprintf (zBuf, zFmt, program_id);
195 exit (strcmp (run_shell (zBuf), program_id));
198 /* * * * * * * * * * * * */
201 initialize ( argc, argv )
205 static const char var_not_found[] =
206 "fixincl ERROR: %s environment variable not defined\n\
207 \tTARGET_MACHINE, DESTDIR, SRCDIR and FIND_BASE are required\n";
209 xmalloc_set_program_name (argv[0]);
217 if (strcmp (argv[1], "-v") == 0)
219 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
221 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
222 errno, xstrerror (errno), argv[1] );
228 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
233 static const char var[] = "TARGET_MACHINE";
234 pz_machine = getenv (var);
235 if (pz_machine == (char *) NULL)
237 fprintf (stderr, var_not_found, var);
243 static const char var[] = "DESTDIR";
244 pz_dest_dir = getenv (var);
245 if (pz_dest_dir == (char *) NULL)
247 fprintf (stderr, var_not_found, var);
253 static const char var[] = "SRCDIR";
254 pz_src_dir = getenv (var);
255 if (pz_src_dir == (char *) NULL)
257 fprintf (stderr, var_not_found, var);
263 static const char var[] = "VERBOSE";
264 char* pz = getenv (var);
265 if (pz != (char *) NULL)
268 verbose_level = (te_verbose)atoi( pz );
273 verbose_level = VERB_SILENT; break;
277 verbose_level = VERB_FIXES; break;
281 verbose_level = VERB_APPLIES; break;
285 verbose_level = VERB_PROGRESS; break;
289 verbose_level = VERB_TESTS; break;
293 verbose_level = VERB_EVERYTHING; break;
299 static const char var[] = "FIND_BASE";
300 char *pz = getenv (var);
301 if (pz == (char *) NULL)
303 fprintf (stderr, var_not_found, var);
306 while ((pz[0] == '.') && (pz[1] == '/'))
308 if ((pz[0] != '.') || (pz[1] != NUL))
309 find_base_len = strlen( pz );
312 /* Compile all the regular expressions now.
313 That way, it is done only once for the whole run.
317 signal (SIGQUIT, SIG_IGN);
319 signal (SIGIOT, SIG_IGN);
321 signal (SIGPIPE, SIG_IGN);
322 signal (SIGALRM, SIG_IGN);
323 signal (SIGTERM, SIG_IGN);
326 /* * * * * * * * * * * * *
328 load_file loads all the contents of a file into malloc-ed memory.
329 Its argument is the name of the file to read in; the returned
330 result is the NUL terminated contents of the file. The file
331 is presumed to be an ASCII text file containing no NULs. */
339 if (stat (fname, &stbf) != 0)
342 fprintf (stderr, "error %d (%s) stat-ing %s\n",
343 errno, xstrerror (errno), fname );
344 return (char *) NULL;
346 if (stbf.st_size == 0)
349 data_map_size = stbf.st_size+1;
350 data_map_fd = open (fname, O_RDONLY);
351 ttl_data_size += data_map_size-1;
356 fprintf (stderr, "error %d (%s) opening %s for read\n",
357 errno, xstrerror (errno), fname);
361 #ifdef HAVE_MMAP_FILE
362 curr_data_mapped = BOOL_TRUE;
363 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE,
365 if (res == (char*)BAD_ADDR)
367 curr_data_mapped = BOOL_FALSE;
368 res = load_file_data ( fdopen (data_map_fd, "r"));
371 curr_data_mapped = BOOL_FALSE;
372 res = load_file_data ( fdopen (data_map_fd, "r"));
379 /* * * * * * * * * * * * *
381 run_compiles run all the regexp compiles for all the fixes once.
386 tFixDesc *p_fixd = fixDescList;
387 int fix_ct = FIX_COUNT;
391 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
393 if (p_re == (regex_t *) NULL)
395 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
396 REGEX_COUNT * sizeof (regex_t));
400 /* Make sure compile_re does not stumble across invalid data */
402 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
403 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
405 compile_re (incl_quote_pat, &incl_quote_re, 1,
406 "quoted include", "run_compiles");
408 /* Allow machine name tests to be ignored (testing, mainly) */
410 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
411 pz_machine = (char*)NULL;
413 /* FOR every fixup, ... */
416 p_test = p_fixd->p_test_desc;
417 test_ct = p_fixd->test_ct;
419 /* IF the machine type pointer is not NULL (we are not in test mode)
420 AND this test is for or not done on particular machines
423 if ( (pz_machine != NULL)
424 && (p_fixd->papz_machs != (const char**) NULL) )
426 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
428 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
429 tSCC skip[] = "skip"; /* 4 bytes */
430 tSCC run[] = "run"; /* 3 bytes */
431 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
433 const char **papz_machs = p_fixd->papz_machs;
438 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
440 /* Start the case statement */
442 sprintf (cmd_buf, case_fmt, pz_machine);
443 pz = cmd_buf + strlen (cmd_buf);
445 /* Determine if a match means to apply the fix or not apply it */
447 if (p_fixd->fd_flags & FD_MACH_IFNOT)
458 /* Emit all the machine names. If there are more than one,
459 then we will insert " | \\\n" between the names */
463 const char* pz_mach = *(papz_machs++);
465 if (pz_mach == (const char*) NULL)
467 sprintf (pz, "%s%s", pz_sep, pz_mach);
472 /* Now emit the match and not-match actions and the esac */
474 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
477 The result will start either with 's' or 'r'. */
481 pz = run_shell (cmd_buf);
486 p_fixd->fd_flags |= FD_SKIP_TEST;
492 /* FOR every test for the fixup, ... */
494 while (--test_ct >= 0)
496 switch (p_test->type)
502 static int re_ct = REGEX_COUNT;
506 fputs ("out of RE's\n", stderr);
511 p_test->p_test_regex = p_re++;
512 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
513 "select test", p_fixd->fix_name);
518 while (p_fixd++, --fix_ct > 0);
522 /* * * * * * * * * * * * *
524 create_file Create the output modified file.
525 Input: the name of the file to create
526 Returns: a file pointer to the new, open file */
528 #if defined(S_IRUSR) && defined(S_IWUSR) && \
529 defined(S_IRGRP) && defined(S_IROTH)
531 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
533 # define S_IRALL 0644
536 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
537 defined(S_IROTH) && defined(S_IXOTH)
539 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
541 # define S_DIRALL 0755
550 char fname[MAXPATHLEN];
552 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
554 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
556 /* We may need to create the directories needed... */
557 if ((fd < 0) && (errno == ENOENT))
559 char *pz_dir = strchr (fname + 1, '/');
562 while (pz_dir != (char *) NULL)
565 if (stat (fname, &stbf) < 0)
567 mkdir (fname, S_IFDIR | S_DIRALL);
571 pz_dir = strchr (pz_dir + 1, '/');
574 /* Now, lets try the open again... */
575 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
579 fprintf (stderr, "Error %d (%s) creating %s\n",
580 errno, xstrerror (errno), fname);
584 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
585 pf = fdopen (fd, "w");
589 static const char hdr[] =
590 "/* DO NOT EDIT THIS FILE.\n\n"
591 " It has been auto-edited by fixincludes from /usr/include/%s\n"
592 " This had to be done to correct non-standard usages in the\n"
593 " original, manufacturer supplied header file. */\n\n";
595 fprintf (pf, hdr, pz_curr_file);
602 /* * * * * * * * * * * * *
604 test_test make sure a shell-style test expression passes.
605 Input: a pointer to the descriptor of the test to run and
606 the name of the file that we might want to fix
607 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
608 shell script we run. */
611 test_test (p_test, pz_test_file)
617 if ( test %s ) > /dev/null 2>&1\n\
625 static char cmd_buf[4096];
627 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
628 pz_res = run_shell (cmd_buf);
640 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
644 free ((void *) pz_res);
649 /* * * * * * * * * * * * *
651 egrep_test make sure an egrep expression is found in the file text.
652 Input: a pointer to the descriptor of the test to run and
653 the pointer to the contents of the file under suspicion
654 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
656 The caller may choose to reverse meaning if the sense of the test
660 egrep_test (pz_data, p_test)
665 if (p_test->p_test_regex == 0)
666 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
667 p_test->pz_test_text);
669 if (regexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
675 /* * * * * * * * * * * * *
677 quoted_file_exists Make sure that a file exists before we emit
678 the file name. If we emit the name, our invoking shell will try
679 to copy a non-existing file into the destination directory. */
682 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
687 char z[ MAXPATHLEN ];
689 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
690 pz = z + strlen ( z );
693 char ch = *pz_file++;
703 if (stat (z, &s) != 0)
705 return S_ISREG( s.st_mode );
710 /* * * * * * * * * * * * *
714 The syntax, `#include "file.h"' specifies that the compiler is to
715 search the local directory of the current file before the include
716 list. Consequently, if we have modified a header and stored it in
717 another directory, any files that are included by that modified
718 file in that fashion must also be copied into this new directory.
719 This routine finds those flavors of #include and for each one found
722 1. source directory of the original file
723 2. the relative path file name of the #includ-ed file
724 3. the full destination path for this file
726 Input: the text of the file, the file name and a pointer to the
727 match list where the match information was stored.
728 Result: internally nothing. The results are written to stdout
729 for interpretation by the invoking shell */
733 extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
735 const char *pz_fixed_file;
736 regmatch_t *p_re_match;
738 char *pz_dir_end = strrchr (pz_fixed_file, '/');
739 char *pz_incl_quot = pz_data;
741 if (VLEVEL( VERB_APPLIES ))
742 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
744 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
745 If there is none, then it is in our current directory, ".". */
747 if (pz_dir_end == (char *) NULL)
754 pz_incl_quot += p_re_match->rm_so;
756 /* Skip forward to the included file name */
757 while (ISSPACE (*pz_incl_quot))
759 /* ISSPACE() may evaluate is argument more than once! */
760 while (++pz_incl_quot, ISSPACE (*pz_incl_quot))
762 pz_incl_quot += sizeof ("include") - 1;
763 while (*pz_incl_quot++ != '"')
766 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
768 /* Print the source directory and the subdirectory
769 of the file in question. */
770 printf ("%s %s/", pz_src_dir, pz_fixed_file);
771 pz_dir_end = pz_incl_quot;
773 /* Append to the directory the relative path of the desired file */
774 while (*pz_incl_quot != '"')
775 putc (*pz_incl_quot++, stdout);
777 /* Now print the destination directory appended with the
778 relative path of the desired file */
779 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
780 while (*pz_dir_end != '"')
781 putc (*pz_dir_end++, stdout);
787 /* Find the next entry */
788 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
794 /* * * * * * * * * * * * *
796 Somebody wrote a *_fix subroutine that we must call.
800 internal_fix (read_fd, p_fixd)
808 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
814 pid_t childid = fork();
837 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
840 static int failCt = 0;
841 if ((errno != EAGAIN) || (++failCt > 10))
848 * Close our current stdin and stdout
850 close (STDIN_FILENO);
851 close (STDOUT_FILENO);
855 * Make the fd passed in the stdin, and the write end of
856 * the new pipe become the stdout.
858 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
859 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
861 apply_fix (p_fixd, pz_curr_file);
866 /* * * * * * * * * * * * *
868 This loop should only cycle for 1/2 of one loop.
869 "chain_open" starts a process that uses "read_fd" as
870 its stdin and returns the new fd this process will use
874 start_fixer (read_fd, p_fixd, pz_fix_file)
882 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
883 return internal_fix (read_fd, p_fixd);
885 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
886 pz_cmd = (char*)NULL;
889 tSCC z_cmd_fmt[] = "file='%s'\n%s";
890 pz_cmd = (char*)malloc (strlen (p_fixd->patch_args[2])
891 + sizeof( z_cmd_fmt )
892 + strlen( pz_fix_file ));
893 if (pz_cmd == (char*)NULL)
895 fputs ("allocation failure\n", stderr);
898 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
899 pz_cmd_save = p_fixd->patch_args[2];
900 p_fixd->patch_args[2] = pz_cmd;
903 /* Start a fix process, handing off the previous read fd for its
904 stdin and getting a new fd that reads from the fix process' stdout.
905 We normally will not loop, but we will up to 10 times if we keep
906 getting "EAGAIN" errors.
911 static int failCt = 0;
914 fd = chain_open (read_fd,
915 (t_pchar *) p_fixd->patch_args,
916 (process_chain_head == -1)
917 ? &process_chain_head : (pid_t *) NULL);
925 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
928 if ((errno != EAGAIN) || (++failCt > 10))
933 /* IF we allocated a shell script command,
934 THEN free it and restore the command format to the fix description */
935 if (pz_cmd != (char*)NULL)
937 free ((void*)pz_cmd);
938 p_fixd->patch_args[2] = pz_cmd_save;
945 /* * * * * * * * * * * * *
947 Process the potential fixes for a particular include file.
948 Input: the original text of the file and the file's name
949 Result: none. A new file may or may not be created. */
956 static const char z_failed[] = "not applying %s %s to %s - "
959 const char *pz_fname = pz_curr_file;
960 const char *pz_scan = p_fixd->file_list;
964 if (p_fixd->fd_flags & FD_SKIP_TEST)
967 /* IF there is a file name restriction,
968 THEN ensure the current file name matches one in the pattern */
970 if (pz_scan != (char *) NULL)
974 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
976 name_len = strlen (pz_fname);
980 pz_scan = strstr (pz_scan + 1, pz_fname);
981 /* IF we can't match the string at all,
983 if (pz_scan == (char *) NULL) {
985 if (VLEVEL( VERB_EVERYTHING ))
986 fprintf (stderr, "file %s not in list for %s\n",
987 pz_fname, p_fixd->fix_name );
992 /* IF the match is surrounded by the '|' markers,
993 THEN we found a full match -- time to run the tests */
995 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1000 /* FOR each test, see if it fails.
1001 IF it does fail, then we go on to the next test */
1003 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1007 switch (p_test->type)
1010 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1012 if (VLEVEL( VERB_EVERYTHING ))
1013 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1014 pz_fname, p_fixd->test_ct - test_ct);
1021 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1023 if (VLEVEL( VERB_EVERYTHING ))
1024 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1025 pz_fname, p_fixd->test_ct - test_ct);
1032 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1034 if (VLEVEL( VERB_EVERYTHING ))
1035 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1036 pz_fname, p_fixd->test_ct - test_ct);
1044 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1047 if (VLEVEL( VERB_EVERYTHING ))
1048 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1049 pz_fname, p_fixd->test_ct - test_ct);
1061 /* * * * * * * * * * * * *
1063 Write out a replacement file */
1066 write_replacement (p_fixd)
1069 const char* pz_text = p_fixd->patch_args[0];
1071 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1075 FILE* out_fp = create_file (pz_curr_file);
1076 fputs (pz_text, out_fp);
1082 /* * * * * * * * * * * * *
1084 We have work to do. Read back in the output
1085 of the filtering chain. Compare each byte as we read it with
1086 the contents of the original file. As soon as we find any
1087 difference, we will create the output file, write out all
1088 the matched text and then copy any remaining data from the
1089 output of the filter chain.
1092 test_for_changes (read_fd)
1095 FILE *in_fp = fdopen (read_fd, "r");
1096 FILE *out_fp = (FILE *) NULL;
1097 char *pz_cmp = pz_curr_data;
1110 /* IF we are emitting the output
1111 THEN emit this character, too.
1113 if (out_fp != (FILE *) NULL)
1116 /* ELSE if this character does not match the original,
1117 THEN now is the time to start the output.
1119 else if (ch != *pz_cmp)
1121 out_fp = create_file (pz_curr_file);
1126 /* IF there are matched data, write the matched part now. */
1127 if (pz_cmp != pz_curr_data)
1128 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1130 /* Emit the current unmatching character */
1134 /* ELSE the character matches. Advance the compare ptr */
1138 /* IF we created the output file, ... */
1139 if (out_fp != (FILE *) NULL)
1143 /* Close the file and see if we have to worry about
1144 `#include "file.h"' constructs. */
1146 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1147 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1151 close (read_fd); /* probably redundant, but I'm paranoid */
1155 /* * * * * * * * * * * * *
1157 Process the potential fixes for a particular include file.
1158 Input: the original text of the file and the file's name
1159 Result: none. A new file may or may not be created. */
1164 static char env_current_file[1024];
1165 tFixDesc *p_fixd = fixDescList;
1166 int todo_ct = FIX_COUNT;
1168 int num_children = 0;
1170 if (access (pz_curr_file, R_OK) != 0)
1173 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1174 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1175 erno, xstrerror (erno));
1179 pz_curr_data = load_file (pz_curr_file);
1180 if (pz_curr_data == (char *) NULL)
1186 if (VLEVEL( VERB_PROGRESS ) && have_tty)
1187 fprintf (stderr, "%6d %-50s \r", data_map_size, pz_curr_file );
1189 process_chain_head = NOPROCESS;
1191 /* For every fix in our fix list, ... */
1192 for (; todo_ct > 0; p_fixd++, todo_ct--)
1194 if (! fix_applies (p_fixd))
1197 if (VLEVEL( VERB_APPLIES ))
1198 fprintf (stderr, "Applying %-24s to %s\n",
1199 p_fixd->fix_name, pz_curr_file);
1201 if (p_fixd->fd_flags & FD_REPLACEMENT)
1203 write_replacement (p_fixd);
1208 /* IF we do not have a read pointer,
1209 THEN this is the first fix for the current file.
1210 Open the source file. That will be used as stdin for
1211 the first fix. Any subsequent fixes will use the
1212 stdout descriptor of the previous fix for its stdin. */
1216 read_fd = open (pz_curr_file, O_RDONLY);
1219 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1220 xstrerror (errno), pz_curr_file);
1221 exit (EXIT_FAILURE);
1224 /* Ensure we do not get duplicate output */
1229 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1233 /* IF we have a read-back file descriptor,
1234 THEN check for changes and write output if changed. */
1238 test_for_changes (read_fd);
1240 apply_ct += num_children;
1242 /* Wait for child processes created by chain_open()
1243 to avoid leaving zombies. */
1245 wait ((int *) NULL);
1246 } while (--num_children > 0);