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 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. */
25 #include "auto-host.h"
27 #include "gansidecl.h"
31 #include "gnu-regex.h"
34 static const char program_id[] = "fixincl version 1.0";
36 #define MINIMUM_MAXIMUM_LINES 128
38 /* If this particular system's header files define the macro `MAXPATHLEN',
39 we happily take advantage of it; otherwise we use a value which ought
40 to be large enough. */
42 # define MAXPATHLEN 4096
44 #define NAME_TABLE_SIZE (MINIMUM_MAXIMUM_LINES * MAXPATHLEN)
47 # define EXIT_SUCCESS 0
50 # define EXIT_FAILURE 1
55 #define tSCC static const char
56 #define tCC const char
57 #define tSC static char
59 typedef int t_success;
65 #define SUCCEEDED(p) ((p) == SUCCESS)
66 #define SUCCESSFUL(p) SUCCEEDED (p)
67 #define FAILED(p) ((p) < SUCCESS)
68 #define HADGLITCH(p) ((p) > SUCCESS)
74 Each fix may have associated tests that determine
75 whether the fix needs to be applied or not.
76 Each test has a type (from the te_test_type enumeration);
77 associated test text; and, if the test is TT_EGREP or
78 the negated form TT_NEGREP, a pointer to the compiled
79 version of the text string.
84 TT_TEST, TT_EGREP, TT_NEGREP
87 typedef struct test_desc tTestDesc;
92 const char *pz_test_text;
93 regex_t *p_test_regex;
96 typedef struct patch_desc tPatchDesc;
100 Everything you ever wanted to know about how to apply
101 a particular fix (which files, how to qualify them,
102 how to actually make the fix, etc...)
105 #define FD_MACH_ONLY 0x0000
106 #define FD_MACH_IFNOT 0x0001
107 #define FD_SHELL_SCRIPT 0x0002
108 #define FD_SKIP_TEST 0x8000
110 typedef struct fix_desc tFixDesc;
113 const char* fix_name; /* Name of the fix */
114 const char* file_list; /* List of files it applies to */
115 const char** papz_machs; /* List of machine/os-es it applies to */
119 tTestDesc* p_test_desc;
120 const char** patch_args;
123 /* Working environment strings. Essentially, invocation 'options'. */
124 char *pz_dest_dir = NULL;
125 char *pz_src_dir = NULL;
126 char *pz_machine = NULL;
127 char *pz_find_base = NULL;
128 int find_base_len = 0;
130 pid_t process_chain_head = (pid_t) -1;
132 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
133 regex_t incl_quote_re;
135 char *load_file _P_((const char *));
136 void process _P_((char *, const char *));
137 void run_compiles ();
138 void wait_for_pid _P_(( pid_t ));
143 /* * * * * * * * * * * * * * * * * * *
152 static const char gnu_lib_mark[] =
153 "This file is part of the GNU C Library";
155 #ifndef NO_BOGOSITY_LIMITS
156 # define BOGUS_LIMIT MINIMUM_MAXIMUM_LINES
160 char *apz_names[BOGUS_LIMIT];
163 /* Before anything else, ensure we can allocate our file name buffer. */
164 file_name_buf = (char *) malloc (NAME_TABLE_SIZE);
165 if (file_name_buf == (char *) NULL)
167 fprintf (stderr, "fixincl cannot allocate 0x%08X bytes\n",
178 if (strcmp (argv[1], "-v") == 0)
180 static const char zFmt[] = "echo '%s'";
182 /* The 'version' option is really used to test that:
183 1. The program loads correctly (no missing libraries)
184 2. we can correctly run our server shell process
185 3. that we can compile all the regular expressions.
188 sprintf (file_name_buf, zFmt, program_id);
189 fputs (file_name_buf + 5, stdout);
190 exit (strcmp (run_shell (file_name_buf), program_id));
192 freopen (argv[1], "r", stdin);
196 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
202 #ifndef NO_BOGOSITY_LIMITS
203 /* Some systems only allow so many calls to fork(2).
204 This is inadequate for this program. Consequently,
205 we must let a grandfather process spawn children
206 that then spawn all the processes that do the real work.
213 char *pz_buf = file_name_buf;
215 /* Only the parent process can read from stdin without confusing
216 the world. (How does the child tell the parent to skip
217 forward? Pipes and files behave differently.) */
219 while ( (file_name_ct < BOGUS_LIMIT)
220 && (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN)))
222 if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL)
224 while (ISSPACE (*pz_buf))
226 if ((*pz_buf == '\0') || (*pz_buf == '#'))
228 apz_names[file_name_ct++] = pz_buf;
229 pz_buf += strlen (pz_buf);
230 while (ISSPACE (pz_buf[-1]))
236 /* IF we did not get any files this time thru
237 THEN we must be done. */
238 if (file_name_ct == 0)
245 pid_t child = fork ();
246 if (child == NULLPROCESS)
249 if (child == NOPROCESS)
251 fprintf (stderr, "Error %d (%s) forking in main\n",
252 errno, strerror (errno));
257 fprintf (stderr, "Waiting for %d to complete %d files\n",
258 child, file_name_ct);
261 wait_for_pid( child, file_name_ct );
265 /*#*/ error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
268 /* For every file specified in stdandard in
269 (except as throttled for bogus reasons)...
271 for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++)
274 char *pz_file_name = apz_names[loop_ct];
276 if (access (pz_file_name, R_OK) != 0)
279 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
280 pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
281 erno, strerror (erno));
283 else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
285 if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
286 process (pz_data, pz_file_name);
287 free ((void *) pz_data);
295 /* * * * * * * * * * * * */
300 static const char var_not_found[] =
301 "fixincl ERROR: %s environment variable not defined\n";
304 static const char var[] = "TARGET_MACHINE";
305 pz_machine = getenv (var);
306 if (pz_machine == (char *) NULL)
308 fprintf (stderr, var_not_found, var);
314 static const char var[] = "DESTDIR";
315 pz_dest_dir = getenv (var);
316 if (pz_dest_dir == (char *) NULL)
318 fprintf (stderr, var_not_found, var);
324 static const char var[] = "SRCDIR";
325 pz_src_dir = getenv (var);
326 if (pz_src_dir == (char *) NULL)
328 fprintf (stderr, var_not_found, var);
334 static const char var[] = "FIND_BASE";
335 pz_find_base = getenv (var);
336 if (pz_find_base == (char *) NULL)
338 fprintf (stderr, var_not_found, var);
341 find_base_len = strlen( pz_find_base );
344 /* Compile all the regular expressions now.
345 That way, it is done only once for the whole run.
349 signal (SIGQUIT, SIG_IGN);
350 signal (SIGIOT, SIG_IGN);
351 signal (SIGPIPE, SIG_IGN);
352 signal (SIGALRM, SIG_IGN);
353 signal (SIGTERM, SIG_IGN);
356 Make sure that if we opened a server process, we close it now.
357 This is the grandparent process. We don't need the server anymore
358 and our children should make their own. */
361 (void)wait ( (int*)NULL );
364 /* * * * * * * * * * * * *
366 wait_for_pid - Keep calling `wait(2)' until it returns
367 the process id we are looking for. Not every system has
368 `waitpid(2)'. We also ensure that the children exit with success. */
371 wait_for_pid(child, file_name_ct)
377 pid_t dead_kid = wait (&status);
379 if (dead_kid == child)
381 if (! WIFEXITED( status ))
383 fprintf (stderr, "child process %d is hung on signal %d\n",
384 child, WSTOPSIG( status ));
387 if (WEXITSTATUS( status ) != 0)
389 fprintf (stderr, "child process %d exited with status %d\n",
390 child, WEXITSTATUS( status ));
393 break; /* normal child completion */
397 IF there is an error, THEN see if it is retryable.
398 If it is not retryable, then break out of this loop. */
399 if (dead_kid == NOPROCESS)
407 fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
408 errno, strerror( errno ), child );
411 case ECHILD: /* no children to wait for?? */
419 /* * * * * * * * * * * * *
421 load_file loads all the contents of a file into malloc-ed memory.
422 Its argument is the name of the file to read in; the returned
423 result is the NUL terminated contents of the file. The file
424 is presumed to be an ASCII text file containing no NULs. */
426 load_file (pz_file_name)
427 const char *pz_file_name;
435 if (stat (pz_file_name, &stbf) != 0)
437 fprintf (stderr, "error %d (%s) stat-ing %s\n",
438 errno, strerror (errno), pz_file_name);
439 return (char *) NULL;
441 file_size = stbf.st_size;
444 return (char *) NULL;
446 pz_data = (char *) malloc ((file_size + 16) & ~0x00F);
447 if (pz_data == (char *) NULL)
449 fprintf (stderr, "error: could not malloc %d bytes\n",
455 FILE *fp = fopen (pz_file_name, "r");
456 size_t size_left = file_size;
457 char *read_ptr = pz_data;
459 if (fp == (FILE *) NULL)
461 fprintf (stderr, "error %d (%s) opening %s\n", errno,
462 strerror (errno), pz_file_name);
463 free ((void *) pz_data);
464 return (char *) NULL;
469 size_t sizeRead = fread ((void *) read_ptr, 1, size_left, fp);
480 fprintf (stderr, "error %d (%s) reading %s\n", err,
481 strerror (err), pz_file_name);
482 free ((void *) pz_data);
484 return (char *) NULL;
488 read_ptr += sizeRead;
489 size_left -= sizeRead;
491 while (size_left != 0);
500 /* * * * * * * * * * * * *
502 run_compiles run all the regexp compiles for all the fixes once.
507 tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\
508 \texpr = `%s'\n\terror %s\n";
509 tFixDesc *p_fixd = fixDescList;
510 int fix_ct = FIX_COUNT;
513 int re_ct = REGEX_COUNT;
515 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
517 if (p_re == (regex_t *) NULL)
519 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
520 REGEX_COUNT * sizeof (regex_t));
524 /* Make sure re_compile_pattern does not stumble across invalid
527 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
528 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
530 /* The patterns we search for are all egrep patterns.
531 In the shell version of this program, we invoke egrep
532 with the supplied pattern. Here, we will run
533 re_compile_pattern, but it must be using the same rules. */
535 re_set_syntax (RE_SYNTAX_EGREP);
536 pz_err = re_compile_pattern (incl_quote_pat, sizeof (incl_quote_pat)-1,
538 if (pz_err != (char *) NULL)
540 fprintf (stderr, z_bad_comp, "quoted include", "run_compiles",
541 incl_quote_pat, pz_err);
545 /* FOR every fixup, ... */
548 p_test = p_fixd->p_test_desc;
549 test_ct = p_fixd->test_ct;
551 /* IF the machine type pointer is not NULL (we are not in test mode)
552 AND this test is for or not done on particular machines
555 if ( (pz_machine != NULL)
556 && (p_fixd->papz_machs != (const char**) NULL) )
558 const char **papz_machs = p_fixd->papz_machs;
559 char *pz = file_name_buf;
563 tSCC skip[] = "skip";
566 /* Construct a shell script that looks like this:
568 case our-cpu-platform-os in
569 tests-cpu-platform-os-pattern )
575 where 'run' and 'skip' may be reversed, depending on
576 the sense of the test. */
578 sprintf (pz, "case %s in\n", pz_machine);
581 if (p_fixd->fd_flags & FD_MACH_IFNOT)
592 /* FOR any additional machine names to test for,
593 insert the " | \\\n" glue and the machine pattern. */
597 const char* pz_mach = *(papz_machs++);
599 if (pz_mach == (const char*) NULL)
601 sprintf (pz, "%s %s", pz_sep, pz_mach);
605 sprintf (pz, " )\n echo %s ;;\n * )\n echo %s ;;\nesac",
606 pz_if_true, pz_if_false);
609 The result will start either with 's' or 'r'. */
613 pz = run_shell (file_name_buf);
618 p_fixd->fd_flags |= FD_SKIP_TEST;
624 /* FOR every test for the fixup, ... */
626 while (--test_ct >= 0)
628 switch (p_test->type)
632 /* You might consider putting the following under #ifdef.
633 The number of re's used is computed by autogen.
634 So, it is static and known at compile time. */
638 fputs ("out of RE's\n", stderr);
642 p_test->p_test_regex = p_re++;
643 pz_err = re_compile_pattern (p_test->pz_test_text,
644 strlen (p_test->pz_test_text),
645 p_test->p_test_regex);
646 if (pz_err != (char *) NULL)
648 fprintf (stderr, z_bad_comp, "select test", p_fixd->fix_name,
649 p_test->pz_test_text, pz_err);
656 while (p_fixd++, --fix_ct > 0);
660 /* * * * * * * * * * * * *
662 create_file Create the output modified file.
663 Input: the name of the file to create
664 Returns: a file pointer to the new, open file */
666 #define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
669 create_file (pz_file_name)
670 const char *pz_file_name;
674 char fname[MAXPATHLEN];
677 if (strncmp( pz_file_name, pz_find_base, find_base_len ) != 0)
679 fprintf (stderr, "Error: input file %s does not match %s/*\n",
680 pz_file_name, pz_find_base );
685 sprintf (fname, "%s/%s", pz_dest_dir, pz_file_name + find_base_len);
687 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
689 /* We may need to create the directories needed... */
690 if ((fd < 0) && (errno == ENOENT))
692 char *pz_dir = strchr (fname + 1, '/');
695 while (pz_dir != (char *) NULL)
698 if (stat (fname, &stbf) < 0)
700 mkdir (fname, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP
701 | S_IROTH | S_IXOTH);
705 pz_dir = strchr (pz_dir + 1, '/');
708 /* Now, lets try the open again... */
709 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
713 fprintf (stderr, "Error %d (%s) creating %s\n",
714 errno, strerror (errno), fname);
717 fprintf (stderr, "Fixed: %s\n", pz_file_name);
718 pf = fdopen (fd, "w");
722 static const char hdr[] =
723 "/* DO NOT EDIT THIS FILE.\n\n"
724 " It has been auto-edited by fixincludes from /usr/include/%s\n"
725 " This had to be done to correct non-standard usages in the\n"
726 " original, manufacturer supplied header file. */\n\n";
728 fprintf (pf, hdr, pz_file_name);
735 /* * * * * * * * * * * * *
737 test_test make sure a shell-style test expression passes.
738 Input: a pointer to the descriptor of the test to run and
739 the name of the file that we might want to fix
740 Result: SUCCESS or FAILURE, depending on the result of the
741 shell script we run. */
744 test_test (p_test, pz_file_name)
750 if ( test %s ) > /dev/null 2>&1\n\
756 t_success res = FAILURE;
758 static char cmd_buf[4096];
760 sprintf (cmd_buf, cmd_fmt, pz_file_name, p_test->pz_test_text);
761 pz_res = run_shell (cmd_buf);
764 free ((void *) pz_res);
769 /* * * * * * * * * * * * *
771 egrep_test make sure an egrep expression is found in the file text.
772 Input: a pointer to the descriptor of the test to run and
773 the pointer to the contents of the file under suspicion
774 Result: SUCCESS if the pattern is found, FAILURE otherwise
776 The caller may choose 'FAILURE' as 'SUCCESS' if the sense of the test
780 egrep_test (pz_data, p_test)
787 if (p_test->p_test_regex == 0)
788 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
789 p_test->pz_test_text);
791 if (regexec (p_test->p_test_regex, pz_data, 1, &match, 0) == 0)
797 /* * * * * * * * * * * * *
799 quoted_file_exists Make sure that a file exists before we emit
800 the file name. If we emit the name, our invoking shell will try
801 to copy a non-existing file into the destination directory. */
804 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
809 char z[ MAXPATHLEN ];
811 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
812 pz = z + strlen ( z );
815 char ch = *pz_file++;
825 if (stat (z, &s) != 0)
827 return S_ISREG( s.st_mode );
832 /* * * * * * * * * * * * *
836 The syntax, `#include "file.h"' specifies that the compiler is to
837 search the local directory of the current file before the include
838 list. Consequently, if we have modified a header and stored it in
839 another directory, any files that are included by that modified
840 file in that fashion must also be copied into this new directory.
841 This routine finds those flavors of #include and for each one found
844 1. source directory of the original file
845 2. the relative path file name of the #includ-ed file
846 3. the full destination path for this file
848 Input: the text of the file, the file name and a pointer to the
849 match list where the match information was stored.
850 Result: internally nothing. The results are written to stdout
851 for interpretation by the invoking shell */
855 extract_quoted_files (pz_data, pz_file_name, p_re_match)
857 const char *pz_file_name;
858 regmatch_t *p_re_match;
860 char *pz_dir_end = strrchr (pz_file_name, '/');
861 char *pz_incl_quot = pz_data;
863 fprintf (stderr, "Quoted includes in %s\n", pz_file_name);
865 /* Set "pz_file_name" to point to the containing subdirectory of the source
866 If there is none, then it is in our current directory, ".". */
868 if (pz_dir_end == (char *) NULL)
875 pz_incl_quot += p_re_match->rm_so;
877 /* Skip forward to the included file name */
878 while (ISSPACE (*pz_incl_quot))
880 /* ISSPACE() may evaluate is argument more than once! */
881 while ((++pz_incl_quot, ISSPACE (*pz_incl_quot)))
883 pz_incl_quot += sizeof ("include") - 1;
884 while (*pz_incl_quot++ != '"')
887 if (quoted_file_exists (pz_src_dir, pz_file_name, pz_incl_quot))
889 /* Print the source directory and the subdirectory
890 of the file in question. */
891 printf ("%s %s/", pz_src_dir, pz_file_name);
892 pz_dir_end = pz_incl_quot;
894 /* Append to the directory the relative path of the desired file */
895 while (*pz_incl_quot != '"')
896 putc (*pz_incl_quot++, stdout);
898 /* Now print the destination directory appended with the
899 relative path of the desired file */
900 printf (" %s/%s/", pz_dest_dir, pz_file_name);
901 while (*pz_dir_end != '"')
902 putc (*pz_dir_end++, stdout);
908 /* Find the next entry */
909 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
916 /* * * * * * * * * * * * *
918 This loop should only cycle for 1/2 of one loop.
919 "chain_open" starts a process that uses "read_fd" as
920 its stdin and returns the new fd this process will use
924 start_fixer (read_fd, p_fixd, pz_file_name)
929 tSCC z_err[] = "Error %d (%s) starting filter process for %s\n";
933 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
934 pz_cmd = (char*)NULL;
937 tSCC z_cmd_fmt[] = "file='%s'\n%s";
938 pz_cmd = (char*)xmalloc (strlen (p_fixd->patch_args[2])
939 + sizeof( z_cmd_fmt )
940 + strlen( pz_file_name ));
941 sprintf (pz_cmd, z_cmd_fmt, pz_file_name, p_fixd->patch_args[2]);
942 pz_cmd_save = p_fixd->patch_args[2];
943 p_fixd->patch_args[2] = pz_cmd;
948 static int failCt = 0;
951 fd = chain_open (read_fd,
952 (t_pchar *) p_fixd->patch_args,
953 (process_chain_head == -1)
954 ? &process_chain_head : (pid_t *) NULL);
962 fprintf (stderr, z_err, errno, strerror (errno),
965 if ((errno != EAGAIN) || (++failCt > 10))
970 if (pz_cmd != (char*)NULL)
972 free ((void*)pz_cmd);
973 p_fixd->patch_args[2] = pz_cmd_save;
979 /* * * * * * * * * * * * *
981 Process the potential fixes for a particular include file.
982 Input: the original text of the file and the file's name
983 Result: none. A new file may or may not be created. */
986 process (pz_data, pz_file_name)
988 const char *pz_file_name;
990 static char env_current_file[1024];
991 tFixDesc *p_fixd = fixDescList;
992 int todo_ct = FIX_COUNT;
994 int num_children = 0;
996 process_chain_head = NOPROCESS;
997 fprintf (stderr, "%-50s \r", pz_file_name );
998 /* For every fix in our fix list, ... */
999 for (; todo_ct > 0; p_fixd++, todo_ct--)
1004 if (p_fixd->fd_flags & FD_SKIP_TEST)
1007 /* IF there is a file name restriction,
1008 THEN ensure the current file name matches one in the pattern */
1010 if (p_fixd->file_list != (char *) NULL)
1012 const char *pz_fname = pz_file_name;
1013 const char *pz_scan = p_fixd->file_list;
1016 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1018 name_len = strlen (pz_fname);
1022 pz_scan = strstr (pz_scan + 1, pz_fname);
1023 /* IF we can't match the string at all,
1025 if (pz_scan == (char *) NULL)
1028 /* IF the match is surrounded by the '|' markers,
1029 THEN we found a full match -- time to run the tests */
1031 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1036 /* FOR each test, see if it fails.
1037 IF it does fail, then we go on to the next test */
1039 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1044 static const char z_test_fail[] =
1045 "%16s test %2d failed for %s\n";
1047 switch (p_test->type)
1050 if (!SUCCESSFUL (test_test (p_test, pz_file_name)))
1053 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1054 p_fixd->test_ct - test_ct, pz_file_name);
1061 if (!SUCCESSFUL (egrep_test (pz_data, p_test)))
1064 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1065 p_fixd->test_ct - test_ct, pz_file_name);
1072 if (SUCCESSFUL (egrep_test (pz_data, p_test)))
1075 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1076 p_fixd->test_ct - test_ct, pz_file_name);
1084 fprintf (stderr, "Applying %-24s to %s\n",
1085 p_fixd->fix_name, pz_file_name);
1087 /* IF we do not have a read pointer,
1088 THEN this is the first fix for the current file.
1089 Open the source file. That will be used as stdin for
1090 the first fix. Any subsequent fixes will use the
1091 stdout descriptor of the previous fix as its stdin. */
1095 read_fd = open (pz_file_name, O_RDONLY);
1098 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1099 strerror (errno), pz_file_name);
1100 exit (EXIT_FAILURE);
1104 read_fd = start_fixer (read_fd, p_fixd, pz_file_name);
1111 /* IF after all the tests we did not start any patch programs,
1117 /* OK. We have work to do. Read back in the output
1118 of the filtering chain. Compare each byte as we read it with
1119 the contents of the original file. As soon as we find any
1120 difference, we will create the output file, write out all
1121 the matched text and then copy any remaining data from the
1122 output of the filter chain.
1125 FILE *in_fp = fdopen (read_fd, "r");
1126 FILE *out_fp = (FILE *) NULL;
1127 char *pz_cmp = pz_data;
1137 /* IF we are emitting the output
1138 THEN emit this character, too.
1140 if (out_fp != (FILE *) NULL)
1143 /* ELSE if this character does not match the original,
1144 THEN now is the time to start the output.
1146 else if (ch != *pz_cmp)
1148 out_fp = create_file (pz_file_name);
1150 /* IF there are matched data, write it all now. */
1151 if (pz_cmp != pz_data)
1156 fputs (pz_data, out_fp);
1160 /* Emit the current unmatching character */
1164 /* ELSE the character matches. Advance the compare ptr */
1168 /* IF we created the output file, ... */
1169 if (out_fp != (FILE *) NULL)
1173 /* Close the file and see if we have to worry about
1174 `#include "file.h"' constructs. */
1176 if (regexec (&incl_quote_re, pz_data, 1, &match, 0) == 0)
1177 extract_quoted_files (pz_data, pz_file_name, &match);
1181 close (read_fd); /* probably redundant, but I'm paranoid */
1183 /* Wait for child processes created by chain_open()
1184 to avoid creating zombies. */
1185 while (--num_children >= 0)
1186 wait ((int *) NULL);