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?!?!"
283 Here we are the child of the grandparent process. The parent
284 of all the little fixup processes. We ignore the deaths of
287 signal (SIGCLD, SIG_IGN);
289 /* For every file specified in stdandard in
290 (except as throttled for bogus reasons)...
292 for (loop_ct = 0; loop_ct < file_name_ct; loop_ct++)
295 char *pz_file_name = apz_names[loop_ct];
297 if (access (pz_file_name, R_OK) != 0)
300 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
301 pz_file_name, getcwd ((char *) NULL, MAXPATHLEN),
302 erno, strerror (erno));
304 else if (pz_data = load_file (pz_file_name), (pz_data != (char *) NULL))
306 if (strstr (pz_data, gnu_lib_mark) == (char *) NULL)
307 process (pz_data, pz_file_name);
308 free ((void *) pz_data);
316 /* * * * * * * * * * * * */
321 static const char var_not_found[] =
322 "fixincl ERROR: %s environment variable not defined\n";
325 static const char var[] = "TARGET_MACHINE";
326 pz_machine = getenv (var);
327 if (pz_machine == (char *) NULL)
329 fprintf (stderr, var_not_found, var);
335 static const char var[] = "DESTDIR";
336 pz_dest_dir = getenv (var);
337 if (pz_dest_dir == (char *) NULL)
339 fprintf (stderr, var_not_found, var);
345 static const char var[] = "SRCDIR";
346 pz_src_dir = getenv (var);
347 if (pz_src_dir == (char *) NULL)
349 fprintf (stderr, var_not_found, var);
355 static const char var[] = "FIND_BASE";
356 pz_find_base = getenv (var);
357 if (pz_find_base == (char *) NULL)
359 fprintf (stderr, var_not_found, var);
362 find_base_len = strlen( pz_find_base );
365 /* Compile all the regular expressions now.
366 That way, it is done only once for the whole run.
370 signal (SIGQUIT, SIG_IGN);
371 signal (SIGIOT, SIG_IGN);
372 signal (SIGPIPE, SIG_IGN);
373 signal (SIGALRM, SIG_IGN);
374 signal (SIGTERM, SIG_IGN);
377 Make sure that if we opened a server process, we close it now.
378 This is the grandparent process. We don't need the server anymore
379 and our children should make their own. */
382 (void)wait ( (int*)NULL );
385 /* * * * * * * * * * * * *
387 wait_for_pid - Keep calling `wait(2)' until it returns
388 the process id we are looking for. Not every system has
389 `waitpid(2)'. We also ensure that the children exit with success. */
392 wait_for_pid(child, file_name_ct)
398 pid_t dead_kid = wait (&status);
400 if (dead_kid == child)
402 if (! WIFEXITED( status ))
404 fprintf (stderr, "child process %d is hung on signal %d\n",
405 child, WSTOPSIG( status ));
408 if (WEXITSTATUS( status ) != 0)
410 fprintf (stderr, "child process %d exited with status %d\n",
411 child, WEXITSTATUS( status ));
414 break; /* normal child completion */
418 IF there is an error, THEN see if it is retryable.
419 If it is not retryable, then break out of this loop. */
420 if (dead_kid == NOPROCESS)
428 fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
429 errno, strerror( errno ), child );
432 case ECHILD: /* no children to wait for?? */
440 /* * * * * * * * * * * * *
442 load_file loads all the contents of a file into malloc-ed memory.
443 Its argument is the name of the file to read in; the returned
444 result is the NUL terminated contents of the file. The file
445 is presumed to be an ASCII text file containing no NULs. */
447 load_file (pz_file_name)
448 const char *pz_file_name;
456 if (stat (pz_file_name, &stbf) != 0)
458 fprintf (stderr, "error %d (%s) stat-ing %s\n",
459 errno, strerror (errno), pz_file_name);
460 return (char *) NULL;
462 file_size = stbf.st_size;
465 return (char *) NULL;
467 pz_data = (char *) malloc ((file_size + 16) & ~0x00F);
468 if (pz_data == (char *) NULL)
470 fprintf (stderr, "error: could not malloc %d bytes\n",
476 FILE *fp = fopen (pz_file_name, "r");
477 size_t size_left = file_size;
478 char *read_ptr = pz_data;
480 if (fp == (FILE *) NULL)
482 fprintf (stderr, "error %d (%s) opening %s\n", errno,
483 strerror (errno), pz_file_name);
484 free ((void *) pz_data);
485 return (char *) NULL;
490 size_t sizeRead = fread ((void *) read_ptr, 1, size_left, fp);
501 fprintf (stderr, "error %d (%s) reading %s\n", err,
502 strerror (err), pz_file_name);
503 free ((void *) pz_data);
505 return (char *) NULL;
509 read_ptr += sizeRead;
510 size_left -= sizeRead;
512 while (size_left != 0);
521 /* * * * * * * * * * * * *
523 run_compiles run all the regexp compiles for all the fixes once.
528 tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\
529 \texpr = `%s'\n\terror %s\n";
530 tFixDesc *p_fixd = fixDescList;
531 int fix_ct = FIX_COUNT;
534 int re_ct = REGEX_COUNT;
536 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
538 if (p_re == (regex_t *) NULL)
540 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
541 REGEX_COUNT * sizeof (regex_t));
545 /* Make sure re_compile_pattern does not stumble across invalid
548 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
549 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
551 /* The patterns we search for are all egrep patterns.
552 In the shell version of this program, we invoke egrep
553 with the supplied pattern. Here, we will run
554 re_compile_pattern, but it must be using the same rules. */
556 re_set_syntax (RE_SYNTAX_EGREP);
557 pz_err = re_compile_pattern (incl_quote_pat, sizeof (incl_quote_pat)-1,
559 if (pz_err != (char *) NULL)
561 fprintf (stderr, z_bad_comp, "quoted include", "run_compiles",
562 incl_quote_pat, pz_err);
566 /* FOR every fixup, ... */
569 p_test = p_fixd->p_test_desc;
570 test_ct = p_fixd->test_ct;
572 /* IF the machine type pointer is not NULL (we are not in test mode)
573 AND this test is for or not done on particular machines
576 if ( (pz_machine != NULL)
577 && (p_fixd->papz_machs != (const char**) NULL) )
579 const char **papz_machs = p_fixd->papz_machs;
580 char *pz = file_name_buf;
584 tSCC skip[] = "skip";
587 /* Construct a shell script that looks like this:
589 case our-cpu-platform-os in
590 tests-cpu-platform-os-pattern )
596 where 'run' and 'skip' may be reversed, depending on
597 the sense of the test. */
599 sprintf (pz, "case %s in\n", pz_machine);
602 if (p_fixd->fd_flags & FD_MACH_IFNOT)
613 /* FOR any additional machine names to test for,
614 insert the " | \\\n" glue and the machine pattern. */
618 const char* pz_mach = *(papz_machs++);
620 if (pz_mach == (const char*) NULL)
622 sprintf (pz, "%s %s", pz_sep, pz_mach);
626 sprintf (pz, " )\n echo %s ;;\n * )\n echo %s ;;\nesac",
627 pz_if_true, pz_if_false);
630 The result will start either with 's' or 'r'. */
634 pz = run_shell (file_name_buf);
639 p_fixd->fd_flags |= FD_SKIP_TEST;
645 /* FOR every test for the fixup, ... */
647 while (--test_ct >= 0)
649 switch (p_test->type)
653 /* You might consider putting the following under #ifdef.
654 The number of re's used is computed by autogen.
655 So, it is static and known at compile time. */
659 fputs ("out of RE's\n", stderr);
663 p_test->p_test_regex = p_re++;
664 pz_err = re_compile_pattern (p_test->pz_test_text,
665 strlen (p_test->pz_test_text),
666 p_test->p_test_regex);
667 if (pz_err != (char *) NULL)
669 fprintf (stderr, z_bad_comp, "select test", p_fixd->fix_name,
670 p_test->pz_test_text, pz_err);
677 while (p_fixd++, --fix_ct > 0);
681 /* * * * * * * * * * * * *
683 create_file Create the output modified file.
684 Input: the name of the file to create
685 Returns: a file pointer to the new, open file */
687 #define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
690 create_file (pz_file_name)
691 const char *pz_file_name;
695 char fname[MAXPATHLEN];
698 if (strncmp( pz_file_name, pz_find_base, find_base_len ) != 0)
700 fprintf (stderr, "Error: input file %s does not match %s/*\n",
701 pz_file_name, pz_find_base );
706 sprintf (fname, "%s/%s", pz_dest_dir, pz_file_name + find_base_len);
708 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
710 /* We may need to create the directories needed... */
711 if ((fd < 0) && (errno == ENOENT))
713 char *pz_dir = strchr (fname + 1, '/');
716 while (pz_dir != (char *) NULL)
719 if (stat (fname, &stbf) < 0)
721 mkdir (fname, S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP
722 | S_IROTH | S_IXOTH);
726 pz_dir = strchr (pz_dir + 1, '/');
729 /* Now, lets try the open again... */
730 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
734 fprintf (stderr, "Error %d (%s) creating %s\n",
735 errno, strerror (errno), fname);
738 fprintf (stderr, "Fixed: %s\n", pz_file_name);
739 pf = fdopen (fd, "w");
743 static const char hdr[] =
744 "/* DO NOT EDIT THIS FILE.\n\n"
745 " It has been auto-edited by fixincludes from /usr/include/%s\n"
746 " This had to be done to correct non-standard usages in the\n"
747 " original, manufacturer supplied header file. */\n\n";
749 fprintf (pf, hdr, pz_file_name);
756 /* * * * * * * * * * * * *
758 test_test make sure a shell-style test expression passes.
759 Input: a pointer to the descriptor of the test to run and
760 the name of the file that we might want to fix
761 Result: SUCCESS or FAILURE, depending on the result of the
762 shell script we run. */
765 test_test (p_test, pz_file_name)
771 if ( test %s ) > /dev/null 2>&1\n\
777 t_success res = FAILURE;
779 static char cmd_buf[4096];
781 sprintf (cmd_buf, cmd_fmt, pz_file_name, p_test->pz_test_text);
782 pz_res = run_shell (cmd_buf);
785 free ((void *) pz_res);
790 /* * * * * * * * * * * * *
792 egrep_test make sure an egrep expression is found in the file text.
793 Input: a pointer to the descriptor of the test to run and
794 the pointer to the contents of the file under suspicion
795 Result: SUCCESS if the pattern is found, FAILURE otherwise
797 The caller may choose 'FAILURE' as 'SUCCESS' if the sense of the test
801 egrep_test (pz_data, p_test)
808 if (p_test->p_test_regex == 0)
809 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
810 p_test->pz_test_text);
812 if (regexec (p_test->p_test_regex, pz_data, 1, &match, 0) == 0)
818 /* * * * * * * * * * * * *
820 quoted_file_exists Make sure that a file exists before we emit
821 the file name. If we emit the name, our invoking shell will try
822 to copy a non-existing file into the destination directory. */
825 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
830 char z[ MAXPATHLEN ];
832 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
833 pz = z + strlen ( z );
836 char ch = *pz_file++;
846 if (stat (z, &s) != 0)
848 return S_ISREG( s.st_mode );
853 /* * * * * * * * * * * * *
857 The syntax, `#include "file.h"' specifies that the compiler is to
858 search the local directory of the current file before the include
859 list. Consequently, if we have modified a header and stored it in
860 another directory, any files that are included by that modified
861 file in that fashion must also be copied into this new directory.
862 This routine finds those flavors of #include and for each one found
865 1. source directory of the original file
866 2. the relative path file name of the #includ-ed file
867 3. the full destination path for this file
869 Input: the text of the file, the file name and a pointer to the
870 match list where the match information was stored.
871 Result: internally nothing. The results are written to stdout
872 for interpretation by the invoking shell */
876 extract_quoted_files (pz_data, pz_file_name, p_re_match)
878 const char *pz_file_name;
879 regmatch_t *p_re_match;
881 char *pz_dir_end = strrchr (pz_file_name, '/');
882 char *pz_incl_quot = pz_data;
884 fprintf (stderr, "Quoted includes in %s\n", pz_file_name);
886 /* Set "pz_file_name" to point to the containing subdirectory of the source
887 If there is none, then it is in our current directory, ".". */
889 if (pz_dir_end == (char *) NULL)
896 pz_incl_quot += p_re_match->rm_so;
898 /* Skip forward to the included file name */
899 while (isspace (*pz_incl_quot))
901 while (isspace (*++pz_incl_quot))
903 pz_incl_quot += sizeof ("include") - 1;
904 while (*pz_incl_quot++ != '"')
907 if (quoted_file_exists (pz_src_dir, pz_file_name, pz_incl_quot))
909 /* Print the source directory and the subdirectory
910 of the file in question. */
911 printf ("%s %s/", pz_src_dir, pz_file_name);
912 pz_dir_end = pz_incl_quot;
914 /* Append to the directory the relative path of the desired file */
915 while (*pz_incl_quot != '"')
916 putc (*pz_incl_quot++, stdout);
918 /* Now print the destination directory appended with the
919 relative path of the desired file */
920 printf (" %s/%s/", pz_dest_dir, pz_file_name);
921 while (*pz_dir_end != '"')
922 putc (*pz_dir_end++, stdout);
928 /* Find the next entry */
929 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
935 /* * * * * * * * * * * * *
937 Process the potential fixes for a particular include file.
938 Input: the original text of the file and the file's name
939 Result: none. A new file may or may not be created. */
942 process (pz_data, pz_file_name)
944 const char *pz_file_name;
946 static char env_current_file[1024];
947 tFixDesc *p_fixd = fixDescList;
948 int todo_ct = FIX_COUNT;
950 int num_children = 0;
952 /* IF this is the first time through,
953 THEN put the 'file' environment variable into the environment.
954 This is used by some of the subject shell scripts and tests. */
956 if (env_current_file[0] == NUL) {
957 strcpy (env_current_file, "file=");
958 putenv (env_current_file);
962 Ghastly as it is, this actually updates the value of the variable:
964 putenv(3C) C Library Functions putenv(3C)
967 putenv() makes the value of the environment variable name
968 equal to value by altering an existing variable or creating
969 a new one. In either case, the string pointed to by string
970 becomes part of the environment, so altering the string will
971 change the environment. string points to a string of the
972 form ``name=value.'' The space used by string is no longer
973 used once a new string-defining name is passed to putenv().
975 strcpy (env_current_file + 5, pz_file_name);
976 process_chain_head = NOPROCESS;
977 fprintf (stderr, "%-50s \r", pz_file_name );
978 /* For every fix in our fix list, ... */
979 for (; todo_ct > 0; p_fixd++, todo_ct--)
984 if (p_fixd->fd_flags & FD_SKIP_TEST)
987 /* IF there is a file name restriction,
988 THEN ensure the current file name matches one in the pattern */
990 if (p_fixd->file_list != (char *) NULL)
992 const char *pz_fname = pz_file_name;
993 const char *pz_scan = p_fixd->file_list;
996 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
998 name_len = strlen (pz_fname);
1002 pz_scan = strstr (pz_scan + 1, pz_fname);
1003 /* IF we can't match the string at all,
1005 if (pz_scan == (char *) NULL)
1008 /* IF the match is surrounded by the '|' markers,
1009 THEN we found a full match -- time to run the tests */
1011 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1016 /* FOR each test, see if it fails.
1017 IF it does fail, then we go on to the next test */
1019 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1024 static const char z_test_fail[] =
1025 "%16s test %2d failed for %s\n";
1027 switch (p_test->type)
1030 if (!SUCCESSFUL (test_test (p_test, pz_file_name)))
1033 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1034 p_fixd->test_ct - test_ct, pz_file_name);
1041 if (!SUCCESSFUL (egrep_test (pz_data, p_test)))
1044 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1045 p_fixd->test_ct - test_ct, pz_file_name);
1052 if (SUCCESSFUL (egrep_test (pz_data, p_test)))
1055 fprintf (stderr, z_test_fail, p_fixd->fix_name,
1056 p_fixd->test_ct - test_ct, pz_file_name);
1064 fprintf (stderr, "Applying %-24s to %s\n",
1065 p_fixd->fix_name, pz_file_name);
1067 /* IF we do not have a read pointer,
1068 THEN this is the first fix for the current file.
1069 Open the source file. That will be used as stdin for
1070 the first fix. Any subsequent fixes will use the
1071 stdout descriptor of the previous fix as its stdin. */
1075 read_fd = open (pz_file_name, O_RDONLY);
1078 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1079 strerror (errno), pz_file_name);
1080 exit (EXIT_FAILURE);
1084 /* This loop should only cycle for 1/2 of one loop.
1085 "chain_open" starts a process that uses "read_fd" as
1086 its stdin and returns the new fd this process will use
1091 tSCC z_err[] = "Error %d (%s) starting filter process for %s\n";
1092 static int failCt = 0;
1093 int fd = chain_open (read_fd,
1094 (t_pchar *) p_fixd->patch_args,
1095 (process_chain_head == -1)
1096 ? &process_chain_head : (pid_t *) NULL);
1105 fprintf (stderr, z_err, errno, strerror (errno),
1108 if ((errno != EAGAIN) || (++failCt > 10))
1109 exit (EXIT_FAILURE);
1117 /* IF after all the tests we did not start any patch programs,
1123 /* OK. We have work to do. Read back in the output
1124 of the filtering chain. Compare each byte as we read it with
1125 the contents of the original file. As soon as we find any
1126 difference, we will create the output file, write out all
1127 the matched text and then copy any remaining data from the
1128 output of the filter chain.
1131 FILE *in_fp = fdopen (read_fd, "r");
1132 FILE *out_fp = (FILE *) NULL;
1133 char *pz_cmp = pz_data;
1143 /* IF we are emitting the output
1144 THEN emit this character, too.
1146 if (out_fp != (FILE *) NULL)
1149 /* ELSE if this character does not match the original,
1150 THEN now is the time to start the output.
1152 else if (ch != *pz_cmp)
1154 out_fp = create_file (pz_file_name);
1156 /* IF there are matched data, write it all now. */
1157 if (pz_cmp != pz_data)
1162 fputs (pz_data, out_fp);
1166 /* Emit the current unmatching character */
1170 /* ELSE the character matches. Advance the compare ptr */
1174 /* IF we created the output file, ... */
1175 if (out_fp != (FILE *) NULL)
1179 /* Close the file and see if we have to worry about
1180 `#include "file.h"' constructs. */
1182 if (regexec (&incl_quote_re, pz_data, 1, &match, 0) == 0)
1183 extract_quoted_files (pz_data, pz_file_name, &match);
1187 close (read_fd); /* probably redundant, but I'm paranoid */
1189 /* Wait for child processes created by chain_open()
1190 to avoid creating zombies. */
1191 while (--num_children >= 0)
1192 wait ((int *) NULL);