1 /* Install modified versions of certain ANSI-incompatible system header
2 files which are fixed to work correctly with ANSI C and placed in a
3 directory that GCC will search.
5 Copyright (C) 1997, 1998, 1999, 2000, 2004 Free Software Foundation, Inc.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
14 GCC is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING. If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
29 #if defined( HAVE_MMAP_FILE )
31 #define BAD_ADDR ((void*)-1)
34 #ifndef SEPARATE_FIX_PROC
38 /* The contents of this string are not very important. It is mostly
39 just used as part of the "I am alive and working" test. */
41 static const char program_id[] = "fixincl version 1.1";
43 /* This format will be used at the start of every generated file */
45 static const char z_std_preamble[] =
46 "/* DO NOT EDIT THIS FILE.\n\n\
47 It has been auto-edited by fixincludes from:\n\n\
49 This had to be done to correct non-standard usages in the\n\
50 original, manufacturer supplied header file. */\n\n";
52 int find_base_len = 0;
63 te_verbose verbose_level = VERB_PROGRESS;
66 #define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
67 #define NOT_SILENT VLEVEL(VERB_FIXES)
69 pid_t process_chain_head = (pid_t) -1;
71 char* pz_curr_file; /* name of the current file under test/fix */
72 char* pz_curr_data; /* original contents of that file */
73 char* pz_temp_file; /* for DOS, a place to stash the temporary
74 fixed data between system(3) calls */
75 t_bool curr_data_mapped;
78 size_t ttl_data_size = 0;
87 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
88 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
89 regex_t incl_quote_re;
91 static void do_version (void) ATTRIBUTE_NORETURN;
92 char *load_file (const char *);
93 void run_compiles (void);
94 void initialize (int argc, char** argv);
97 /* External Source Code */
101 /* * * * * * * * * * * * * * * * * * *
105 extern int main (int, char **);
107 main (int argc, char** argv)
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 */
178 # ifdef SEPARATE_FIX_PROC
179 unlink( pz_temp_file );
188 static const char zFmt[] = "echo '%s'";
191 /* The 'version' option is really used to test that:
192 1. The program loads correctly (no missing libraries)
193 2. that we can compile all the regular expressions.
194 3. we can correctly run our server shell process
197 sprintf (zBuf, zFmt, program_id);
198 #ifndef SEPARATE_FIX_PROC
200 exit (strcmp (run_shell (zBuf), program_id));
202 exit (system (zBuf));
206 /* * * * * * * * * * * * */
209 initialize ( int argc, char** argv )
211 xmalloc_set_program_name (argv[0]);
219 if (strcmp (argv[1], "-v") == 0)
221 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
223 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
224 errno, xstrerror (errno), argv[1] );
230 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
235 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
236 receive the signal. A different setting is inheritable */
237 signal (SIGCHLD, SIG_DFL);
242 if (ISDIGIT ( *pz_verbose ))
243 verbose_level = (te_verbose)atoi( pz_verbose );
245 switch (*pz_verbose) {
248 verbose_level = VERB_SILENT; break;
252 verbose_level = VERB_FIXES; break;
256 verbose_level = VERB_APPLIES; break;
261 verbose_level = VERB_PROGRESS; break;
265 verbose_level = VERB_TESTS; break;
269 verbose_level = VERB_EVERYTHING; break;
271 if (verbose_level >= VERB_EVERYTHING) {
272 verbose_level = VERB_EVERYTHING;
273 fputs ("fixinc verbosity: EVERYTHING\n", stderr);
275 while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
277 if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
278 find_base_len = strlen( pz_find_base );
280 /* Compile all the regular expressions now.
281 That way, it is done only once for the whole run.
285 # ifdef SEPARATE_FIX_PROC
286 /* NULL as the first argument to `tempnam' causes it to DTRT
287 wrt the temporary directory where the file will be created. */
288 pz_temp_file = tempnam( NULL, "fxinc" );
291 signal (SIGQUIT, SIG_IGN);
292 signal (SIGIOT, SIG_IGN);
293 signal (SIGPIPE, SIG_IGN);
294 signal (SIGALRM, SIG_IGN);
295 signal (SIGTERM, SIG_IGN);
298 /* * * * * * * * * * * * *
300 load_file loads all the contents of a file into malloc-ed memory.
301 Its argument is the name of the file to read in; the returned
302 result is the NUL terminated contents of the file. The file
303 is presumed to be an ASCII text file containing no NULs. */
305 load_file ( const char* fname )
310 if (stat (fname, &stbf) != 0)
313 fprintf (stderr, "error %d (%s) stat-ing %s\n",
314 errno, xstrerror (errno), fname );
315 return (char *) NULL;
317 if (stbf.st_size == 0)
320 /* Make the data map size one larger than the file size for documentation
321 purposes. Truth is that there will be a following NUL character if
322 the file size is not a multiple of the page size. If it is a multiple,
323 then this adjustment sometimes fails anyway. */
324 data_map_size = stbf.st_size+1;
325 data_map_fd = open (fname, O_RDONLY);
326 ttl_data_size += data_map_size-1;
331 fprintf (stderr, "error %d (%s) opening %s for read\n",
332 errno, xstrerror (errno), fname);
336 #ifdef HAVE_MMAP_FILE
337 curr_data_mapped = BOOL_TRUE;
339 /* IF the file size is a multiple of the page size,
340 THEN sometimes you will seg fault trying to access a trailing byte */
341 if ((stbf.st_size & (getpagesize()-1)) == 0)
342 res = (char*)BAD_ADDR;
344 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
345 MAP_PRIVATE, data_map_fd, 0);
346 if (res == (char*)BAD_ADDR)
349 FILE* fp = fdopen (data_map_fd, "r");
350 curr_data_mapped = BOOL_FALSE;
351 res = load_file_data (fp);
359 machine_matches( tFixDesc* p_fixd )
361 # ifndef SEPARATE_FIX_PROC
362 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
364 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
365 tSCC skip[] = "skip"; /* 4 bytes */
366 tSCC run[] = "run"; /* 3 bytes */
367 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
369 const char **papz_machs = p_fixd->papz_machs;
371 const char *pz_sep = "";
374 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
376 /* Start the case statement */
378 sprintf (cmd_buf, case_fmt, pz_machine);
379 pz = cmd_buf + strlen (cmd_buf);
381 /* Determine if a match means to apply the fix or not apply it */
383 if (p_fixd->fd_flags & FD_MACH_IFNOT)
394 /* Emit all the machine names. If there are more than one,
395 then we will insert " | \\\n" between the names */
399 const char* pz_mach = *(papz_machs++);
401 if (pz_mach == (const char*) NULL)
403 sprintf (pz, "%s%s", pz_sep, pz_mach);
408 /* Now emit the match and not-match actions and the esac */
410 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
413 The result will start either with 's' or 'r'. */
417 pz = run_shell (cmd_buf);
422 p_fixd->fd_flags |= FD_SKIP_TEST;
428 # else /* is SEPARATE_FIX_PROC */
429 const char **papz_machs = p_fixd->papz_machs;
430 int invert = (p_fixd->fd_flags & FD_MACH_IFNOT) != 0;
433 const char* pz_mach = *(papz_machs++);
435 if (pz_mach == (const char*) NULL)
437 if (strstr (pz_mach, "dos") != NULL && !invert)
441 p_fixd->fd_flags |= FD_SKIP_TEST;
446 /* * * * * * * * * * * * *
448 run_compiles run all the regexp compiles for all the fixes once.
453 tFixDesc *p_fixd = fixDescList;
454 int fix_ct = FIX_COUNT;
455 regex_t *p_re = XCNEWVEC (regex_t, REGEX_COUNT);
457 /* Make sure compile_re does not stumble across invalid data */
459 memset (&incl_quote_re, '\0', sizeof (regex_t));
461 compile_re (incl_quote_pat, &incl_quote_re, 1,
462 "quoted include", "run_compiles");
464 /* Allow machine name tests to be ignored (testing, mainly) */
466 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
467 pz_machine = (char*)NULL;
469 /* FOR every fixup, ... */
472 tTestDesc *p_test = p_fixd->p_test_desc;
473 int test_ct = p_fixd->test_ct;
475 /* IF the machine type pointer is not NULL (we are not in test mode)
476 AND this test is for or not done on particular machines
479 if ( (pz_machine != NULL)
480 && (p_fixd->papz_machs != (const char**) NULL)
481 && ! machine_matches (p_fixd) )
484 /* FOR every test for the fixup, ... */
486 while (--test_ct >= 0)
488 switch (p_test->type)
492 p_test->p_test_regex = p_re++;
493 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
494 "select test", p_fixd->fix_name);
500 while (p_fixd++, --fix_ct > 0);
504 /* * * * * * * * * * * * *
506 create_file Create the output modified file.
507 Input: the name of the file to create
508 Returns: a file pointer to the new, open file */
510 #if defined(S_IRUSR) && defined(S_IWUSR) && \
511 defined(S_IRGRP) && defined(S_IROTH)
513 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
515 # define S_IRALL 0644
518 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
519 defined(S_IROTH) && defined(S_IXOTH)
521 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
523 # define S_DIRALL 0755
532 char fname[MAXPATHLEN];
534 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
536 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
538 /* We may need to create the directories needed... */
539 if ((fd < 0) && (errno == ENOENT))
541 char *pz_dir = strchr (fname + 1, '/');
544 while (pz_dir != (char *) NULL)
547 if (stat (fname, &stbf) < 0)
552 mkdir (fname, S_IFDIR | S_DIRALL);
557 pz_dir = strchr (pz_dir + 1, '/');
560 /* Now, lets try the open again... */
561 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
565 fprintf (stderr, "Error %d (%s) creating %s\n",
566 errno, xstrerror (errno), fname);
570 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
571 pf = fdopen (fd, "w");
574 * IF pz_machine is NULL, then we are in some sort of test mode.
575 * Do not insert the current directory name. Use a constant string.
577 fprintf (pf, z_std_preamble,
587 /* * * * * * * * * * * * *
589 test_test make sure a shell-style test expression passes.
590 Input: a pointer to the descriptor of the test to run and
591 the name of the file that we might want to fix
592 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
593 shell script we run. */
594 #ifndef SEPARATE_FIX_PROC
596 test_test (tTestDesc* p_test, char* pz_test_file)
600 if ( test %s ) > /dev/null 2>&1\n\
608 static char cmd_buf[4096];
610 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
611 pz_res = run_shell (cmd_buf);
623 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
628 free ((void *) pz_res);
633 * IF we are in MS-DOS land, then whatever shell-type test is required
634 * will, by definition, fail
636 #define test_test(t,tf) SKIP_FIX
639 /* * * * * * * * * * * * *
641 egrep_test make sure an egrep expression is found in the file text.
642 Input: a pointer to the descriptor of the test to run and
643 the pointer to the contents of the file under suspicion
644 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
646 The caller may choose to reverse meaning if the sense of the test
650 egrep_test (char* pz_data, tTestDesc* p_test)
653 if (p_test->p_test_regex == 0)
654 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
655 p_test->pz_test_text);
657 if (xregexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
663 /* * * * * * * * * * * * *
665 quoted_file_exists Make sure that a file exists before we emit
666 the file name. If we emit the name, our invoking shell will try
667 to copy a non-existing file into the destination directory. */
670 quoted_file_exists (const char* pz_src_path,
671 const char* pz_file_path,
674 char z[ MAXPATHLEN ];
676 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
677 pz = z + strlen ( z );
680 char ch = *pz_file++;
690 if (stat (z, &s) != 0)
692 return S_ISREG( s.st_mode );
697 /* * * * * * * * * * * * *
701 The syntax, `#include "file.h"' specifies that the compiler is to
702 search the local directory of the current file before the include
703 list. Consequently, if we have modified a header and stored it in
704 another directory, any files that are included by that modified
705 file in that fashion must also be copied into this new directory.
706 This routine finds those flavors of #include and for each one found
709 1. source directory of the original file
710 2. the relative path file name of the #includ-ed file
711 3. the full destination path for this file
713 Input: the text of the file, the file name and a pointer to the
714 match list where the match information was stored.
715 Result: internally nothing. The results are written to stdout
716 for interpretation by the invoking shell */
720 extract_quoted_files (char* pz_data,
721 const char* pz_fixed_file,
722 regmatch_t* p_re_match)
724 char *pz_dir_end = strrchr (pz_fixed_file, '/');
725 char *pz_incl_quot = pz_data;
727 if (VLEVEL( VERB_APPLIES ))
728 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
730 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
731 If there is none, then it is in our current directory, ".". */
733 if (pz_dir_end == (char *) NULL)
740 pz_incl_quot += p_re_match->rm_so;
742 /* Skip forward to the included file name */
743 while (*pz_incl_quot != '"')
746 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
748 /* Print the source directory and the subdirectory
749 of the file in question. */
750 printf ("%s %s/", pz_src_dir, pz_fixed_file);
751 pz_dir_end = pz_incl_quot;
753 /* Append to the directory the relative path of the desired file */
754 while (*pz_incl_quot != '"')
755 putc (*pz_incl_quot++, stdout);
757 /* Now print the destination directory appended with the
758 relative path of the desired file */
759 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
760 while (*pz_dir_end != '"')
761 putc (*pz_dir_end++, stdout);
767 /* Find the next entry */
768 if (xregexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
774 /* * * * * * * * * * * * *
776 Somebody wrote a *_fix subroutine that we must call.
778 #ifndef SEPARATE_FIX_PROC
780 internal_fix (int read_fd, tFixDesc* p_fixd)
786 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
792 pid_t childid = fork();
815 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
818 static int failCt = 0;
819 if ((errno != EAGAIN) || (++failCt > 10))
826 * Close our current stdin and stdout
828 close (STDIN_FILENO);
829 close (STDOUT_FILENO);
833 * Make the fd passed in the stdin, and the write end of
834 * the new pipe become the stdout.
836 dup2 (fd[1], STDOUT_FILENO);
837 dup2 (read_fd, STDIN_FILENO);
839 apply_fix (p_fixd, pz_curr_file);
842 #endif /* !SEPARATE_FIX_PROC */
845 #ifdef SEPARATE_FIX_PROC
847 fix_with_system (tFixDesc* p_fixd,
856 if (p_fixd->fd_flags & FD_SUBROUTINE)
858 static const char z_applyfix_prog[] =
859 "/../fixincludes/applyfix" EXE_EXT;
863 + strlen (pz_orig_dir)
864 + sizeof (z_applyfix_prog)
865 + strlen (pz_fix_file)
866 + strlen (pz_file_source)
867 + strlen (pz_temp_file);
869 /* Allocate something sure to be big enough for our purposes */
870 pz_cmd = XNEWVEC (char, argsize);
871 strcpy (pz_cmd, pz_orig_dir);
872 pz_scan = pz_cmd + strlen (pz_orig_dir);
874 strcpy (pz_scan, z_applyfix_prog);
876 /* IF we can't find the "applyfix" executable file at the first guess,
877 try one level higher up */
878 if (stat (pz_cmd, &buf) == -1)
880 strcpy (pz_scan, "/..");
881 strcpy (pz_scan+3, z_applyfix_prog);
884 pz_scan += strlen (pz_scan);
887 * Now add the fix number and file names that may be needed
889 sprintf (pz_scan, " %ld '%s' '%s' '%s'", p_fixd - fixDescList,
890 pz_fix_file, pz_file_source, pz_temp_file);
892 else /* NOT an "internal" fix: */
896 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
897 dst is a temporary file anyway, so we know there's no other
898 file by that name; and DOS's system(3) doesn't mind to
899 clobber existing file in redirection. Besides, with DOS 8+3
900 limited file namespace, we can easily lose if dst already has
901 an extension that is 3 or more characters long.
903 I do not think the 8+3 issue is relevant because all the files
904 we operate on are named "*.h", making 8+2 adequate. Anyway,
905 the following bizarre use of 'cat' only works on DOS boxes.
906 It causes the file to be dropped into a temporary file for
907 'cat' to read (pipes do not work on DOS). */
908 tSCC z_cmd_fmt[] = " '%s' | cat > '%s'";
910 /* Don't use positional formatting arguments because some lame-o
911 implementations cannot cope :-(. */
912 tSCC z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
914 tCC** ppArgs = p_fixd->patch_args;
916 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
917 + strlen( pz_file_source );
922 * Compute the size of the command line. Add lotsa extra space
923 * because some of the args to sed use lotsa single quotes.
924 * (This requires three extra bytes per quote. Here we allow
925 * for up to 8 single quotes for each argument, including the
926 * command name "sed" itself. Nobody will *ever* need more. :)
930 tCC* p_arg = *(ppArgs++);
933 argsize += 24 + strlen( p_arg );
936 /* Estimated buffer size we will need. */
937 pz_scan = pz_cmd = XNEWVEC (char, argsize);
938 /* How much of it do we allot to the program name and its
940 parg_size = argsize - parg_size;
942 ppArgs = p_fixd->patch_args;
945 * Copy the program name, unquoted
948 tCC* pArg = *(ppArgs++);
959 * Copy the program arguments, quoted
963 tCC* pArg = *(ppArgs++);
968 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
969 parg_size - (pz_scan - pz_cmd) );
971 * Make sure we don't overflow the buffer due to sloppy
974 while (pz_scan == (char*)NULL)
976 size_t already_filled = pz_scan_save - pz_cmd;
977 pz_cmd = xrealloc (pz_cmd, argsize += 100);
978 pz_scan_save = pz_scan = pz_cmd + already_filled;
980 pz_scan = make_raw_shell_str( pz_scan, pArg,
981 parg_size - (pz_scan - pz_cmd) );
986 * add the file machinations.
989 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
991 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
992 pz_temp_file, pz_temp_file, pz_temp_file);
996 free( (void*)pz_cmd );
999 /* * * * * * * * * * * * *
1001 This loop should only cycle for 1/2 of one loop.
1002 "chain_open" starts a process that uses "read_fd" as
1003 its stdin and returns the new fd this process will use
1006 #else /* is *NOT* SEPARATE_FIX_PROC */
1008 start_fixer (int read_fd, tFixDesc* p_fixd, char* pz_fix_file)
1013 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1014 return internal_fix (read_fd, p_fixd);
1016 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1023 tSCC z_cmd_fmt[] = "file='%s'\n%s";
1024 pz_cmd = XNEWVEC (char, strlen (p_fixd->patch_args[2])
1025 + sizeof (z_cmd_fmt) + strlen (pz_fix_file));
1026 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
1027 pz_cmd_save = p_fixd->patch_args[2];
1028 p_fixd->patch_args[2] = pz_cmd;
1031 /* Start a fix process, handing off the previous read fd for its
1032 stdin and getting a new fd that reads from the fix process' stdout.
1033 We normally will not loop, but we will up to 10 times if we keep
1034 getting "EAGAIN" errors.
1039 static int failCt = 0;
1042 fd = chain_open (read_fd,
1043 (tCC **) p_fixd->patch_args,
1044 (process_chain_head == -1)
1045 ? &process_chain_head : (pid_t *) NULL);
1053 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
1056 if ((errno != EAGAIN) || (++failCt > 10))
1057 exit (EXIT_FAILURE);
1061 /* IF we allocated a shell script command,
1062 THEN free it and restore the command format to the fix description */
1063 if (pz_cmd != (char*)NULL)
1065 free ((void*)pz_cmd);
1066 p_fixd->patch_args[2] = pz_cmd_save;
1074 /* * * * * * * * * * * * *
1076 Process the potential fixes for a particular include file.
1077 Input: the original text of the file and the file's name
1078 Result: none. A new file may or may not be created. */
1081 fix_applies (tFixDesc* p_fixd)
1083 const char *pz_fname = pz_curr_file;
1084 const char *pz_scan = p_fixd->file_list;
1088 # ifdef SEPARATE_FIX_PROC
1090 * There is only one fix that uses a shell script as of this writing.
1091 * I hope to nuke it anyway, it does not apply to DOS and it would
1092 * be painful to implement. Therefore, no "shell" fixes for DOS.
1094 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
1097 if (p_fixd->fd_flags & FD_SKIP_TEST)
1101 /* IF there is a file name restriction,
1102 THEN ensure the current file name matches one in the pattern */
1104 if (pz_scan != (char *) NULL)
1108 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1110 name_len = strlen (pz_fname);
1114 pz_scan = strstr (pz_scan + 1, pz_fname);
1115 /* IF we can't match the string at all,
1117 if (pz_scan == (char *) NULL)
1120 /* IF the match is surrounded by the '|' markers,
1121 THEN we found a full match -- time to run the tests */
1123 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1128 /* FOR each test, see if it fails.
1129 IF it does fail, then we go on to the next test */
1131 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1135 switch (p_test->type)
1138 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1140 if (VLEVEL( VERB_EVERYTHING ))
1141 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1142 pz_fname, p_fixd->test_ct - test_ct);
1149 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1151 if (VLEVEL( VERB_EVERYTHING ))
1152 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1153 pz_fname, p_fixd->test_ct - test_ct);
1160 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1162 if (VLEVEL( VERB_EVERYTHING ))
1163 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1164 pz_fname, p_fixd->test_ct - test_ct);
1172 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1175 if (VLEVEL( VERB_EVERYTHING ))
1176 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1177 pz_fname, p_fixd->test_ct - test_ct);
1189 /* * * * * * * * * * * * *
1191 Write out a replacement file */
1194 write_replacement (tFixDesc* p_fixd)
1196 const char* pz_text = p_fixd->patch_args[0];
1198 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1202 FILE* out_fp = create_file ();
1203 fputs (pz_text, out_fp);
1209 /* * * * * * * * * * * * *
1211 We have work to do. Read back in the output
1212 of the filtering chain. Compare each byte as we read it with
1213 the contents of the original file. As soon as we find any
1214 difference, we will create the output file, write out all
1215 the matched text and then copy any remaining data from the
1216 output of the filter chain.
1219 test_for_changes (int read_fd)
1221 FILE *in_fp = fdopen (read_fd, "r");
1222 FILE *out_fp = (FILE *) NULL;
1223 unsigned char *pz_cmp = (unsigned char*)pz_curr_data;
1235 ch &= 0xFF; /* all bytes are 8 bits */
1237 /* IF we are emitting the output
1238 THEN emit this character, too.
1240 if (out_fp != (FILE *) NULL)
1243 /* ELSE if this character does not match the original,
1244 THEN now is the time to start the output.
1246 else if (ch != *pz_cmp)
1248 out_fp = create_file ();
1253 /* IF there are matched data, write the matched part now. */
1254 if ((char*)pz_cmp != pz_curr_data)
1255 fwrite (pz_curr_data, (size_t)((char*)pz_cmp - pz_curr_data),
1258 /* Emit the current unmatching character */
1262 /* ELSE the character matches. Advance the compare ptr */
1266 /* IF we created the output file, ... */
1267 if (out_fp != (FILE *) NULL)
1271 /* Close the file and see if we have to worry about
1272 `#include "file.h"' constructs. */
1274 if (xregexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1275 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1279 close (read_fd); /* probably redundant, but I'm paranoid */
1283 /* * * * * * * * * * * * *
1285 Process the potential fixes for a particular include file.
1286 Input: the original text of the file and the file's name
1287 Result: none. A new file may or may not be created. */
1292 tFixDesc *p_fixd = fixDescList;
1293 int todo_ct = FIX_COUNT;
1295 # ifndef SEPARATE_FIX_PROC
1296 int num_children = 0;
1297 # else /* is SEPARATE_FIX_PROC */
1298 char* pz_file_source = pz_curr_file;
1301 if (access (pz_curr_file, R_OK) != 0)
1304 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1305 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1306 erno, xstrerror (erno));
1310 pz_curr_data = load_file (pz_curr_file);
1311 if (pz_curr_data == (char *) NULL)
1317 if (VLEVEL( VERB_PROGRESS ) && have_tty)
1318 fprintf (stderr, "%6lu %-50s \r",
1319 (unsigned long) data_map_size, pz_curr_file);
1321 # ifndef SEPARATE_FIX_PROC
1322 process_chain_head = NOPROCESS;
1324 /* For every fix in our fix list, ... */
1325 for (; todo_ct > 0; p_fixd++, todo_ct--)
1327 if (! fix_applies (p_fixd))
1330 if (VLEVEL( VERB_APPLIES ))
1331 fprintf (stderr, "Applying %-24s to %s\n",
1332 p_fixd->fix_name, pz_curr_file);
1334 if (p_fixd->fd_flags & FD_REPLACEMENT)
1336 write_replacement (p_fixd);
1341 /* IF we do not have a read pointer,
1342 THEN this is the first fix for the current file.
1343 Open the source file. That will be used as stdin for
1344 the first fix. Any subsequent fixes will use the
1345 stdout descriptor of the previous fix for its stdin. */
1349 read_fd = open (pz_curr_file, O_RDONLY);
1352 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1353 xstrerror (errno), pz_curr_file);
1354 exit (EXIT_FAILURE);
1357 /* Ensure we do not get duplicate output */
1362 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1366 /* IF we have a read-back file descriptor,
1367 THEN check for changes and write output if changed. */
1371 test_for_changes (read_fd);
1373 apply_ct += num_children;
1375 /* Wait for child processes created by chain_open()
1376 to avoid leaving zombies. */
1378 wait ((int *) NULL);
1379 } while (--num_children > 0);
1382 # else /* is SEPARATE_FIX_PROC */
1384 for (; todo_ct > 0; p_fixd++, todo_ct--)
1386 if (! fix_applies (p_fixd))
1389 if (VLEVEL( VERB_APPLIES ))
1390 fprintf (stderr, "Applying %-24s to %s\n",
1391 p_fixd->fix_name, pz_curr_file);
1393 if (p_fixd->fd_flags & FD_REPLACEMENT)
1395 write_replacement (p_fixd);
1399 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
1400 pz_file_source = pz_temp_file;
1403 read_fd = open (pz_temp_file, O_RDONLY);
1406 if (errno != ENOENT)
1407 fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
1408 errno, xstrerror (errno), pz_temp_file);
1412 test_for_changes (read_fd);
1413 /* Unlinking a file while it is still open is a Bad Idea on
1416 unlink (pz_temp_file);