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";
215 if (strcmp (argv[1], "-v") == 0)
217 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
219 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
220 errno, xstrerror (errno), argv[1] );
226 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
231 static const char var[] = "TARGET_MACHINE";
232 pz_machine = getenv (var);
233 if (pz_machine == (char *) NULL)
235 fprintf (stderr, var_not_found, var);
241 static const char var[] = "DESTDIR";
242 pz_dest_dir = getenv (var);
243 if (pz_dest_dir == (char *) NULL)
245 fprintf (stderr, var_not_found, var);
251 static const char var[] = "SRCDIR";
252 pz_src_dir = getenv (var);
253 if (pz_src_dir == (char *) NULL)
255 fprintf (stderr, var_not_found, var);
261 static const char var[] = "VERBOSE";
262 char* pz = getenv (var);
263 if (pz != (char *) NULL)
266 verbose_level = (te_verbose)atoi( pz );
271 verbose_level = VERB_SILENT; break;
275 verbose_level = VERB_FIXES; break;
279 verbose_level = VERB_APPLIES; break;
283 verbose_level = VERB_PROGRESS; break;
287 verbose_level = VERB_TESTS; break;
291 verbose_level = VERB_EVERYTHING; break;
297 static const char var[] = "FIND_BASE";
298 char *pz = getenv (var);
299 if (pz == (char *) NULL)
301 fprintf (stderr, var_not_found, var);
304 while ((pz[0] == '.') && (pz[1] == '/'))
306 if ((pz[0] != '.') || (pz[1] != NUL))
307 find_base_len = strlen( pz );
310 /* Compile all the regular expressions now.
311 That way, it is done only once for the whole run.
315 signal (SIGQUIT, SIG_IGN);
317 signal (SIGIOT, SIG_IGN);
319 signal (SIGPIPE, SIG_IGN);
320 signal (SIGALRM, SIG_IGN);
321 signal (SIGTERM, SIG_IGN);
324 /* * * * * * * * * * * * *
326 load_file loads all the contents of a file into malloc-ed memory.
327 Its argument is the name of the file to read in; the returned
328 result is the NUL terminated contents of the file. The file
329 is presumed to be an ASCII text file containing no NULs. */
337 if (stat (fname, &stbf) != 0)
340 fprintf (stderr, "error %d (%s) stat-ing %s\n",
341 errno, xstrerror (errno), fname );
342 return (char *) NULL;
344 if (stbf.st_size == 0)
347 data_map_size = stbf.st_size+1;
348 data_map_fd = open (fname, O_RDONLY);
349 ttl_data_size += data_map_size-1;
354 fprintf (stderr, "error %d (%s) opening %s for read\n",
355 errno, xstrerror (errno), fname);
359 #ifdef HAVE_MMAP_FILE
360 curr_data_mapped = BOOL_TRUE;
361 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE,
363 if (res == (char*)BAD_ADDR)
365 curr_data_mapped = BOOL_FALSE;
366 res = load_file_data ( fdopen (data_map_fd, "r"));
369 curr_data_mapped = BOOL_FALSE;
370 res = load_file_data ( fdopen (data_map_fd, "r"));
377 /* * * * * * * * * * * * *
379 run_compiles run all the regexp compiles for all the fixes once.
384 tFixDesc *p_fixd = fixDescList;
385 int fix_ct = FIX_COUNT;
389 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
391 if (p_re == (regex_t *) NULL)
393 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
394 REGEX_COUNT * sizeof (regex_t));
398 /* Make sure compile_re does not stumble across invalid data */
400 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
401 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
403 compile_re (incl_quote_pat, &incl_quote_re, 1,
404 "quoted include", "run_compiles");
406 /* Allow machine name tests to be ignored (testing, mainly) */
408 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
409 pz_machine = (char*)NULL;
411 /* FOR every fixup, ... */
414 p_test = p_fixd->p_test_desc;
415 test_ct = p_fixd->test_ct;
417 /* IF the machine type pointer is not NULL (we are not in test mode)
418 AND this test is for or not done on particular machines
421 if ( (pz_machine != NULL)
422 && (p_fixd->papz_machs != (const char**) NULL) )
424 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
426 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
427 tSCC skip[] = "skip"; /* 4 bytes */
428 tSCC run[] = "run"; /* 3 bytes */
429 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
431 const char **papz_machs = p_fixd->papz_machs;
436 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
438 /* Start the case statement */
440 sprintf (cmd_buf, case_fmt, pz_machine);
441 pz = cmd_buf + strlen (cmd_buf);
443 /* Determine if a match means to apply the fix or not apply it */
445 if (p_fixd->fd_flags & FD_MACH_IFNOT)
456 /* Emit all the machine names. If there are more than one,
457 then we will insert " | \\\n" between the names */
461 const char* pz_mach = *(papz_machs++);
463 if (pz_mach == (const char*) NULL)
465 sprintf (pz, "%s%s", pz_sep, pz_mach);
470 /* Now emit the match and not-match actions and the esac */
472 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
475 The result will start either with 's' or 'r'. */
479 pz = run_shell (cmd_buf);
484 p_fixd->fd_flags |= FD_SKIP_TEST;
490 /* FOR every test for the fixup, ... */
492 while (--test_ct >= 0)
494 switch (p_test->type)
500 static int re_ct = REGEX_COUNT;
504 fputs ("out of RE's\n", stderr);
509 p_test->p_test_regex = p_re++;
510 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
511 "select test", p_fixd->fix_name);
516 while (p_fixd++, --fix_ct > 0);
520 /* * * * * * * * * * * * *
522 create_file Create the output modified file.
523 Input: the name of the file to create
524 Returns: a file pointer to the new, open file */
526 #if defined(S_IRUSR) && defined(S_IWUSR) && \
527 defined(S_IRGRP) && defined(S_IROTH)
529 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
531 # define S_IRALL 0644
534 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
535 defined(S_IROTH) && defined(S_IXOTH)
537 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
539 # define S_DIRALL 0755
548 char fname[MAXPATHLEN];
550 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
552 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
554 /* We may need to create the directories needed... */
555 if ((fd < 0) && (errno == ENOENT))
557 char *pz_dir = strchr (fname + 1, '/');
560 while (pz_dir != (char *) NULL)
563 if (stat (fname, &stbf) < 0)
565 mkdir (fname, S_IFDIR | S_DIRALL);
569 pz_dir = strchr (pz_dir + 1, '/');
572 /* Now, lets try the open again... */
573 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
577 fprintf (stderr, "Error %d (%s) creating %s\n",
578 errno, xstrerror (errno), fname);
582 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
583 pf = fdopen (fd, "w");
587 static const char hdr[] =
588 "/* DO NOT EDIT THIS FILE.\n\n"
589 " It has been auto-edited by fixincludes from /usr/include/%s\n"
590 " This had to be done to correct non-standard usages in the\n"
591 " original, manufacturer supplied header file. */\n\n";
593 fprintf (pf, hdr, pz_curr_file);
600 /* * * * * * * * * * * * *
602 test_test make sure a shell-style test expression passes.
603 Input: a pointer to the descriptor of the test to run and
604 the name of the file that we might want to fix
605 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
606 shell script we run. */
609 test_test (p_test, pz_test_file)
615 if ( test %s ) > /dev/null 2>&1\n\
623 static char cmd_buf[4096];
625 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
626 pz_res = run_shell (cmd_buf);
638 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
642 free ((void *) pz_res);
647 /* * * * * * * * * * * * *
649 egrep_test make sure an egrep expression is found in the file text.
650 Input: a pointer to the descriptor of the test to run and
651 the pointer to the contents of the file under suspicion
652 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
654 The caller may choose to reverse meaning if the sense of the test
658 egrep_test (pz_data, p_test)
663 if (p_test->p_test_regex == 0)
664 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
665 p_test->pz_test_text);
667 if (regexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
673 /* * * * * * * * * * * * *
675 quoted_file_exists Make sure that a file exists before we emit
676 the file name. If we emit the name, our invoking shell will try
677 to copy a non-existing file into the destination directory. */
680 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
685 char z[ MAXPATHLEN ];
687 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
688 pz = z + strlen ( z );
691 char ch = *pz_file++;
701 if (stat (z, &s) != 0)
703 return S_ISREG( s.st_mode );
708 /* * * * * * * * * * * * *
712 The syntax, `#include "file.h"' specifies that the compiler is to
713 search the local directory of the current file before the include
714 list. Consequently, if we have modified a header and stored it in
715 another directory, any files that are included by that modified
716 file in that fashion must also be copied into this new directory.
717 This routine finds those flavors of #include and for each one found
720 1. source directory of the original file
721 2. the relative path file name of the #includ-ed file
722 3. the full destination path for this file
724 Input: the text of the file, the file name and a pointer to the
725 match list where the match information was stored.
726 Result: internally nothing. The results are written to stdout
727 for interpretation by the invoking shell */
731 extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
733 const char *pz_fixed_file;
734 regmatch_t *p_re_match;
736 char *pz_dir_end = strrchr (pz_fixed_file, '/');
737 char *pz_incl_quot = pz_data;
739 if (VLEVEL( VERB_APPLIES ))
740 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
742 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
743 If there is none, then it is in our current directory, ".". */
745 if (pz_dir_end == (char *) NULL)
752 pz_incl_quot += p_re_match->rm_so;
754 /* Skip forward to the included file name */
755 while (ISSPACE (*pz_incl_quot))
757 /* ISSPACE() may evaluate is argument more than once! */
758 while (++pz_incl_quot, ISSPACE (*pz_incl_quot))
760 pz_incl_quot += sizeof ("include") - 1;
761 while (*pz_incl_quot++ != '"')
764 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
766 /* Print the source directory and the subdirectory
767 of the file in question. */
768 printf ("%s %s/", pz_src_dir, pz_fixed_file);
769 pz_dir_end = pz_incl_quot;
771 /* Append to the directory the relative path of the desired file */
772 while (*pz_incl_quot != '"')
773 putc (*pz_incl_quot++, stdout);
775 /* Now print the destination directory appended with the
776 relative path of the desired file */
777 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
778 while (*pz_dir_end != '"')
779 putc (*pz_dir_end++, stdout);
785 /* Find the next entry */
786 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
792 /* * * * * * * * * * * * *
794 Somebody wrote a *_fix subroutine that we must call.
798 internal_fix (read_fd, p_fixd)
806 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
812 pid_t childid = fork();
835 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
838 static int failCt = 0;
839 if ((errno != EAGAIN) || (++failCt > 10))
846 * Close our current stdin and stdout
848 close (STDIN_FILENO);
849 close (STDOUT_FILENO);
853 * Make the fd passed in the stdin, and the write end of
854 * the new pipe become the stdout.
856 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
857 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
859 apply_fix (p_fixd, pz_curr_file);
864 /* * * * * * * * * * * * *
866 This loop should only cycle for 1/2 of one loop.
867 "chain_open" starts a process that uses "read_fd" as
868 its stdin and returns the new fd this process will use
872 start_fixer (read_fd, p_fixd, pz_fix_file)
880 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
881 return internal_fix (read_fd, p_fixd);
883 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
884 pz_cmd = (char*)NULL;
887 tSCC z_cmd_fmt[] = "file='%s'\n%s";
888 pz_cmd = (char*)malloc (strlen (p_fixd->patch_args[2])
889 + sizeof( z_cmd_fmt )
890 + strlen( pz_fix_file ));
891 if (pz_cmd == (char*)NULL)
893 fputs ("allocation failure\n", stderr);
896 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
897 pz_cmd_save = p_fixd->patch_args[2];
898 p_fixd->patch_args[2] = pz_cmd;
901 /* Start a fix process, handing off the previous read fd for its
902 stdin and getting a new fd that reads from the fix process' stdout.
903 We normally will not loop, but we will up to 10 times if we keep
904 getting "EAGAIN" errors.
909 static int failCt = 0;
912 fd = chain_open (read_fd,
913 (t_pchar *) p_fixd->patch_args,
914 (process_chain_head == -1)
915 ? &process_chain_head : (pid_t *) NULL);
923 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
926 if ((errno != EAGAIN) || (++failCt > 10))
931 /* IF we allocated a shell script command,
932 THEN free it and restore the command format to the fix description */
933 if (pz_cmd != (char*)NULL)
935 free ((void*)pz_cmd);
936 p_fixd->patch_args[2] = pz_cmd_save;
943 /* * * * * * * * * * * * *
945 Process the potential fixes for a particular include file.
946 Input: the original text of the file and the file's name
947 Result: none. A new file may or may not be created. */
954 static const char z_failed[] = "not applying %s %s to %s - "
957 const char *pz_fname = pz_curr_file;
958 const char *pz_scan = p_fixd->file_list;
962 if (p_fixd->fd_flags & FD_SKIP_TEST)
965 /* IF there is a file name restriction,
966 THEN ensure the current file name matches one in the pattern */
968 if (pz_scan != (char *) NULL)
972 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
974 name_len = strlen (pz_fname);
978 pz_scan = strstr (pz_scan + 1, pz_fname);
979 /* IF we can't match the string at all,
981 if (pz_scan == (char *) NULL) {
983 if (VLEVEL( VERB_EVERYTHING ))
984 fprintf (stderr, "file %s not in list for %s\n",
985 pz_fname, p_fixd->fix_name );
990 /* IF the match is surrounded by the '|' markers,
991 THEN we found a full match -- time to run the tests */
993 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
998 /* FOR each test, see if it fails.
999 IF it does fail, then we go on to the next test */
1001 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1005 switch (p_test->type)
1008 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1010 if (VLEVEL( VERB_EVERYTHING ))
1011 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1012 pz_fname, p_fixd->test_ct - test_ct);
1019 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1021 if (VLEVEL( VERB_EVERYTHING ))
1022 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1023 pz_fname, p_fixd->test_ct - test_ct);
1030 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1032 if (VLEVEL( VERB_EVERYTHING ))
1033 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1034 pz_fname, p_fixd->test_ct - test_ct);
1042 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1045 if (VLEVEL( VERB_EVERYTHING ))
1046 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1047 pz_fname, p_fixd->test_ct - test_ct);
1059 /* * * * * * * * * * * * *
1061 Write out a replacement file */
1064 write_replacement (p_fixd)
1067 const char* pz_text = p_fixd->patch_args[0];
1069 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1073 FILE* out_fp = create_file (pz_curr_file);
1074 fputs (pz_text, out_fp);
1080 /* * * * * * * * * * * * *
1082 We have work to do. Read back in the output
1083 of the filtering chain. Compare each byte as we read it with
1084 the contents of the original file. As soon as we find any
1085 difference, we will create the output file, write out all
1086 the matched text and then copy any remaining data from the
1087 output of the filter chain.
1090 test_for_changes (read_fd)
1093 FILE *in_fp = fdopen (read_fd, "r");
1094 FILE *out_fp = (FILE *) NULL;
1095 char *pz_cmp = pz_curr_data;
1108 /* IF we are emitting the output
1109 THEN emit this character, too.
1111 if (out_fp != (FILE *) NULL)
1114 /* ELSE if this character does not match the original,
1115 THEN now is the time to start the output.
1117 else if (ch != *pz_cmp)
1119 out_fp = create_file (pz_curr_file);
1124 /* IF there are matched data, write the matched part now. */
1125 if (pz_cmp != pz_curr_data)
1126 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1128 /* Emit the current unmatching character */
1132 /* ELSE the character matches. Advance the compare ptr */
1136 /* IF we created the output file, ... */
1137 if (out_fp != (FILE *) NULL)
1141 /* Close the file and see if we have to worry about
1142 `#include "file.h"' constructs. */
1144 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1145 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1149 close (read_fd); /* probably redundant, but I'm paranoid */
1153 /* * * * * * * * * * * * *
1155 Process the potential fixes for a particular include file.
1156 Input: the original text of the file and the file's name
1157 Result: none. A new file may or may not be created. */
1162 static char env_current_file[1024];
1163 tFixDesc *p_fixd = fixDescList;
1164 int todo_ct = FIX_COUNT;
1166 int num_children = 0;
1168 if (access (pz_curr_file, R_OK) != 0)
1171 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1172 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1173 erno, xstrerror (erno));
1177 pz_curr_data = load_file (pz_curr_file);
1178 if (pz_curr_data == (char *) NULL)
1184 if (VLEVEL( VERB_PROGRESS ) && have_tty)
1185 fprintf (stderr, "%6d %-50s \r", data_map_size, pz_curr_file );
1187 process_chain_head = NOPROCESS;
1189 /* For every fix in our fix list, ... */
1190 for (; todo_ct > 0; p_fixd++, todo_ct--)
1192 if (! fix_applies (p_fixd))
1195 if (VLEVEL( VERB_APPLIES ))
1196 fprintf (stderr, "Applying %-24s to %s\n",
1197 p_fixd->fix_name, pz_curr_file);
1199 if (p_fixd->fd_flags & FD_REPLACEMENT)
1201 write_replacement (p_fixd);
1206 /* IF we do not have a read pointer,
1207 THEN this is the first fix for the current file.
1208 Open the source file. That will be used as stdin for
1209 the first fix. Any subsequent fixes will use the
1210 stdout descriptor of the previous fix for its stdin. */
1214 read_fd = open (pz_curr_file, O_RDONLY);
1217 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1218 xstrerror (errno), pz_curr_file);
1219 exit (EXIT_FAILURE);
1222 /* Ensure we do not get duplicate output */
1227 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1231 /* IF we have a read-back file descriptor,
1232 THEN check for changes and write output if changed. */
1236 test_for_changes (read_fd);
1238 apply_ct += num_children;
1240 /* Wait for child processes created by chain_open()
1241 to avoid leaving zombies. */
1243 wait ((int *) NULL);
1244 } while (--num_children > 0);