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 <sys/types.h>
28 #include <sys/param.h>
30 #ifdef HAVE_SYS_WAIT_H
46 #include "gnu-regex.h"
49 static const char program_id[] = "fixincl version 1.0";
51 #define MINIMUM_MAXIMUM_LINES 128
53 /* If this particular system's header files define the macro `MAXPATHLEN',
54 we happily take advantage of it; otherwise we use a value which ought
55 to be large enough. */
57 # define MAXPATHLEN 4096
59 #define NAME_TABLE_SIZE (MINIMUM_MAXIMUM_LINES * MAXPATHLEN)
62 # define EXIT_SUCCESS 0
65 # define EXIT_FAILURE 1
70 #define tSCC static const char
71 #define tCC const char
72 #define tSC static char
74 typedef int t_success;
80 #define SUCCEEDED(p) ((p) == SUCCESS)
81 #define SUCCESSFUL(p) SUCCEEDED (p)
82 #define FAILED(p) ((p) < SUCCESS)
83 #define HADGLITCH(p) ((p) > SUCCESS)
89 Each fix may have associated tests that determine
90 whether the fix needs to be applied or not.
91 Each test has a type (from the te_test_type enumeration);
92 associated test text; and, if the test is TT_EGREP or
93 the negated form TT_NEGREP, a pointer to the compiled
94 version of the text string.
99 TT_TEST, TT_EGREP, TT_NEGREP
102 typedef struct test_desc tTestDesc;
107 const char *pz_test_text;
108 regex_t *p_test_regex;
111 typedef struct patch_desc tPatchDesc;
115 Everything you ever wanted to know about how to apply
116 a particular fix (which files, how to qualify them,
117 how to actually make the fix, etc...)
120 #define FD_MACH_ONLY 0x0000
121 #define FD_MACH_IFNOT 0x0001
122 #define FD_SKIP_TEST 0x8000
124 typedef struct fix_desc tFixDesc;
127 const char* fix_name; /* Name of the fix */
128 const char* file_list; /* List of files it applies to */
129 const char** papz_machs; /* List of machine/os-es it applies to */
133 tTestDesc* p_test_desc;
134 const char** patch_args;
137 /* Working environment strings. Essentially, invocation 'options'. */
138 char *pz_dest_dir = NULL;
139 char *pz_src_dir = NULL;
140 char *pz_machine = NULL;
141 char *pz_find_base = NULL;
142 int find_base_len = 0;
144 pid_t process_chain_head = (pid_t) -1;
146 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
147 regex_t incl_quote_re;
149 char *load_file _P_((const char *));
150 void process _P_((char *, const char *));
151 void run_compiles ();
152 void wait_for_pid _P_(( pid_t ));
157 /* * * * * * * * * * * * * * * * * * *
166 static const char gnu_lib_mark[] =
167 "This file is part of the GNU C Library";
169 #ifndef NO_BOGOSITY_LIMITS
170 # define BOGUS_LIMIT MINIMUM_MAXIMUM_LINES
174 char *apz_names[BOGUS_LIMIT];
177 /* Before anything else, ensure we can allocate our file name buffer. */
178 file_name_buf = (char *) malloc (NAME_TABLE_SIZE);
179 if (file_name_buf == (char *) NULL)
181 fprintf (stderr, "fixincl cannot allocate 0x%08X bytes\n",
192 if (strcmp (argv[1], "-v") == 0)
194 static const char zFmt[] = "echo '%s'";
196 /* The 'version' option is really used to test that:
197 1. The program loads correctly (no missing libraries)
198 2. we can correctly run our server shell process
199 3. that we can compile all the regular expressions.
202 sprintf (file_name_buf, zFmt, program_id);
203 fputs (file_name_buf + 5, stdout);
204 exit (strcmp (run_shell (file_name_buf), program_id));
206 freopen (argv[1], "r", stdin);
210 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
216 #ifndef NO_BOGOSITY_LIMITS
217 /* Some systems only allow so many calls to fork(2).
218 This is inadequate for this program. Consequently,
219 we must let a grandfather process spawn children
220 that then spawn all the processes that do the real work.
227 char *pz_buf = file_name_buf;
229 /* Only the parent process can read from stdin without confusing
230 the world. (How does the child tell the parent to skip
231 forward? Pipes and files behave differently.) */
233 while ( (file_name_ct < BOGUS_LIMIT)
234 && (pz_buf < (file_name_buf + NAME_TABLE_SIZE - MAXPATHLEN)))
236 if (fgets (pz_buf, MAXPATHLEN, stdin) == (char *) NULL)
238 while (isspace (*pz_buf))
240 if ((*pz_buf == '\0') || (*pz_buf == '#'))
242 apz_names[file_name_ct++] = pz_buf;
243 pz_buf += strlen (pz_buf);
244 while (isspace (pz_buf[-1]))
250 /* IF we did not get any files this time thru
251 THEN we must be done. */
252 if (file_name_ct == 0)
259 pid_t child = fork ();
260 if (child == NULLPROCESS)
263 if (child == NOPROCESS)
265 fprintf (stderr, "Error %d (%s) forking in main\n",
266 errno, strerror (errno));
271 fprintf (stderr, "Waiting for %d to complete %d files\n",
272 child, file_name_ct);
275 wait_for_pid( child, file_name_ct );
279 /*#*/ error "NON-BOGUS LIMITS NOT SUPPORTED?!?!"
282 /* For every file specified in stdandard in
283 (except as throttled for bogus reasons)...
285 for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++)
288 char *pz_file_name = apz_names[loop_ct];
290 if (access (pz_file_name, R_OK) != 0)
293 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
294 pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
295 erno, strerror (erno));
297 else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
299 if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
300 process (pz_data, pz_file_name);
301 free ((void *) pz_data);
309 /* * * * * * * * * * * * */
314 static const char var_not_found[] =
315 "fixincl ERROR: %s environment variable not defined\n";
318 static const char var[] = "TARGET_MACHINE";
319 pz_machine = getenv (var);
320 if (pz_machine == (char *) NULL)
322 fprintf (stderr, var_not_found, var);
328 static const char var[] = "DESTDIR";
329 pz_dest_dir = getenv (var);
330 if (pz_dest_dir == (char *) NULL)
332 fprintf (stderr, var_not_found, var);
338 static const char var[] = "SRCDIR";
339 pz_src_dir = getenv (var);
340 if (pz_src_dir == (char *) NULL)
342 fprintf (stderr, var_not_found, var);
348 static const char var[] = "FIND_BASE";
349 pz_find_base = getenv (var);
350 if (pz_find_base == (char *) NULL)
352 fprintf (stderr, var_not_found, var);
355 find_base_len = strlen( pz_find_base );
358 /* Compile all the regular expressions now.
359 That way, it is done only once for the whole run.
363 signal (SIGQUIT, SIG_IGN);
364 signal (SIGIOT, SIG_IGN);
365 signal (SIGPIPE, SIG_IGN);
366 signal (SIGALRM, SIG_IGN);
367 signal (SIGTERM, SIG_IGN);
370 Make sure that if we opened a server process, we close it now.
371 This is the grandparent process. We don't need the server anymore
372 and our children should make their own. */
375 (void)wait ( (int*)NULL );
378 /* * * * * * * * * * * * *
380 wait_for_pid - Keep calling `wait(2)' until it returns
381 the process id we are looking for. Not every system has
382 `waitpid(2)'. We also ensure that the children exit with success. */
385 wait_for_pid(child, file_name_ct)
391 pid_t dead_kid = wait (&status);
393 if (dead_kid == child)
395 if (! WIFEXITED( status ))
397 fprintf (stderr, "child process %d is hung on signal %d\n",
398 child, WSTOPSIG( status ));
401 if (WEXITSTATUS( status ) != 0)
403 fprintf (stderr, "child process %d exited with status %d\n",
404 child, WEXITSTATUS( status ));
407 break; /* normal child completion */
411 IF there is an error, THEN see if it is retryable.
412 If it is not retryable, then break out of this loop. */
413 if (dead_kid == NOPROCESS)
421 fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
422 errno, strerror( errno ), child );
425 case ECHILD: /* no children to wait for?? */
433 /* * * * * * * * * * * * *
435 load_file loads all the contents of a file into malloc-ed memory.
436 Its argument is the name of the file to read in; the returned
437 result is the NUL terminated contents of the file. The file
438 is presumed to be an ASCII text file containing no NULs. */
440 load_file (pz_file_name)
441 const char *pz_file_name;
449 if (stat (pz_file_name, &stbf) != 0)
451 fprintf (stderr, "error %d (%s) stat-ing %s\n",
452 errno, strerror (errno), pz_file_name);
453 return (char *) NULL;
455 file_size = stbf.st_size;
458 return (char *) NULL;
460 pz_data = (char *) malloc ((file_size + 16) & ~0x00F);
461 if (pz_data == (char *) NULL)
463 fprintf (stderr, "error: could not malloc %d bytes\n",
469 FILE *fp = fopen (pz_file_name, "r");
470 size_t size_left = file_size;
471 char *read_ptr = pz_data;
473 if (fp == (FILE *) NULL)
475 fprintf (stderr, "error %d (%s) opening %s\n", errno,
476 strerror (errno), pz_file_name);
477 free ((void *) pz_data);
478 return (char *) NULL;
483 size_t sizeRead = fread ((void *) read_ptr, 1, size_left, fp);
494 fprintf (stderr, "error %d (%s) reading %s\n", err,
495 strerror (err), pz_file_name);
496 free ((void *) pz_data);
498 return (char *) NULL;
502 read_ptr += sizeRead;
503 size_left -= sizeRead;
505 while (size_left != 0);
514 /* * * * * * * * * * * * *
516 run_compiles run all the regexp compiles for all the fixes once.
521 tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\
522 \texpr = `%s'\n\terror %s\n";
523 tFixDesc *p_fixd = fixDescList;
524 int fix_ct = FIX_COUNT;
527 int re_ct = REGEX_COUNT;
529 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
531 if (p_re == (regex_t *) NULL)
533 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
534 REGEX_COUNT * sizeof (regex_t));
538 /* Make sure re_compile_pattern does not stumble across invalid
541 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
542 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
544 /* The patterns we search for are all egrep patterns.
545 In the shell version of this program, we invoke egrep
546 with the supplied pattern. Here, we will run
547 re_compile_pattern, but it must be using the same rules. */
549 re_set_syntax (RE_SYNTAX_EGREP);
550 pz_err = re_compile_pattern (incl_quote_pat, sizeof (incl_quote_pat)-1,
552 if (pz_err != (char *) NULL)
554 fprintf (stderr, z_bad_comp, "quoted include", "run_compiles",
555 incl_quote_pat, pz_err);
559 /* FOR every fixup, ... */
562 p_test = p_fixd->p_test_desc;
563 test_ct = p_fixd->test_ct;
565 /* IF the machine type pointer is not NULL (we are not in test mode)
566 AND this test is for or not done on particular machines
569 if ( (pz_machine != NULL)
570 && (p_fixd->papz_machs != (const char**) NULL) )
572 const char **papz_machs = p_fixd->papz_machs;
573 char *pz = file_name_buf;
577 tSCC skip[] = "skip";
580 /* Construct a shell script that looks like this:
582 case our-cpu-platform-os in
583 tests-cpu-platform-os-pattern )
589 where 'run' and 'skip' may be reversed, depending on
590 the sense of the test. */
592 sprintf (pz, "case %s in\n", pz_machine);
595 if (p_fixd->fd_flags & FD_MACH_IFNOT)
606 /* FOR any additional machine names to test for,
607 insert the " | \\\n" glue and the machine pattern. */
611 const char* pz_mach = *(papz_machs++);
613 if (pz_mach == (const char*) NULL)
615 sprintf (pz, "%s %s", pz_sep, pz_mach);
619 sprintf (pz, " )\n echo %s ;;\n * )\n echo %s ;;\nesac",
620 pz_if_true, pz_if_false);
623 The result will start either with 's' or 'r'. */
627 pz = run_shell (file_name_buf);
632 p_fixd->fd_flags |= FD_SKIP_TEST;
638 /* FOR every test for the fixup, ... */
640 while (--test_ct >= 0)
642 switch (p_test->type)
646 /* You might consider putting the following under #ifdef.
647 The number of re's used is computed by autogen.
648 So, it is static and known at compile time. */
652 fputs ("out of RE's\n", stderr);
656 p_test->p_test_regex = p_re++;
657 pz_err = re_compile_pattern (p_test->pz_test_text,
658 strlen (p_test->pz_test_text),
659 p_test->p_test_regex);
660 if (pz_err != (char *) NULL)
662 fprintf (stderr, z_bad_comp, "select test", p_fixd->fix_name,
663 p_test->pz_test_text, pz_err);
670 while (p_fixd++, --fix_ct > 0);
674 /* * * * * * * * * * * * *
676 create_file Create the output modified file.
677 Input: the name of the file to create
678 Returns: a file pointer to the new, open file */
680 #define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
683 create_file (pz_file_name)
684 const char *pz_file_name;
688 char fname[MAXPATHLEN];
691 if (strncmp( pz_file_name, pz_find_base, find_base_len ) != 0)
693 fprintf (stderr, "Error: input file %s does not match %s/*\n",
694 pz_file_name, pz_find_base );
699 sprintf (fname, "%s/%s", pz_dest_dir, pz_file_name + find_base_len);
701 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
703 /* We may need to create the directories needed... */
704 if ((fd < 0) && (errno == ENOENT))
706 char *pz_dir = strchr (fname + 1, '/');
709 while (pz_dir != (char *) NULL)
712 if (stat (fname, &stbf) < 0)
714 mkdir (fname, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP
715 | S_IROTH | S_IXOTH);
719 pz_dir = strchr (pz_dir + 1, '/');
722 /* Now, lets try the open again... */
723 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
727 fprintf (stderr, "Error %d (%s) creating %s\n",
728 errno, strerror (errno), fname);
731 fprintf (stderr, "Fixed: %s\n", pz_file_name);
732 pf = fdopen (fd, "w");
736 static const char hdr[] =
737 "/* DO NOT EDIT THIS FILE.\n\n"
738 " It has been auto-edited by fixincludes from /usr/include/%s\n"
739 " This had to be done to correct non-standard usages in the\n"
740 " original, manufacturer supplied header file. */\n\n";
742 fprintf (pf, hdr, pz_file_name);
749 /* * * * * * * * * * * * *
751 test_test make sure a shell-style test expression passes.
752 Input: a pointer to the descriptor of the test to run and
753 the name of the file that we might want to fix
754 Result: SUCCESS or FAILURE, depending on the result of the
755 shell script we run. */
758 test_test (p_test, pz_file_name)
764 if ( test %s ) > /dev/null 2>&1\n\
770 t_success res = FAILURE;
772 static char cmd_buf[4096];
774 sprintf (cmd_buf, cmd_fmt, pz_file_name, p_test->pz_test_text);
775 pz_res = run_shell (cmd_buf);
778 free ((void *) pz_res);
783 /* * * * * * * * * * * * *
785 egrep_test make sure an egrep expression is found in the file text.
786 Input: a pointer to the descriptor of the test to run and
787 the pointer to the contents of the file under suspicion
788 Result: SUCCESS if the pattern is found, FAILURE otherwise
790 The caller may choose 'FAILURE' as 'SUCCESS' if the sense of the test
794 egrep_test (pz_data, p_test)
801 if (p_test->p_test_regex == 0)
802 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
803 p_test->pz_test_text);
805 if (regexec (p_test->p_test_regex, pz_data, 1, &match, 0) == 0)
811 /* * * * * * * * * * * * *
813 quoted_file_exists Make sure that a file exists before we emit
814 the file name. If we emit the name, our invoking shell will try
815 to copy a non-existing file into the destination directory. */
818 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
823 char z[ MAXPATHLEN ];
825 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
826 pz = z + strlen ( z );
829 char ch = *pz_file++;
839 if (stat (z, &s) != 0)
841 return S_ISREG( s.st_mode );
846 /* * * * * * * * * * * * *
850 The syntax, `#include "file.h"' specifies that the compiler is to
851 search the local directory of the current file before the include
852 list. Consequently, if we have modified a header and stored it in
853 another directory, any files that are included by that modified
854 file in that fashion must also be copied into this new directory.
855 This routine finds those flavors of #include and for each one found
858 1. source directory of the original file
859 2. the relative path file name of the #includ-ed file
860 3. the full destination path for this file
862 Input: the text of the file, the file name and a pointer to the
863 match list where the match information was stored.
864 Result: internally nothing. The results are written to stdout
865 for interpretation by the invoking shell */
869 extract_quoted_files (pz_data, pz_file_name, p_re_match)
871 const char *pz_file_name;
872 regmatch_t *p_re_match;
874 char *pz_dir_end = strrchr (pz_file_name, '/');
875 char *pz_incl_quot = pz_data;
877 fprintf (stderr, "Quoted includes in %s\n", pz_file_name);
879 /* Set "pz_file_name" to point to the containing subdirectory of the source
880 If there is none, then it is in our current directory, ".". */
882 if (pz_dir_end == (char *) NULL)
889 pz_incl_quot += p_re_match->rm_so;
891 /* Skip forward to the included file name */
892 while (isspace (*pz_incl_quot))
894 while (isspace (*++pz_incl_quot))
896 pz_incl_quot += sizeof ("include") - 1;
897 while (*pz_incl_quot++ != '"')
900 if (quoted_file_exists (pz_src_dir, pz_file_name, pz_incl_quot))
902 /* Print the source directory and the subdirectory
903 of the file in question. */
904 printf ("%s %s/", pz_src_dir, pz_file_name);
905 pz_dir_end = pz_incl_quot;
907 /* Append to the directory the relative path of the desired file */
908 while (*pz_incl_quot != '"')
909 putc (*pz_incl_quot++, stdout);
911 /* Now print the destination directory appended with the
912 relative path of the desired file */
913 printf (" %s/%s/", pz_dest_dir, pz_file_name);
914 while (*pz_dir_end != '"')
915 putc (*pz_dir_end++, stdout);
921 /* Find the next entry */
922 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
928 /* * * * * * * * * * * * *
930 Process the potential fixes for a particular include file.
931 Input: the original text of the file and the file's name
932 Result: none. A new file may or may not be created. */
935 process (pz_data, pz_file_name)
937 const char *pz_file_name;
939 static char env_current_file[1024];
940 tFixDesc *p_fixd = fixDescList;
941 int todo_ct = FIX_COUNT;
943 int num_children = 0;
945 /* IF this is the first time through,
946 THEN put the 'file' environment variable into the environment.
947 This is used by some of the subject shell scripts and tests. */
949 if (env_current_file[0] == NUL) {
950 strcpy (env_current_file, "file=");
951 putenv (env_current_file);
955 Ghastly as it is, this actually updates the value of the variable:
957 putenv(3C) C Library Functions putenv(3C)
960 putenv() makes the value of the environment variable name
961 equal to value by altering an existing variable or creating
962 a new one. In either case, the string pointed to by string
963 becomes part of the environment, so altering the string will
964 change the environment. string points to a string of the
965 form ``name=value.'' The space used by string is no longer
966 used once a new string-defining name is passed to putenv().
968 strcpy (env_current_file + 5, pz_file_name);
969 process_chain_head = NOPROCESS;
970 fprintf (stderr, "%-50s \r", pz_file_name );
971 /* For every fix in our fix list, ... */
972 for (; todo_ct > 0; p_fixd++, todo_ct--)
977 if (p_fixd->fd_flags & FD_SKIP_TEST)
980 /* IF there is a file name restriction,
981 THEN ensure the current file name matches one in the pattern */
983 if (p_fixd->file_list != (char *) NULL)
985 const char *pz_fname = pz_file_name;
986 const char *pz_scan = p_fixd->file_list;
989 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
991 name_len = strlen (pz_fname);
995 pz_scan = strstr (pz_scan + 1, pz_fname);
996 /* IF we can't match the string at all,
998 if (pz_scan == (char *) NULL)
1001 /* IF the match is surrounded by the '|' markers,
1002 THEN we found a full match -- time to run the tests */
1004 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1009 /* FOR each test, see if it fails.
1010 IF it does fail, then we go on to the next test */
1012 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1017 static const char z_test_fail[] =
1018 "%16s test %2d failed for %s\n";
1020 switch (p_test->type)
1023 if (!SUCCESSFUL (test_test (p_test, pz_file_name)))
1026 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1027 p_fixd->test_ct - test_ct, pz_file_name);
1034 if (!SUCCESSFUL (egrep_test (pz_data, p_test)))
1037 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1038 p_fixd->test_ct - test_ct, pz_file_name);
1045 if (SUCCESSFUL (egrep_test (pz_data, p_test)))
1048 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1049 p_fixd->test_ct - test_ct, pz_file_name);
1057 fprintf (stderr, "Applying %-24s to %s\n",
1058 p_fixd->fix_name, pz_file_name);
1060 /* IF we do not have a read pointer,
1061 THEN this is the first fix for the current file.
1062 Open the source file. That will be used as stdin for
1063 the first fix. Any subsequent fixes will use the
1064 stdout descriptor of the previous fix as its stdin. */
1068 read_fd = open (pz_file_name, O_RDONLY);
1071 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1072 strerror (errno), pz_file_name);
1073 exit (EXIT_FAILURE);
1077 /* This loop should only cycle for 1/2 of one loop.
1078 "chain_open" starts a process that uses "read_fd" as
1079 its stdin and returns the new fd this process will use
1084 tSCC z_err[] = "Error %d (%s) starting filter process for %s\n";
1085 static int failCt = 0;
1086 int fd = chain_open (read_fd,
1087 (t_pchar *) p_fixd->patch_args,
1088 (process_chain_head == -1)
1089 ? &process_chain_head : (pid_t *) NULL);
1098 fprintf (stderr, z_err, errno, strerror (errno),
1101 if ((errno != EAGAIN) || (++failCt > 10))
1102 exit (EXIT_FAILURE);
1110 /* IF after all the tests we did not start any patch programs,
1116 /* OK. We have work to do. Read back in the output
1117 of the filtering chain. Compare each byte as we read it with
1118 the contents of the original file. As soon as we find any
1119 difference, we will create the output file, write out all
1120 the matched text and then copy any remaining data from the
1121 output of the filter chain.
1124 FILE *in_fp = fdopen (read_fd, "r");
1125 FILE *out_fp = (FILE *) NULL;
1126 char *pz_cmp = pz_data;
1136 /* IF we are emitting the output
1137 THEN emit this character, too.
1139 if (out_fp != (FILE *) NULL)
1142 /* ELSE if this character does not match the original,
1143 THEN now is the time to start the output.
1145 else if (ch != *pz_cmp)
1147 out_fp = create_file (pz_file_name);
1149 /* IF there are matched data, write it all now. */
1150 if (pz_cmp != pz_data)
1155 fputs (pz_data, out_fp);
1159 /* Emit the current unmatching character */
1163 /* ELSE the character matches. Advance the compare ptr */
1167 /* IF we created the output file, ... */
1168 if (out_fp != (FILE *) NULL)
1172 /* Close the file and see if we have to worry about
1173 `#include "file.h"' constructs. */
1175 if (regexec (&incl_quote_re, pz_data, 1, &match, 0) == 0)
1176 extract_quoted_files (pz_data, pz_file_name, &match);
1180 close (read_fd); /* probably redundant, but I'm paranoid */
1182 /* Wait for child processes created by chain_open()
1183 to avoid creating zombies. */
1184 while (--num_children >= 0)
1185 wait ((int *) NULL);