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, 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
28 #ifndef SEPARATE_FIX_PROC
32 #if defined( HAVE_MMAP_FILE )
34 #define BAD_ADDR ((void*)-1)
37 #ifndef SEPARATE_FIX_PROC
41 /* The contents of this string are not very important. It is mostly
42 just used as part of the "I am alive and working" test. */
44 static const char program_id[] = "fixincl version 1.1";
46 /* This format will be used at the start of every generated file */
48 static const char z_std_preamble[] =
49 "/* DO NOT EDIT THIS FILE.\n\n\
50 It has been auto-edited by fixincludes from:\n\n\
52 This had to be done to correct non-standard usages in the\n\
53 original, manufacturer supplied header file. */\n\n";
55 int find_base_len = 0;
66 te_verbose verbose_level = VERB_PROGRESS;
69 #define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
70 #define NOT_SILENT VLEVEL(VERB_FIXES)
72 pid_t process_chain_head = (pid_t) -1;
74 char* pz_curr_file; /* name of the current file under test/fix */
75 char* pz_curr_data; /* original contents of that file */
76 char* pz_temp_file; /* for DOS, a place to stash the temporary
77 fixed data between system(3) calls */
78 t_bool curr_data_mapped;
81 size_t ttl_data_size = 0;
90 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
91 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
92 regex_t incl_quote_re;
94 static void do_version (void) ATTRIBUTE_NORETURN;
95 char *load_file (const char *);
96 void run_compiles (void);
97 void initialize (int argc, char** argv);
100 /* External Source Code */
104 /* * * * * * * * * * * * * * * * * * *
108 extern int main (int, char **);
110 main (int argc, char** argv)
114 initialize ( argc, argv );
116 have_tty = isatty (fileno (stderr));
118 /* Before anything else, ensure we can allocate our file name buffer. */
119 file_name_buf = load_file_data (stdin);
121 /* Because of the way server shells work, you have to keep stdin, out
122 and err open so that the proper input file does not get closed
125 freopen ("/dev/null", "r", stdin);
127 if (file_name_buf == (char *) NULL)
129 fputs ("No file names listed for fixing\n", stderr);
137 /* skip to start of name, past any "./" prefixes */
139 while (ISSPACE (*file_name_buf)) file_name_buf++;
140 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
143 /* Check for end of list */
145 if (*file_name_buf == NUL)
148 /* Set global file name pointer and find end of name */
150 pz_curr_file = file_name_buf;
151 pz_end = strchr( pz_curr_file, '\n' );
152 if (pz_end == (char*)NULL)
153 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
155 file_name_buf = pz_end + 1;
157 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
159 /* IF no name is found (blank line) or comment marker, skip line */
161 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
169 if (VLEVEL( VERB_PROGRESS )) {
172 Processed %5d files containing %d bytes \n\
173 Applying %5d fixes to %d files\n\
174 Altering %5d of them\n";
176 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
177 fixed_ct, altered_ct);
179 #endif /* DO_STATS */
181 # ifdef SEPARATE_FIX_PROC
182 unlink( pz_temp_file );
191 static const char zFmt[] = "echo '%s'";
194 /* The 'version' option is really used to test that:
195 1. The program loads correctly (no missing libraries)
196 2. that we can compile all the regular expressions.
197 3. we can correctly run our server shell process
200 sprintf (zBuf, zFmt, program_id);
201 #ifndef SEPARATE_FIX_PROC
203 exit (strcmp (run_shell (zBuf), program_id));
205 exit (system (zBuf));
209 /* * * * * * * * * * * * */
212 initialize ( int argc, char** argv )
214 xmalloc_set_program_name (argv[0]);
222 if (strcmp (argv[1], "-v") == 0)
224 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
226 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
227 errno, xstrerror (errno), argv[1] );
233 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
238 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
239 receive the signal. A different setting is inheritable */
240 signal (SIGCHLD, SIG_DFL);
245 if (ISDIGIT ( *pz_verbose ))
246 verbose_level = (te_verbose)atoi( pz_verbose );
248 switch (*pz_verbose) {
251 verbose_level = VERB_SILENT; break;
255 verbose_level = VERB_FIXES; break;
259 verbose_level = VERB_APPLIES; break;
264 verbose_level = VERB_PROGRESS; break;
268 verbose_level = VERB_TESTS; break;
272 verbose_level = VERB_EVERYTHING; break;
274 if (verbose_level >= VERB_EVERYTHING) {
275 verbose_level = VERB_EVERYTHING;
276 fputs ("fixinc verbosity: EVERYTHING\n", stderr);
278 while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
280 if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
281 find_base_len = strlen( pz_find_base );
283 /* Compile all the regular expressions now.
284 That way, it is done only once for the whole run.
288 # ifdef SEPARATE_FIX_PROC
289 /* NULL as the first argument to `tempnam' causes it to DTRT
290 wrt the temporary directory where the file will be created. */
291 pz_temp_file = tempnam( NULL, "fxinc" );
294 signal (SIGQUIT, SIG_IGN);
295 signal (SIGIOT, SIG_IGN);
296 signal (SIGPIPE, SIG_IGN);
297 signal (SIGALRM, SIG_IGN);
298 signal (SIGTERM, SIG_IGN);
301 /* * * * * * * * * * * * *
303 load_file loads all the contents of a file into malloc-ed memory.
304 Its argument is the name of the file to read in; the returned
305 result is the NUL terminated contents of the file. The file
306 is presumed to be an ASCII text file containing no NULs. */
308 load_file ( const char* fname )
313 if (stat (fname, &stbf) != 0)
316 fprintf (stderr, "error %d (%s) stat-ing %s\n",
317 errno, xstrerror (errno), fname );
318 return (char *) NULL;
320 if (stbf.st_size == 0)
323 /* Make the data map size one larger than the file size for documentation
324 purposes. Truth is that there will be a following NUL character if
325 the file size is not a multiple of the page size. If it is a multiple,
326 then this adjustment sometimes fails anyway. */
327 data_map_size = stbf.st_size+1;
328 data_map_fd = open (fname, O_RDONLY);
329 ttl_data_size += data_map_size-1;
334 fprintf (stderr, "error %d (%s) opening %s for read\n",
335 errno, xstrerror (errno), fname);
339 #ifdef HAVE_MMAP_FILE
340 curr_data_mapped = BOOL_TRUE;
342 /* IF the file size is a multiple of the page size,
343 THEN sometimes you will seg fault trying to access a trailing byte */
344 if ((stbf.st_size & (getpagesize()-1)) == 0)
345 res = (char*)BAD_ADDR;
347 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
348 MAP_PRIVATE, data_map_fd, 0);
349 if (res == (char*)BAD_ADDR)
352 FILE* fp = fdopen (data_map_fd, "r");
353 curr_data_mapped = BOOL_FALSE;
354 res = load_file_data (fp);
362 machine_matches( tFixDesc* p_fixd )
364 char const ** papz_machs = p_fixd->papz_machs;
365 int have_match = BOOL_FALSE;
369 char const * pz_mpat = *(papz_machs++);
372 if (fnmatch(pz_mpat, pz_machine, 0) == 0)
374 have_match = BOOL_TRUE;
379 if (p_fixd->fd_flags & FD_MACH_IFNOT)
384 /* * * * * * * * * * * * *
386 * run_compiles run all the regexp compiles for all the fixes once.
391 tFixDesc *p_fixd = fixDescList;
392 int fix_ct = FIX_COUNT;
393 regex_t *p_re = XCNEWVEC (regex_t, REGEX_COUNT);
395 /* Make sure compile_re does not stumble across invalid data */
397 memset (&incl_quote_re, '\0', sizeof (regex_t));
399 compile_re (incl_quote_pat, &incl_quote_re, 1,
400 "quoted include", "run_compiles");
402 /* Allow machine name tests to be ignored (testing, mainly) */
404 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
405 pz_machine = (char*)NULL;
407 /* FOR every fixup, ... */
410 tTestDesc *p_test = p_fixd->p_test_desc;
411 int test_ct = p_fixd->test_ct;
413 /* IF the machine type pointer is not NULL (we are not in test mode)
414 AND this test is for or not done on particular machines
417 if ( (pz_machine != NULL)
418 && (p_fixd->papz_machs != (const char**) NULL)
419 && ! machine_matches (p_fixd) )
422 /* FOR every test for the fixup, ... */
424 while (--test_ct >= 0)
426 switch (p_test->type)
430 p_test->p_test_regex = p_re++;
431 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
432 "select test", p_fixd->fix_name);
438 while (p_fixd++, --fix_ct > 0);
442 /* * * * * * * * * * * * *
444 create_file Create the output modified file.
445 Input: the name of the file to create
446 Returns: a file pointer to the new, open file */
448 #if defined(S_IRUSR) && defined(S_IWUSR) && \
449 defined(S_IRGRP) && defined(S_IROTH)
451 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
453 # define S_IRALL 0644
456 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
457 defined(S_IROTH) && defined(S_IXOTH)
459 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
461 # define S_DIRALL 0755
470 char fname[MAXPATHLEN];
472 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
474 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
476 /* We may need to create the directories needed... */
477 if ((fd < 0) && (errno == ENOENT))
479 char *pz_dir = strchr (fname + 1, '/');
482 while (pz_dir != (char *) NULL)
485 if (stat (fname, &stbf) < 0)
490 mkdir (fname, S_IFDIR | S_DIRALL);
495 pz_dir = strchr (pz_dir + 1, '/');
498 /* Now, lets try the open again... */
499 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
503 fprintf (stderr, "Error %d (%s) creating %s\n",
504 errno, xstrerror (errno), fname);
508 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
509 pf = fdopen (fd, "w");
512 * IF pz_machine is NULL, then we are in some sort of test mode.
513 * Do not insert the current directory name. Use a constant string.
515 fprintf (pf, z_std_preamble,
525 /* * * * * * * * * * * * *
527 test_test make sure a shell-style test expression passes.
528 Input: a pointer to the descriptor of the test to run and
529 the name of the file that we might want to fix
530 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
531 shell script we run. */
532 #ifndef SEPARATE_FIX_PROC
534 test_test (tTestDesc* p_test, char* pz_test_file)
538 if ( test %s ) > /dev/null 2>&1\n\
546 static char cmd_buf[4096];
548 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
549 pz_res = run_shell (cmd_buf);
561 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
566 free ((void *) pz_res);
571 * IF we are in MS-DOS land, then whatever shell-type test is required
572 * will, by definition, fail
574 #define test_test(t,tf) SKIP_FIX
577 /* * * * * * * * * * * * *
579 egrep_test make sure an egrep expression is found in the file text.
580 Input: a pointer to the descriptor of the test to run and
581 the pointer to the contents of the file under suspicion
582 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
584 The caller may choose to reverse meaning if the sense of the test
588 egrep_test (char* pz_data, tTestDesc* p_test)
591 if (p_test->p_test_regex == 0)
592 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
593 p_test->pz_test_text);
595 if (xregexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
601 /* * * * * * * * * * * * *
603 quoted_file_exists Make sure that a file exists before we emit
604 the file name. If we emit the name, our invoking shell will try
605 to copy a non-existing file into the destination directory. */
608 quoted_file_exists (const char* pz_src_path,
609 const char* pz_file_path,
612 char z[ MAXPATHLEN ];
614 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
615 pz = z + strlen ( z );
618 char ch = *pz_file++;
628 if (stat (z, &s) != 0)
630 return S_ISREG( s.st_mode );
635 /* * * * * * * * * * * * *
639 The syntax, `#include "file.h"' specifies that the compiler is to
640 search the local directory of the current file before the include
641 list. Consequently, if we have modified a header and stored it in
642 another directory, any files that are included by that modified
643 file in that fashion must also be copied into this new directory.
644 This routine finds those flavors of #include and for each one found
647 1. source directory of the original file
648 2. the relative path file name of the #includ-ed file
649 3. the full destination path for this file
651 Input: the text of the file, the file name and a pointer to the
652 match list where the match information was stored.
653 Result: internally nothing. The results are written to stdout
654 for interpretation by the invoking shell */
658 extract_quoted_files (char* pz_data,
659 const char* pz_fixed_file,
660 regmatch_t* p_re_match)
662 char *pz_dir_end = strrchr (pz_fixed_file, '/');
663 char *pz_incl_quot = pz_data;
665 if (VLEVEL( VERB_APPLIES ))
666 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
668 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
669 If there is none, then it is in our current directory, ".". */
671 if (pz_dir_end == (char *) NULL)
678 pz_incl_quot += p_re_match->rm_so;
680 /* Skip forward to the included file name */
681 while (*pz_incl_quot != '"')
684 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
686 /* Print the source directory and the subdirectory
687 of the file in question. */
688 printf ("%s %s/", pz_src_dir, pz_fixed_file);
689 pz_dir_end = pz_incl_quot;
691 /* Append to the directory the relative path of the desired file */
692 while (*pz_incl_quot != '"')
693 putc (*pz_incl_quot++, stdout);
695 /* Now print the destination directory appended with the
696 relative path of the desired file */
697 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
698 while (*pz_dir_end != '"')
699 putc (*pz_dir_end++, stdout);
705 /* Find the next entry */
706 if (xregexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
712 /* * * * * * * * * * * * *
714 Somebody wrote a *_fix subroutine that we must call.
716 #ifndef SEPARATE_FIX_PROC
718 internal_fix (int read_fd, tFixDesc* p_fixd)
724 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
730 pid_t childid = fork();
753 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
756 static int failCt = 0;
757 if ((errno != EAGAIN) || (++failCt > 10))
764 * Close our current stdin and stdout
766 close (STDIN_FILENO);
767 close (STDOUT_FILENO);
771 * Make the fd passed in the stdin, and the write end of
772 * the new pipe become the stdout.
774 dup2 (fd[1], STDOUT_FILENO);
775 dup2 (read_fd, STDIN_FILENO);
777 apply_fix (p_fixd, pz_curr_file);
780 #endif /* !SEPARATE_FIX_PROC */
783 #ifdef SEPARATE_FIX_PROC
785 fix_with_system (tFixDesc* p_fixd,
794 if (p_fixd->fd_flags & FD_SUBROUTINE)
796 static const char z_applyfix_prog[] =
797 "/../fixincludes/applyfix" EXE_EXT;
801 + strlen (pz_orig_dir)
802 + sizeof (z_applyfix_prog)
803 + strlen (pz_fix_file)
804 + strlen (pz_file_source)
805 + strlen (pz_temp_file);
807 /* Allocate something sure to be big enough for our purposes */
808 pz_cmd = XNEWVEC (char, argsize);
809 strcpy (pz_cmd, pz_orig_dir);
810 pz_scan = pz_cmd + strlen (pz_orig_dir);
812 strcpy (pz_scan, z_applyfix_prog);
814 /* IF we can't find the "applyfix" executable file at the first guess,
815 try one level higher up */
816 if (stat (pz_cmd, &buf) == -1)
818 strcpy (pz_scan, "/..");
819 strcpy (pz_scan+3, z_applyfix_prog);
822 pz_scan += strlen (pz_scan);
825 * Now add the fix number and file names that may be needed
827 sprintf (pz_scan, " %ld '%s' '%s' '%s'", p_fixd - fixDescList,
828 pz_fix_file, pz_file_source, pz_temp_file);
830 else /* NOT an "internal" fix: */
834 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
835 dst is a temporary file anyway, so we know there's no other
836 file by that name; and DOS's system(3) doesn't mind to
837 clobber existing file in redirection. Besides, with DOS 8+3
838 limited file namespace, we can easily lose if dst already has
839 an extension that is 3 or more characters long.
841 I do not think the 8+3 issue is relevant because all the files
842 we operate on are named "*.h", making 8+2 adequate. Anyway,
843 the following bizarre use of 'cat' only works on DOS boxes.
844 It causes the file to be dropped into a temporary file for
845 'cat' to read (pipes do not work on DOS). */
846 tSCC z_cmd_fmt[] = " '%s' | cat > '%s'";
848 /* Don't use positional formatting arguments because some lame-o
849 implementations cannot cope :-(. */
850 tSCC z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
852 tCC** ppArgs = p_fixd->patch_args;
854 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
855 + strlen( pz_file_source );
860 * Compute the size of the command line. Add lotsa extra space
861 * because some of the args to sed use lotsa single quotes.
862 * (This requires three extra bytes per quote. Here we allow
863 * for up to 8 single quotes for each argument, including the
864 * command name "sed" itself. Nobody will *ever* need more. :)
868 tCC* p_arg = *(ppArgs++);
871 argsize += 24 + strlen( p_arg );
874 /* Estimated buffer size we will need. */
875 pz_scan = pz_cmd = XNEWVEC (char, argsize);
876 /* How much of it do we allot to the program name and its
878 parg_size = argsize - parg_size;
880 ppArgs = p_fixd->patch_args;
883 * Copy the program name, unquoted
886 tCC* pArg = *(ppArgs++);
897 * Copy the program arguments, quoted
901 tCC* pArg = *(ppArgs++);
906 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
907 parg_size - (pz_scan - pz_cmd) );
909 * Make sure we don't overflow the buffer due to sloppy
912 while (pz_scan == (char*)NULL)
914 size_t already_filled = pz_scan_save - pz_cmd;
915 pz_cmd = xrealloc (pz_cmd, argsize += 100);
916 pz_scan_save = pz_scan = pz_cmd + already_filled;
918 pz_scan = make_raw_shell_str( pz_scan, pArg,
919 parg_size - (pz_scan - pz_cmd) );
924 * add the file machinations.
927 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
929 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
930 pz_temp_file, pz_temp_file, pz_temp_file);
934 free( (void*)pz_cmd );
937 /* * * * * * * * * * * * *
939 This loop should only cycle for 1/2 of one loop.
940 "chain_open" starts a process that uses "read_fd" as
941 its stdin and returns the new fd this process will use
944 #else /* is *NOT* SEPARATE_FIX_PROC */
946 start_fixer (int read_fd, tFixDesc* p_fixd, char* pz_fix_file)
951 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
952 return internal_fix (read_fd, p_fixd);
954 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
961 tSCC z_cmd_fmt[] = "file='%s'\n%s";
962 pz_cmd = XNEWVEC (char, strlen (p_fixd->patch_args[2])
963 + sizeof (z_cmd_fmt) + strlen (pz_fix_file));
964 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
965 pz_cmd_save = p_fixd->patch_args[2];
966 p_fixd->patch_args[2] = pz_cmd;
969 /* Start a fix process, handing off the previous read fd for its
970 stdin and getting a new fd that reads from the fix process' stdout.
971 We normally will not loop, but we will up to 10 times if we keep
972 getting "EAGAIN" errors.
977 static int failCt = 0;
980 fd = chain_open (read_fd,
981 (tCC **) p_fixd->patch_args,
982 (process_chain_head == -1)
983 ? &process_chain_head : (pid_t *) NULL);
991 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
994 if ((errno != EAGAIN) || (++failCt > 10))
999 /* IF we allocated a shell script command,
1000 THEN free it and restore the command format to the fix description */
1001 if (pz_cmd != (char*)NULL)
1003 free ((void*)pz_cmd);
1004 p_fixd->patch_args[2] = pz_cmd_save;
1012 /* * * * * * * * * * * * *
1014 * Process the potential fixes for a particular include file.
1015 * Input: the original text of the file and the file's name
1016 * Result: none. A new file may or may not be created.
1019 fix_applies (tFixDesc* p_fixd)
1021 const char *pz_fname = pz_curr_file;
1022 const char *pz_scan = p_fixd->file_list;
1026 #ifdef SEPARATE_FIX_PROC
1028 * There is only one fix that uses a shell script as of this writing.
1029 * I hope to nuke it anyway, it does not apply to DOS and it would
1030 * be painful to implement. Therefore, no "shell" fixes for DOS.
1032 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
1035 if (p_fixd->fd_flags & FD_SKIP_TEST)
1039 /* IF there is a file name restriction,
1040 THEN ensure the current file name matches one in the pattern */
1042 if (pz_scan != (char *) NULL)
1046 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1048 name_len = strlen (pz_fname);
1052 if (fnmatch (pz_scan, pz_fname, 0) == 0)
1054 pz_scan += strlen (pz_scan) + 1;
1055 if (*pz_scan == NUL)
1060 /* FOR each test, see if it fails.
1061 IF it does fail, then we go on to the next test */
1063 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1067 switch (p_test->type)
1070 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1072 if (VLEVEL( VERB_EVERYTHING ))
1073 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1074 pz_fname, p_fixd->test_ct - test_ct);
1081 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1083 if (VLEVEL( VERB_EVERYTHING ))
1084 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1085 pz_fname, p_fixd->test_ct - test_ct);
1092 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1094 if (VLEVEL( VERB_EVERYTHING ))
1095 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1096 pz_fname, p_fixd->test_ct - test_ct);
1104 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1107 if (VLEVEL( VERB_EVERYTHING ))
1108 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1109 pz_fname, p_fixd->test_ct - test_ct);
1121 /* * * * * * * * * * * * *
1123 Write out a replacement file */
1126 write_replacement (tFixDesc* p_fixd)
1128 const char* pz_text = p_fixd->patch_args[0];
1130 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1134 FILE* out_fp = create_file ();
1135 size_t sz = strlen (pz_text);
1136 fwrite (pz_text, sz, 1, out_fp);
1137 if (pz_text[ sz-1 ] != '\n')
1138 fputc ('\n', out_fp);
1144 /* * * * * * * * * * * * *
1146 We have work to do. Read back in the output
1147 of the filtering chain. Compare each byte as we read it with
1148 the contents of the original file. As soon as we find any
1149 difference, we will create the output file, write out all
1150 the matched text and then copy any remaining data from the
1151 output of the filter chain.
1154 test_for_changes (int read_fd)
1156 FILE *in_fp = fdopen (read_fd, "r");
1157 FILE *out_fp = (FILE *) NULL;
1158 unsigned char *pz_cmp = (unsigned char*)pz_curr_data;
1170 ch &= 0xFF; /* all bytes are 8 bits */
1172 /* IF we are emitting the output
1173 THEN emit this character, too.
1175 if (out_fp != (FILE *) NULL)
1178 /* ELSE if this character does not match the original,
1179 THEN now is the time to start the output.
1181 else if (ch != *pz_cmp)
1183 out_fp = create_file ();
1188 /* IF there are matched data, write the matched part now. */
1189 if ((char*)pz_cmp != pz_curr_data)
1190 fwrite (pz_curr_data, (size_t)((char*)pz_cmp - pz_curr_data),
1193 /* Emit the current unmatching character */
1197 /* ELSE the character matches. Advance the compare ptr */
1201 /* IF we created the output file, ... */
1202 if (out_fp != (FILE *) NULL)
1206 /* Close the file and see if we have to worry about
1207 `#include "file.h"' constructs. */
1209 if (xregexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1210 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1214 close (read_fd); /* probably redundant, but I'm paranoid */
1218 /* * * * * * * * * * * * *
1220 Process the potential fixes for a particular include file.
1221 Input: the original text of the file and the file's name
1222 Result: none. A new file may or may not be created. */
1227 tFixDesc *p_fixd = fixDescList;
1228 int todo_ct = FIX_COUNT;
1230 # ifndef SEPARATE_FIX_PROC
1231 int num_children = 0;
1232 # else /* is SEPARATE_FIX_PROC */
1233 char* pz_file_source = pz_curr_file;
1236 if (access (pz_curr_file, R_OK) != 0)
1239 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1240 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1241 erno, xstrerror (erno));
1245 pz_curr_data = load_file (pz_curr_file);
1246 if (pz_curr_data == (char *) NULL)
1252 if (VLEVEL( VERB_PROGRESS ) && have_tty)
1253 fprintf (stderr, "%6lu %-50s \r",
1254 (unsigned long) data_map_size, pz_curr_file);
1256 # ifndef SEPARATE_FIX_PROC
1257 process_chain_head = NOPROCESS;
1259 /* For every fix in our fix list, ... */
1260 for (; todo_ct > 0; p_fixd++, todo_ct--)
1262 if (! fix_applies (p_fixd))
1265 if (VLEVEL( VERB_APPLIES ))
1266 fprintf (stderr, "Applying %-24s to %s\n",
1267 p_fixd->fix_name, pz_curr_file);
1269 if (p_fixd->fd_flags & FD_REPLACEMENT)
1271 write_replacement (p_fixd);
1276 /* IF we do not have a read pointer,
1277 THEN this is the first fix for the current file.
1278 Open the source file. That will be used as stdin for
1279 the first fix. Any subsequent fixes will use the
1280 stdout descriptor of the previous fix for its stdin. */
1284 read_fd = open (pz_curr_file, O_RDONLY);
1287 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1288 xstrerror (errno), pz_curr_file);
1289 exit (EXIT_FAILURE);
1292 /* Ensure we do not get duplicate output */
1297 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1301 /* IF we have a read-back file descriptor,
1302 THEN check for changes and write output if changed. */
1306 test_for_changes (read_fd);
1308 apply_ct += num_children;
1310 /* Wait for child processes created by chain_open()
1311 to avoid leaving zombies. */
1313 wait ((int *) NULL);
1314 } while (--num_children > 0);
1317 # else /* is SEPARATE_FIX_PROC */
1319 for (; todo_ct > 0; p_fixd++, todo_ct--)
1321 if (! fix_applies (p_fixd))
1324 if (VLEVEL( VERB_APPLIES ))
1325 fprintf (stderr, "Applying %-24s to %s\n",
1326 p_fixd->fix_name, pz_curr_file);
1328 if (p_fixd->fd_flags & FD_REPLACEMENT)
1330 write_replacement (p_fixd);
1334 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
1335 pz_file_source = pz_temp_file;
1338 read_fd = open (pz_temp_file, O_RDONLY);
1341 if (errno != ENOENT)
1342 fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
1343 errno, xstrerror (errno), pz_temp_file);
1347 test_for_changes (read_fd);
1348 /* Unlinking a file while it is still open is a Bad Idea on
1351 unlink (pz_temp_file);