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. */
27 #ifndef SEPARATE_FIX_PROC
31 #if defined( HAVE_MMAP_FILE )
33 #define BAD_ADDR ((void*)-1)
36 #ifndef SEPARATE_FIX_PROC
40 /* The contents of this string are not very important. It is mostly
41 just used as part of the "I am alive and working" test. */
43 static const char program_id
[] = "fixincl version 1.1";
45 /* This format will be used at the start of every generated file */
47 static const char z_std_preamble
[] =
48 "/* DO NOT EDIT THIS FILE.\n\n\
49 It has been auto-edited by fixincludes from:\n\n\
51 This had to be done to correct non-standard usages in the\n\
52 original, manufacturer supplied header file. */\n\n";
54 int find_base_len
= 0;
65 te_verbose verbose_level
= VERB_PROGRESS
;
68 #define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
69 #define NOT_SILENT VLEVEL(VERB_FIXES)
71 pid_t process_chain_head
= (pid_t
) -1;
73 char* pz_curr_file
; /* name of the current file under test/fix */
74 char* pz_curr_data
; /* original contents of that file */
75 char* pz_temp_file
; /* for DOS, a place to stash the temporary
76 fixed data between system(3) calls */
77 t_bool curr_data_mapped
;
80 size_t ttl_data_size
= 0;
89 const char incl_quote_pat
[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
90 tSCC z_fork_err
[] = "Error %d (%s) starting filter process for %s\n";
91 regex_t incl_quote_re
;
93 static void do_version (void) ATTRIBUTE_NORETURN
;
94 char *load_file (const char *);
95 void run_compiles (void);
96 void initialize (int argc
, char** argv
);
99 /* External Source Code */
103 /* * * * * * * * * * * * * * * * * * *
107 extern int main (int, char **);
109 main (int argc
, char** argv
)
113 initialize ( argc
, argv
);
115 have_tty
= isatty (fileno (stderr
));
117 /* Before anything else, ensure we can allocate our file name buffer. */
118 file_name_buf
= load_file_data (stdin
);
120 /* Because of the way server shells work, you have to keep stdin, out
121 and err open so that the proper input file does not get closed
124 freopen ("/dev/null", "r", stdin
);
126 if (file_name_buf
== (char *) NULL
)
128 fputs ("No file names listed for fixing\n", stderr
);
136 /* skip to start of name, past any "./" prefixes */
138 while (ISSPACE (*file_name_buf
)) file_name_buf
++;
139 while ((file_name_buf
[0] == '.') && (file_name_buf
[1] == '/'))
142 /* Check for end of list */
144 if (*file_name_buf
== NUL
)
147 /* Set global file name pointer and find end of name */
149 pz_curr_file
= file_name_buf
;
150 pz_end
= strchr( pz_curr_file
, '\n' );
151 if (pz_end
== (char*)NULL
)
152 pz_end
= file_name_buf
= pz_curr_file
+ strlen (pz_curr_file
);
154 file_name_buf
= pz_end
+ 1;
156 while ((pz_end
> pz_curr_file
) && ISSPACE( pz_end
[-1])) pz_end
--;
158 /* IF no name is found (blank line) or comment marker, skip line */
160 if ((pz_curr_file
== pz_end
) || (*pz_curr_file
== '#'))
168 if (VLEVEL( VERB_PROGRESS
)) {
171 Processed %5d files containing %d bytes \n\
172 Applying %5d fixes to %d files\n\
173 Altering %5d of them\n";
175 fprintf (stderr
, zFmt
, process_ct
, ttl_data_size
, apply_ct
,
176 fixed_ct
, altered_ct
);
178 #endif /* DO_STATS */
180 # ifdef SEPARATE_FIX_PROC
181 unlink( pz_temp_file
);
190 static const char zFmt
[] = "echo '%s'";
193 /* The 'version' option is really used to test that:
194 1. The program loads correctly (no missing libraries)
195 2. that we can compile all the regular expressions.
196 3. we can correctly run our server shell process
199 sprintf (zBuf
, zFmt
, program_id
);
200 #ifndef SEPARATE_FIX_PROC
202 exit (strcmp (run_shell (zBuf
), program_id
));
204 exit (system (zBuf
));
208 /* * * * * * * * * * * * */
211 initialize ( int argc
, char** argv
)
213 xmalloc_set_program_name (argv
[0]);
221 if (strcmp (argv
[1], "-v") == 0)
223 if (freopen (argv
[1], "r", stdin
) == (FILE*)NULL
)
225 fprintf (stderr
, "Error %d (%s) reopening %s as stdin\n",
226 errno
, xstrerror (errno
), argv
[1] );
232 fputs ("fixincl ERROR: too many command line arguments\n", stderr
);
237 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
238 receive the signal. A different setting is inheritable */
239 signal (SIGCHLD
, SIG_DFL
);
244 if (ISDIGIT ( *pz_verbose
))
245 verbose_level
= (te_verbose
)atoi( pz_verbose
);
247 switch (*pz_verbose
) {
250 verbose_level
= VERB_SILENT
; break;
254 verbose_level
= VERB_FIXES
; break;
258 verbose_level
= VERB_APPLIES
; break;
263 verbose_level
= VERB_PROGRESS
; break;
267 verbose_level
= VERB_TESTS
; break;
271 verbose_level
= VERB_EVERYTHING
; break;
273 if (verbose_level
>= VERB_EVERYTHING
) {
274 verbose_level
= VERB_EVERYTHING
;
275 fputs ("fixinc verbosity: EVERYTHING\n", stderr
);
277 while ((pz_find_base
[0] == '.') && (pz_find_base
[1] == '/'))
279 if ((pz_find_base
[0] != '.') || (pz_find_base
[1] != NUL
))
280 find_base_len
= strlen( pz_find_base
);
282 /* Compile all the regular expressions now.
283 That way, it is done only once for the whole run.
287 # ifdef SEPARATE_FIX_PROC
288 /* NULL as the first argument to `tempnam' causes it to DTRT
289 wrt the temporary directory where the file will be created. */
290 pz_temp_file
= tempnam( NULL
, "fxinc" );
293 signal (SIGQUIT
, SIG_IGN
);
294 signal (SIGIOT
, SIG_IGN
);
295 signal (SIGPIPE
, SIG_IGN
);
296 signal (SIGALRM
, SIG_IGN
);
297 signal (SIGTERM
, SIG_IGN
);
300 /* * * * * * * * * * * * *
302 load_file loads all the contents of a file into malloc-ed memory.
303 Its argument is the name of the file to read in; the returned
304 result is the NUL terminated contents of the file. The file
305 is presumed to be an ASCII text file containing no NULs. */
307 load_file ( const char* fname
)
312 if (stat (fname
, &stbf
) != 0)
315 fprintf (stderr
, "error %d (%s) stat-ing %s\n",
316 errno
, xstrerror (errno
), fname
);
317 return (char *) NULL
;
319 if (stbf
.st_size
== 0)
322 /* Make the data map size one larger than the file size for documentation
323 purposes. Truth is that there will be a following NUL character if
324 the file size is not a multiple of the page size. If it is a multiple,
325 then this adjustment sometimes fails anyway. */
326 data_map_size
= stbf
.st_size
+1;
327 data_map_fd
= open (fname
, O_RDONLY
);
328 ttl_data_size
+= data_map_size
-1;
333 fprintf (stderr
, "error %d (%s) opening %s for read\n",
334 errno
, xstrerror (errno
), fname
);
338 #ifdef HAVE_MMAP_FILE
339 curr_data_mapped
= BOOL_TRUE
;
341 /* IF the file size is a multiple of the page size,
342 THEN sometimes you will seg fault trying to access a trailing byte */
343 if ((stbf
.st_size
& (getpagesize()-1)) == 0)
344 res
= (char*)BAD_ADDR
;
346 res
= (char*)mmap ((void*)NULL
, data_map_size
, PROT_READ
,
347 MAP_PRIVATE
, data_map_fd
, 0);
348 if (res
== (char*)BAD_ADDR
)
351 FILE* fp
= fdopen (data_map_fd
, "r");
352 curr_data_mapped
= BOOL_FALSE
;
353 res
= load_file_data (fp
);
361 machine_matches( tFixDesc
* p_fixd
)
363 # ifndef SEPARATE_FIX_PROC
364 tSCC case_fmt
[] = "case %s in\n"; /* 9 bytes, plus string */
366 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
367 tSCC skip
[] = "skip"; /* 4 bytes */
368 tSCC run
[] = "run"; /* 3 bytes */
369 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
371 const char **papz_machs
= p_fixd
->papz_machs
;
373 const char *pz_sep
= "";
376 char cmd_buf
[ MACH_LIST_SIZE_LIMIT
]; /* size lim from fixincl.tpl */
378 /* Start the case statement */
380 sprintf (cmd_buf
, case_fmt
, pz_machine
);
381 pz
= cmd_buf
+ strlen (cmd_buf
);
383 /* Determine if a match means to apply the fix or not apply it */
385 if (p_fixd
->fd_flags
& FD_MACH_IFNOT
)
396 /* Emit all the machine names. If there are more than one,
397 then we will insert " | \\\n" between the names */
401 const char* pz_mach
= *(papz_machs
++);
403 if (pz_mach
== (const char*) NULL
)
405 sprintf (pz
, "%s%s", pz_sep
, pz_mach
);
410 /* Now emit the match and not-match actions and the esac */
412 sprintf (pz
, esac_fmt
, pz_if_true
, pz_if_false
);
415 The result will start either with 's' or 'r'. */
419 pz
= run_shell (cmd_buf
);
424 p_fixd
->fd_flags
|= FD_SKIP_TEST
;
430 # else /* is SEPARATE_FIX_PROC */
431 const char **papz_machs
= p_fixd
->papz_machs
;
432 int invert
= (p_fixd
->fd_flags
& FD_MACH_IFNOT
) != 0;
435 const char* pz_mach
= *(papz_machs
++);
437 if (pz_mach
== (const char*) NULL
)
439 if (strstr (pz_mach
, "dos") != NULL
&& !invert
)
443 p_fixd
->fd_flags
|= FD_SKIP_TEST
;
448 /* * * * * * * * * * * * *
450 run_compiles run all the regexp compiles for all the fixes once.
455 tFixDesc
*p_fixd
= fixDescList
;
456 int fix_ct
= FIX_COUNT
;
457 regex_t
*p_re
= XCNEWVEC (regex_t
, REGEX_COUNT
);
459 /* Make sure compile_re does not stumble across invalid data */
461 memset (&incl_quote_re
, '\0', sizeof (regex_t
));
463 compile_re (incl_quote_pat
, &incl_quote_re
, 1,
464 "quoted include", "run_compiles");
466 /* Allow machine name tests to be ignored (testing, mainly) */
468 if (pz_machine
&& ((*pz_machine
== '\0') || (*pz_machine
== '*')))
469 pz_machine
= (char*)NULL
;
471 /* FOR every fixup, ... */
474 tTestDesc
*p_test
= p_fixd
->p_test_desc
;
475 int test_ct
= p_fixd
->test_ct
;
477 /* IF the machine type pointer is not NULL (we are not in test mode)
478 AND this test is for or not done on particular machines
481 if ( (pz_machine
!= NULL
)
482 && (p_fixd
->papz_machs
!= (const char**) NULL
)
483 && ! machine_matches (p_fixd
) )
486 /* FOR every test for the fixup, ... */
488 while (--test_ct
>= 0)
490 switch (p_test
->type
)
494 p_test
->p_test_regex
= p_re
++;
495 compile_re (p_test
->pz_test_text
, p_test
->p_test_regex
, 0,
496 "select test", p_fixd
->fix_name
);
502 while (p_fixd
++, --fix_ct
> 0);
506 /* * * * * * * * * * * * *
508 create_file Create the output modified file.
509 Input: the name of the file to create
510 Returns: a file pointer to the new, open file */
512 #if defined(S_IRUSR) && defined(S_IWUSR) && \
513 defined(S_IRGRP) && defined(S_IROTH)
515 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
517 # define S_IRALL 0644
520 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
521 defined(S_IROTH) && defined(S_IXOTH)
523 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
525 # define S_DIRALL 0755
534 char fname
[MAXPATHLEN
];
536 sprintf (fname
, "%s/%s", pz_dest_dir
, pz_curr_file
+ find_base_len
);
538 fd
= open (fname
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRALL
);
540 /* We may need to create the directories needed... */
541 if ((fd
< 0) && (errno
== ENOENT
))
543 char *pz_dir
= strchr (fname
+ 1, '/');
546 while (pz_dir
!= (char *) NULL
)
549 if (stat (fname
, &stbf
) < 0)
554 mkdir (fname
, S_IFDIR
| S_DIRALL
);
559 pz_dir
= strchr (pz_dir
+ 1, '/');
562 /* Now, lets try the open again... */
563 fd
= open (fname
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRALL
);
567 fprintf (stderr
, "Error %d (%s) creating %s\n",
568 errno
, xstrerror (errno
), fname
);
572 fprintf (stderr
, "Fixed: %s\n", pz_curr_file
);
573 pf
= fdopen (fd
, "w");
576 * IF pz_machine is NULL, then we are in some sort of test mode.
577 * Do not insert the current directory name. Use a constant string.
579 fprintf (pf
, z_std_preamble
,
589 /* * * * * * * * * * * * *
591 test_test make sure a shell-style test expression passes.
592 Input: a pointer to the descriptor of the test to run and
593 the name of the file that we might want to fix
594 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
595 shell script we run. */
596 #ifndef SEPARATE_FIX_PROC
598 test_test (tTestDesc
* p_test
, char* pz_test_file
)
602 if ( test %s ) > /dev/null 2>&1\n\
610 static char cmd_buf
[4096];
612 sprintf (cmd_buf
, cmd_fmt
, pz_test_file
, p_test
->pz_test_text
);
613 pz_res
= run_shell (cmd_buf
);
625 fprintf (stderr
, "Script yielded bogus result of `%s':\n%s\n\n",
630 free ((void *) pz_res
);
635 * IF we are in MS-DOS land, then whatever shell-type test is required
636 * will, by definition, fail
638 #define test_test(t,tf) SKIP_FIX
641 /* * * * * * * * * * * * *
643 egrep_test make sure an egrep expression is found in the file text.
644 Input: a pointer to the descriptor of the test to run and
645 the pointer to the contents of the file under suspicion
646 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
648 The caller may choose to reverse meaning if the sense of the test
652 egrep_test (char* pz_data
, tTestDesc
* p_test
)
655 if (p_test
->p_test_regex
== 0)
656 fprintf (stderr
, "fixincl ERROR RE not compiled: `%s'\n",
657 p_test
->pz_test_text
);
659 if (xregexec (p_test
->p_test_regex
, pz_data
, 0, 0, 0) == 0)
665 /* * * * * * * * * * * * *
667 quoted_file_exists Make sure that a file exists before we emit
668 the file name. If we emit the name, our invoking shell will try
669 to copy a non-existing file into the destination directory. */
672 quoted_file_exists (const char* pz_src_path
,
673 const char* pz_file_path
,
676 char z
[ MAXPATHLEN
];
678 sprintf (z
, "%s/%s/", pz_src_path
, pz_file_path
);
679 pz
= z
+ strlen ( z
);
682 char ch
= *pz_file
++;
692 if (stat (z
, &s
) != 0)
694 return S_ISREG( s
.st_mode
);
699 /* * * * * * * * * * * * *
703 The syntax, `#include "file.h"' specifies that the compiler is to
704 search the local directory of the current file before the include
705 list. Consequently, if we have modified a header and stored it in
706 another directory, any files that are included by that modified
707 file in that fashion must also be copied into this new directory.
708 This routine finds those flavors of #include and for each one found
711 1. source directory of the original file
712 2. the relative path file name of the #includ-ed file
713 3. the full destination path for this file
715 Input: the text of the file, the file name and a pointer to the
716 match list where the match information was stored.
717 Result: internally nothing. The results are written to stdout
718 for interpretation by the invoking shell */
722 extract_quoted_files (char* pz_data
,
723 const char* pz_fixed_file
,
724 regmatch_t
* p_re_match
)
726 char *pz_dir_end
= strrchr (pz_fixed_file
, '/');
727 char *pz_incl_quot
= pz_data
;
729 if (VLEVEL( VERB_APPLIES
))
730 fprintf (stderr
, "Quoted includes in %s\n", pz_fixed_file
);
732 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
733 If there is none, then it is in our current directory, ".". */
735 if (pz_dir_end
== (char *) NULL
)
742 pz_incl_quot
+= p_re_match
->rm_so
;
744 /* Skip forward to the included file name */
745 while (*pz_incl_quot
!= '"')
748 if (quoted_file_exists (pz_src_dir
, pz_fixed_file
, pz_incl_quot
))
750 /* Print the source directory and the subdirectory
751 of the file in question. */
752 printf ("%s %s/", pz_src_dir
, pz_fixed_file
);
753 pz_dir_end
= pz_incl_quot
;
755 /* Append to the directory the relative path of the desired file */
756 while (*pz_incl_quot
!= '"')
757 putc (*pz_incl_quot
++, stdout
);
759 /* Now print the destination directory appended with the
760 relative path of the desired file */
761 printf (" %s/%s/", pz_dest_dir
, pz_fixed_file
);
762 while (*pz_dir_end
!= '"')
763 putc (*pz_dir_end
++, stdout
);
769 /* Find the next entry */
770 if (xregexec (&incl_quote_re
, pz_incl_quot
, 1, p_re_match
, 0) != 0)
776 /* * * * * * * * * * * * *
778 Somebody wrote a *_fix subroutine that we must call.
780 #ifndef SEPARATE_FIX_PROC
782 internal_fix (int read_fd
, tFixDesc
* p_fixd
)
788 fprintf (stderr
, "Error %d on pipe(2) call\n", errno
);
794 pid_t childid
= fork();
817 fprintf (stderr
, z_fork_err
, errno
, xstrerror (errno
),
820 static int failCt
= 0;
821 if ((errno
!= EAGAIN
) || (++failCt
> 10))
828 * Close our current stdin and stdout
830 close (STDIN_FILENO
);
831 close (STDOUT_FILENO
);
835 * Make the fd passed in the stdin, and the write end of
836 * the new pipe become the stdout.
838 dup2 (fd
[1], STDOUT_FILENO
);
839 dup2 (read_fd
, STDIN_FILENO
);
841 apply_fix (p_fixd
, pz_curr_file
);
844 #endif /* !SEPARATE_FIX_PROC */
847 #ifdef SEPARATE_FIX_PROC
849 fix_with_system (tFixDesc
* p_fixd
,
858 if (p_fixd
->fd_flags
& FD_SUBROUTINE
)
860 static const char z_applyfix_prog
[] =
861 "/../fixincludes/applyfix" EXE_EXT
;
865 + strlen (pz_orig_dir
)
866 + sizeof (z_applyfix_prog
)
867 + strlen (pz_fix_file
)
868 + strlen (pz_file_source
)
869 + strlen (pz_temp_file
);
871 /* Allocate something sure to be big enough for our purposes */
872 pz_cmd
= XNEWVEC (char, argsize
);
873 strcpy (pz_cmd
, pz_orig_dir
);
874 pz_scan
= pz_cmd
+ strlen (pz_orig_dir
);
876 strcpy (pz_scan
, z_applyfix_prog
);
878 /* IF we can't find the "applyfix" executable file at the first guess,
879 try one level higher up */
880 if (stat (pz_cmd
, &buf
) == -1)
882 strcpy (pz_scan
, "/..");
883 strcpy (pz_scan
+3, z_applyfix_prog
);
886 pz_scan
+= strlen (pz_scan
);
889 * Now add the fix number and file names that may be needed
891 sprintf (pz_scan
, " %ld '%s' '%s' '%s'", p_fixd
- fixDescList
,
892 pz_fix_file
, pz_file_source
, pz_temp_file
);
894 else /* NOT an "internal" fix: */
898 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
899 dst is a temporary file anyway, so we know there's no other
900 file by that name; and DOS's system(3) doesn't mind to
901 clobber existing file in redirection. Besides, with DOS 8+3
902 limited file namespace, we can easily lose if dst already has
903 an extension that is 3 or more characters long.
905 I do not think the 8+3 issue is relevant because all the files
906 we operate on are named "*.h", making 8+2 adequate. Anyway,
907 the following bizarre use of 'cat' only works on DOS boxes.
908 It causes the file to be dropped into a temporary file for
909 'cat' to read (pipes do not work on DOS). */
910 tSCC z_cmd_fmt
[] = " '%s' | cat > '%s'";
912 /* Don't use positional formatting arguments because some lame-o
913 implementations cannot cope :-(. */
914 tSCC z_cmd_fmt
[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
916 tCC
** ppArgs
= p_fixd
->patch_args
;
918 argsize
= sizeof( z_cmd_fmt
) + strlen( pz_temp_file
)
919 + strlen( pz_file_source
);
924 * Compute the size of the command line. Add lotsa extra space
925 * because some of the args to sed use lotsa single quotes.
926 * (This requires three extra bytes per quote. Here we allow
927 * for up to 8 single quotes for each argument, including the
928 * command name "sed" itself. Nobody will *ever* need more. :)
932 tCC
* p_arg
= *(ppArgs
++);
935 argsize
+= 24 + strlen( p_arg
);
938 /* Estimated buffer size we will need. */
939 pz_scan
= pz_cmd
= XNEWVEC (char, argsize
);
940 /* How much of it do we allot to the program name and its
942 parg_size
= argsize
- parg_size
;
944 ppArgs
= p_fixd
->patch_args
;
947 * Copy the program name, unquoted
950 tCC
* pArg
= *(ppArgs
++);
961 * Copy the program arguments, quoted
965 tCC
* pArg
= *(ppArgs
++);
970 pz_scan
= make_raw_shell_str( pz_scan_save
= pz_scan
, pArg
,
971 parg_size
- (pz_scan
- pz_cmd
) );
973 * Make sure we don't overflow the buffer due to sloppy
976 while (pz_scan
== (char*)NULL
)
978 size_t already_filled
= pz_scan_save
- pz_cmd
;
979 pz_cmd
= xrealloc (pz_cmd
, argsize
+= 100);
980 pz_scan_save
= pz_scan
= pz_cmd
+ already_filled
;
982 pz_scan
= make_raw_shell_str( pz_scan
, pArg
,
983 parg_size
- (pz_scan
- pz_cmd
) );
988 * add the file machinations.
991 sprintf (pz_scan
, z_cmd_fmt
, pz_file_source
, pz_temp_file
);
993 sprintf (pz_scan
, z_cmd_fmt
, pz_file_source
, pz_temp_file
,
994 pz_temp_file
, pz_temp_file
, pz_temp_file
);
998 free( (void*)pz_cmd
);
1001 /* * * * * * * * * * * * *
1003 This loop should only cycle for 1/2 of one loop.
1004 "chain_open" starts a process that uses "read_fd" as
1005 its stdin and returns the new fd this process will use
1008 #else /* is *NOT* SEPARATE_FIX_PROC */
1010 start_fixer (int read_fd
, tFixDesc
* p_fixd
, char* pz_fix_file
)
1015 if ((p_fixd
->fd_flags
& FD_SUBROUTINE
) != 0)
1016 return internal_fix (read_fd
, p_fixd
);
1018 if ((p_fixd
->fd_flags
& FD_SHELL_SCRIPT
) == 0)
1025 tSCC z_cmd_fmt
[] = "file='%s'\n%s";
1026 pz_cmd
= XNEWVEC (char, strlen (p_fixd
->patch_args
[2])
1027 + sizeof (z_cmd_fmt
) + strlen (pz_fix_file
));
1028 sprintf (pz_cmd
, z_cmd_fmt
, pz_fix_file
, p_fixd
->patch_args
[2]);
1029 pz_cmd_save
= p_fixd
->patch_args
[2];
1030 p_fixd
->patch_args
[2] = pz_cmd
;
1033 /* Start a fix process, handing off the previous read fd for its
1034 stdin and getting a new fd that reads from the fix process' stdout.
1035 We normally will not loop, but we will up to 10 times if we keep
1036 getting "EAGAIN" errors.
1041 static int failCt
= 0;
1044 fd
= chain_open (read_fd
,
1045 (tCC
**) p_fixd
->patch_args
,
1046 (process_chain_head
== -1)
1047 ? &process_chain_head
: (pid_t
*) NULL
);
1055 fprintf (stderr
, z_fork_err
, errno
, xstrerror (errno
),
1058 if ((errno
!= EAGAIN
) || (++failCt
> 10))
1059 exit (EXIT_FAILURE
);
1063 /* IF we allocated a shell script command,
1064 THEN free it and restore the command format to the fix description */
1065 if (pz_cmd
!= (char*)NULL
)
1067 free ((void*)pz_cmd
);
1068 p_fixd
->patch_args
[2] = pz_cmd_save
;
1076 /* * * * * * * * * * * * *
1078 Process the potential fixes for a particular include file.
1079 Input: the original text of the file and the file's name
1080 Result: none. A new file may or may not be created. */
1083 fix_applies (tFixDesc
* p_fixd
)
1085 const char *pz_fname
= pz_curr_file
;
1086 const char *pz_scan
= p_fixd
->file_list
;
1090 # ifdef SEPARATE_FIX_PROC
1092 * There is only one fix that uses a shell script as of this writing.
1093 * I hope to nuke it anyway, it does not apply to DOS and it would
1094 * be painful to implement. Therefore, no "shell" fixes for DOS.
1096 if (p_fixd
->fd_flags
& (FD_SHELL_SCRIPT
| FD_SKIP_TEST
))
1099 if (p_fixd
->fd_flags
& FD_SKIP_TEST
)
1103 /* IF there is a file name restriction,
1104 THEN ensure the current file name matches one in the pattern */
1106 if (pz_scan
!= (char *) NULL
)
1110 while ((pz_fname
[0] == '.') && (pz_fname
[1] == '/'))
1112 name_len
= strlen (pz_fname
);
1116 pz_scan
= strstr (pz_scan
+ 1, pz_fname
);
1117 /* IF we can't match the string at all,
1119 if (pz_scan
== (char *) NULL
)
1122 /* IF the match is surrounded by the '|' markers,
1123 THEN we found a full match -- time to run the tests */
1125 if ((pz_scan
[-1] == '|') && (pz_scan
[name_len
] == '|'))
1130 /* FOR each test, see if it fails.
1131 IF it does fail, then we go on to the next test */
1133 for (p_test
= p_fixd
->p_test_desc
, test_ct
= p_fixd
->test_ct
;
1137 switch (p_test
->type
)
1140 if (test_test (p_test
, pz_curr_file
) != APPLY_FIX
) {
1142 if (VLEVEL( VERB_EVERYTHING
))
1143 fprintf (stderr
, z_failed
, "TEST", p_fixd
->fix_name
,
1144 pz_fname
, p_fixd
->test_ct
- test_ct
);
1151 if (egrep_test (pz_curr_data
, p_test
) != APPLY_FIX
) {
1153 if (VLEVEL( VERB_EVERYTHING
))
1154 fprintf (stderr
, z_failed
, "EGREP", p_fixd
->fix_name
,
1155 pz_fname
, p_fixd
->test_ct
- test_ct
);
1162 if (egrep_test (pz_curr_data
, p_test
) == APPLY_FIX
) {
1164 if (VLEVEL( VERB_EVERYTHING
))
1165 fprintf (stderr
, z_failed
, "NEGREP", p_fixd
->fix_name
,
1166 pz_fname
, p_fixd
->test_ct
- test_ct
);
1174 if (run_test (p_test
->pz_test_text
, pz_curr_file
, pz_curr_data
)
1177 if (VLEVEL( VERB_EVERYTHING
))
1178 fprintf (stderr
, z_failed
, "FTEST", p_fixd
->fix_name
,
1179 pz_fname
, p_fixd
->test_ct
- test_ct
);
1191 /* * * * * * * * * * * * *
1193 Write out a replacement file */
1196 write_replacement (tFixDesc
* p_fixd
)
1198 const char* pz_text
= p_fixd
->patch_args
[0];
1200 if ((pz_text
== (char*)NULL
) || (*pz_text
== NUL
))
1204 FILE* out_fp
= create_file ();
1205 fputs (pz_text
, out_fp
);
1211 /* * * * * * * * * * * * *
1213 We have work to do. Read back in the output
1214 of the filtering chain. Compare each byte as we read it with
1215 the contents of the original file. As soon as we find any
1216 difference, we will create the output file, write out all
1217 the matched text and then copy any remaining data from the
1218 output of the filter chain.
1221 test_for_changes (int read_fd
)
1223 FILE *in_fp
= fdopen (read_fd
, "r");
1224 FILE *out_fp
= (FILE *) NULL
;
1225 unsigned char *pz_cmp
= (unsigned char*)pz_curr_data
;
1237 ch
&= 0xFF; /* all bytes are 8 bits */
1239 /* IF we are emitting the output
1240 THEN emit this character, too.
1242 if (out_fp
!= (FILE *) NULL
)
1245 /* ELSE if this character does not match the original,
1246 THEN now is the time to start the output.
1248 else if (ch
!= *pz_cmp
)
1250 out_fp
= create_file ();
1255 /* IF there are matched data, write the matched part now. */
1256 if ((char*)pz_cmp
!= pz_curr_data
)
1257 fwrite (pz_curr_data
, (size_t)((char*)pz_cmp
- pz_curr_data
),
1260 /* Emit the current unmatching character */
1264 /* ELSE the character matches. Advance the compare ptr */
1268 /* IF we created the output file, ... */
1269 if (out_fp
!= (FILE *) NULL
)
1273 /* Close the file and see if we have to worry about
1274 `#include "file.h"' constructs. */
1276 if (xregexec (&incl_quote_re
, pz_curr_data
, 1, &match
, 0) == 0)
1277 extract_quoted_files (pz_curr_data
, pz_curr_file
, &match
);
1281 close (read_fd
); /* probably redundant, but I'm paranoid */
1285 /* * * * * * * * * * * * *
1287 Process the potential fixes for a particular include file.
1288 Input: the original text of the file and the file's name
1289 Result: none. A new file may or may not be created. */
1294 tFixDesc
*p_fixd
= fixDescList
;
1295 int todo_ct
= FIX_COUNT
;
1297 # ifndef SEPARATE_FIX_PROC
1298 int num_children
= 0;
1299 # else /* is SEPARATE_FIX_PROC */
1300 char* pz_file_source
= pz_curr_file
;
1303 if (access (pz_curr_file
, R_OK
) != 0)
1306 fprintf (stderr
, "Cannot access %s from %s\n\terror %d (%s)\n",
1307 pz_curr_file
, getcwd ((char *) NULL
, MAXPATHLEN
),
1308 erno
, xstrerror (erno
));
1312 pz_curr_data
= load_file (pz_curr_file
);
1313 if (pz_curr_data
== (char *) NULL
)
1319 if (VLEVEL( VERB_PROGRESS
) && have_tty
)
1320 fprintf (stderr
, "%6lu %-50s \r",
1321 (unsigned long) data_map_size
, pz_curr_file
);
1323 # ifndef SEPARATE_FIX_PROC
1324 process_chain_head
= NOPROCESS
;
1326 /* For every fix in our fix list, ... */
1327 for (; todo_ct
> 0; p_fixd
++, todo_ct
--)
1329 if (! fix_applies (p_fixd
))
1332 if (VLEVEL( VERB_APPLIES
))
1333 fprintf (stderr
, "Applying %-24s to %s\n",
1334 p_fixd
->fix_name
, pz_curr_file
);
1336 if (p_fixd
->fd_flags
& FD_REPLACEMENT
)
1338 write_replacement (p_fixd
);
1343 /* IF we do not have a read pointer,
1344 THEN this is the first fix for the current file.
1345 Open the source file. That will be used as stdin for
1346 the first fix. Any subsequent fixes will use the
1347 stdout descriptor of the previous fix for its stdin. */
1351 read_fd
= open (pz_curr_file
, O_RDONLY
);
1354 fprintf (stderr
, "Error %d (%s) opening %s\n", errno
,
1355 xstrerror (errno
), pz_curr_file
);
1356 exit (EXIT_FAILURE
);
1359 /* Ensure we do not get duplicate output */
1364 read_fd
= start_fixer (read_fd
, p_fixd
, pz_curr_file
);
1368 /* IF we have a read-back file descriptor,
1369 THEN check for changes and write output if changed. */
1373 test_for_changes (read_fd
);
1375 apply_ct
+= num_children
;
1377 /* Wait for child processes created by chain_open()
1378 to avoid leaving zombies. */
1380 wait ((int *) NULL
);
1381 } while (--num_children
> 0);
1384 # else /* is SEPARATE_FIX_PROC */
1386 for (; todo_ct
> 0; p_fixd
++, todo_ct
--)
1388 if (! fix_applies (p_fixd
))
1391 if (VLEVEL( VERB_APPLIES
))
1392 fprintf (stderr
, "Applying %-24s to %s\n",
1393 p_fixd
->fix_name
, pz_curr_file
);
1395 if (p_fixd
->fd_flags
& FD_REPLACEMENT
)
1397 write_replacement (p_fixd
);
1401 fix_with_system (p_fixd
, pz_curr_file
, pz_file_source
, pz_temp_file
);
1402 pz_file_source
= pz_temp_file
;
1405 read_fd
= open (pz_temp_file
, O_RDONLY
);
1408 if (errno
!= ENOENT
)
1409 fprintf (stderr
, "error %d (%s) opening output (%s) for read\n",
1410 errno
, xstrerror (errno
), pz_temp_file
);
1414 test_for_changes (read_fd
);
1415 /* Unlinking a file while it is still open is a Bad Idea on
1418 unlink (pz_temp_file
);