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, 2009, 2012
6 Free Software Foundation, Inc.
8 This file is part of GCC.
10 GCC 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 3, or (at your option)
15 GCC 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 GCC; see the file COPYING3. If not see
22 <http://www.gnu.org/licenses/>. */
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;
58 pid_t process_chain_head
= (pid_t
) -1;
60 char* pz_curr_file
; /* name of the current file under test/fix */
61 char* pz_curr_data
; /* original contents of that file */
62 char* pz_temp_file
; /* for DOS, a place to stash the temporary
63 fixed data between system(3) calls */
64 t_bool curr_data_mapped
;
67 size_t ttl_data_size
= 0;
76 const char incl_quote_pat
[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
77 regex_t incl_quote_re
;
79 #ifndef SEPARATE_FIX_PROC
80 tSCC z_fork_err
[] = "Error %d (%s) starting filter process for %s\n";
83 static void do_version (void) ATTRIBUTE_NORETURN
;
84 char *load_file (const char *);
85 void run_compiles (void);
86 void initialize (int argc
, char** argv
);
89 /* External Source Code */
93 /* * * * * * * * * * * * * * * * * * *
97 extern int main (int, char **);
99 main (int argc
, char** argv
)
103 initialize ( argc
, argv
);
105 have_tty
= isatty (fileno (stderr
));
107 /* Before anything else, ensure we can allocate our file name buffer. */
108 file_name_buf
= load_file_data (stdin
);
110 /* Because of the way server shells work, you have to keep stdin, out
111 and err open so that the proper input file does not get closed
114 freopen ("/dev/null", "r", stdin
);
116 if (file_name_buf
== (char *) NULL
)
118 fputs ("No file names listed for fixing\n", stderr
);
126 /* skip to start of name, past any "./" prefixes */
128 while (ISSPACE (*file_name_buf
)) file_name_buf
++;
129 while ((file_name_buf
[0] == '.') && (file_name_buf
[1] == '/'))
132 /* Check for end of list */
134 if (*file_name_buf
== NUL
)
137 /* Set global file name pointer and find end of name */
139 pz_curr_file
= file_name_buf
;
140 pz_end
= strchr( pz_curr_file
, '\n' );
141 if (pz_end
== (char*)NULL
)
142 pz_end
= file_name_buf
= pz_curr_file
+ strlen (pz_curr_file
);
144 file_name_buf
= pz_end
+ 1;
146 while ((pz_end
> pz_curr_file
) && ISSPACE( pz_end
[-1])) pz_end
--;
148 /* IF no name is found (blank line) or comment marker, skip line */
150 if ((pz_curr_file
== pz_end
) || (*pz_curr_file
== '#'))
158 if (VLEVEL( VERB_PROGRESS
)) {
161 Processed %5d files containing %d bytes \n\
162 Applying %5d fixes to %d files\n\
163 Altering %5d of them\n";
165 fprintf (stderr
, zFmt
, process_ct
, ttl_data_size
, apply_ct
,
166 fixed_ct
, altered_ct
);
168 #endif /* DO_STATS */
170 # ifdef SEPARATE_FIX_PROC
171 unlink( pz_temp_file
);
180 static const char zFmt
[] = "echo '%s'";
183 /* The 'version' option is really used to test that:
184 1. The program loads correctly (no missing libraries)
185 2. that we can compile all the regular expressions.
186 3. we can correctly run our server shell process
189 sprintf (zBuf
, zFmt
, program_id
);
190 #ifndef SEPARATE_FIX_PROC
192 exit (strcmp (run_shell (zBuf
), program_id
));
194 exit (system_with_shell (zBuf
));
198 /* * * * * * * * * * * * */
201 initialize ( int argc
, char** argv
)
203 xmalloc_set_program_name (argv
[0]);
211 if (strcmp (argv
[1], "-v") == 0)
213 if (freopen (argv
[1], "r", stdin
) == (FILE*)NULL
)
215 fprintf (stderr
, "Error %d (%s) reopening %s as stdin\n",
216 errno
, xstrerror (errno
), argv
[1] );
222 fputs ("fixincl ERROR: too many command line arguments\n", stderr
);
227 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
228 receive the signal. A different setting is inheritable */
229 signal (SIGCHLD
, SIG_DFL
);
234 if (ISDIGIT ( *pz_verbose
))
235 verbose_level
= (te_verbose
)atoi( pz_verbose
);
237 switch (*pz_verbose
) {
240 verbose_level
= VERB_SILENT
; break;
244 verbose_level
= VERB_FIXES
; break;
248 verbose_level
= VERB_APPLIES
; break;
253 verbose_level
= VERB_PROGRESS
; break;
257 verbose_level
= VERB_TESTS
; break;
261 verbose_level
= VERB_EVERYTHING
; break;
263 if (verbose_level
>= VERB_EVERYTHING
) {
264 verbose_level
= VERB_EVERYTHING
;
265 fputs ("fixinc verbosity: EVERYTHING\n", stderr
);
267 while ((pz_find_base
[0] == '.') && (pz_find_base
[1] == '/'))
269 if ((pz_find_base
[0] != '.') || (pz_find_base
[1] != NUL
))
270 find_base_len
= strlen( pz_find_base
);
272 /* Compile all the regular expressions now.
273 That way, it is done only once for the whole run.
277 # ifdef SEPARATE_FIX_PROC
278 /* NULL as the first argument to `tempnam' causes it to DTRT
279 wrt the temporary directory where the file will be created. */
280 pz_temp_file
= tempnam( NULL
, "fxinc" );
282 #if defined(__MINGW32__)
283 fix_path_separators (pz_temp_file
);
288 signal (SIGQUIT
, SIG_IGN
);
289 signal (SIGIOT
, SIG_IGN
);
290 signal (SIGPIPE
, SIG_IGN
);
291 signal (SIGALRM
, SIG_IGN
);
292 signal (SIGTERM
, SIG_IGN
);
295 /* * * * * * * * * * * * *
297 load_file loads all the contents of a file into malloc-ed memory.
298 Its argument is the name of the file to read in; the returned
299 result is the NUL terminated contents of the file. The file
300 is presumed to be an ASCII text file containing no NULs. */
302 load_file ( const char* fname
)
307 if (stat (fname
, &stbf
) != 0)
310 fprintf (stderr
, "error %d (%s) stat-ing %s\n",
311 errno
, xstrerror (errno
), fname
);
312 return (char *) NULL
;
314 if (stbf
.st_size
== 0)
317 /* Make the data map size one larger than the file size for documentation
318 purposes. Truth is that there will be a following NUL character if
319 the file size is not a multiple of the page size. If it is a multiple,
320 then this adjustment sometimes fails anyway. */
321 data_map_size
= stbf
.st_size
+1;
322 data_map_fd
= open (fname
, O_RDONLY
);
323 ttl_data_size
+= data_map_size
-1;
328 fprintf (stderr
, "error %d (%s) opening %s for read\n",
329 errno
, xstrerror (errno
), fname
);
333 #ifdef HAVE_MMAP_FILE
334 curr_data_mapped
= BOOL_TRUE
;
336 /* IF the file size is a multiple of the page size,
337 THEN sometimes you will seg fault trying to access a trailing byte */
338 if ((stbf
.st_size
& (getpagesize()-1)) == 0)
339 res
= (char*)BAD_ADDR
;
341 res
= (char*)mmap ((void*)NULL
, data_map_size
, PROT_READ
,
342 MAP_PRIVATE
, data_map_fd
, 0);
343 if (res
== (char*)BAD_ADDR
)
346 FILE* fp
= fdopen (data_map_fd
, "r");
347 curr_data_mapped
= BOOL_FALSE
;
348 res
= load_file_data (fp
);
356 machine_matches( tFixDesc
* p_fixd
)
358 char const ** papz_machs
= p_fixd
->papz_machs
;
359 int have_match
= BOOL_FALSE
;
363 char const * pz_mpat
= *(papz_machs
++);
366 if (fnmatch(pz_mpat
, pz_machine
, 0) == 0)
368 have_match
= BOOL_TRUE
;
373 /* Check for sense inversion then set the "skip test" flag, if needed */
374 if (p_fixd
->fd_flags
& FD_MACH_IFNOT
)
375 have_match
= ! have_match
;
378 p_fixd
->fd_flags
|= FD_SKIP_TEST
;
383 /* * * * * * * * * * * * *
385 * run_compiles run all the regexp compiles for all the fixes once.
390 tFixDesc
*p_fixd
= fixDescList
;
391 int fix_ct
= FIX_COUNT
;
392 regex_t
*p_re
= XCNEWVEC (regex_t
, REGEX_COUNT
);
394 /* Make sure compile_re does not stumble across invalid data */
396 memset (&incl_quote_re
, '\0', sizeof (regex_t
));
398 compile_re (incl_quote_pat
, &incl_quote_re
, 1,
399 "quoted include", "run_compiles");
401 /* Allow machine name tests to be ignored (testing, mainly) */
403 if (pz_machine
&& ((*pz_machine
== '\0') || (*pz_machine
== '*')))
404 pz_machine
= (char*)NULL
;
406 /* FOR every fixup, ... */
412 if (fixinc_mode
&& (p_fixd
->fd_flags
& FD_REPLACEMENT
))
414 p_fixd
->fd_flags
|= FD_SKIP_TEST
;
418 p_test
= p_fixd
->p_test_desc
;
419 test_ct
= p_fixd
->test_ct
;
421 /* IF the machine type pointer is not NULL (we are not in test mode)
422 AND this test is for or not done on particular machines
425 if ( (pz_machine
!= NULL
)
426 && (p_fixd
->papz_machs
!= (const char**) NULL
)
427 && ! machine_matches (p_fixd
) )
430 /* FOR every test for the fixup, ... */
432 while (--test_ct
>= 0)
434 switch (p_test
->type
)
438 p_test
->p_test_regex
= p_re
++;
439 compile_re (p_test
->pz_test_text
, p_test
->p_test_regex
, 0,
440 "select test", p_fixd
->fix_name
);
446 while (p_fixd
++, --fix_ct
> 0);
450 /* * * * * * * * * * * * *
452 create_file Create the output modified file.
453 Input: the name of the file to create
454 Returns: a file pointer to the new, open file */
456 #if defined(S_IRUSR) && defined(S_IWUSR) && \
457 defined(S_IRGRP) && defined(S_IROTH)
459 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
461 # define S_IRALL 0644
464 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
465 defined(S_IROTH) && defined(S_IXOTH)
467 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
469 # define S_DIRALL 0755
478 char fname
[MAXPATHLEN
];
480 sprintf (fname
, "%s/%s", pz_dest_dir
, pz_curr_file
+ find_base_len
);
482 fd
= open (fname
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRALL
);
484 /* We may need to create the directories needed... */
485 if ((fd
< 0) && (errno
== ENOENT
))
487 char *pz_dir
= strchr (fname
+ 1, '/');
490 while (pz_dir
!= (char *) NULL
)
493 if (stat (fname
, &stbf
) < 0)
498 mkdir (fname
, S_IFDIR
| S_DIRALL
);
503 pz_dir
= strchr (pz_dir
+ 1, '/');
506 /* Now, lets try the open again... */
507 fd
= open (fname
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRALL
);
511 fprintf (stderr
, "Error %d (%s) creating %s\n",
512 errno
, xstrerror (errno
), fname
);
516 fprintf (stderr
, "Fixed: %s\n", pz_curr_file
);
517 pf
= fdopen (fd
, "w");
520 * IF pz_machine is NULL, then we are in some sort of test mode.
521 * Do not insert the current directory name. Use a constant string.
523 fprintf (pf
, z_std_preamble
,
533 /* * * * * * * * * * * * *
535 test_test make sure a shell-style test expression passes.
536 Input: a pointer to the descriptor of the test to run and
537 the name of the file that we might want to fix
538 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
539 shell script we run. */
540 #ifndef SEPARATE_FIX_PROC
542 test_test (tTestDesc
* p_test
, char* pz_test_file
)
546 if ( test %s ) > /dev/null 2>&1\n\
554 static char cmd_buf
[4096];
556 sprintf (cmd_buf
, cmd_fmt
, pz_test_file
, p_test
->pz_test_text
);
557 pz_res
= run_shell (cmd_buf
);
569 fprintf (stderr
, "Script yielded bogus result of `%s':\n%s\n\n",
574 free ((void *) pz_res
);
577 #elif defined(__MINGW32__) || defined(__DJGPP__)
579 test_test (tTestDesc
* p_test
, char* pz_test_file
)
582 #if defined(__DJGPP__)
583 "file=%s; test %s >/dev/null 2>/dev/null";
585 "file=%s; test %s > /dev/null 2>&1";
589 char *cmd_buf
= XNEWVEC (char, strlen(cmd_fmt
) + strlen(pz_test_file
) + strlen(p_test
->pz_test_text
));
591 sprintf (cmd_buf
, cmd_fmt
, pz_test_file
, p_test
->pz_test_text
);
592 res
= system_with_shell (cmd_buf
);
595 return res
? SKIP_FIX
: APPLY_FIX
;
599 * IF we are in MS-DOS land, then whatever shell-type test is required
600 * will, by definition, fail
602 #define test_test(t,tf) SKIP_FIX
605 /* * * * * * * * * * * * *
607 egrep_test make sure an egrep expression is found in the file text.
608 Input: a pointer to the descriptor of the test to run and
609 the pointer to the contents of the file under suspicion
610 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
612 The caller may choose to reverse meaning if the sense of the test
616 egrep_test (char* pz_data
, tTestDesc
* p_test
)
619 if (p_test
->p_test_regex
== 0)
620 fprintf (stderr
, "fixincl ERROR RE not compiled: `%s'\n",
621 p_test
->pz_test_text
);
623 if (xregexec (p_test
->p_test_regex
, pz_data
, 0, 0, 0) == 0)
628 /* * * * * * * * * * * * *
630 cksum_test check the sum of the candidate file
631 Input: the original file contents and the file name
632 Result: APPLY_FIX if the check sum matches, SKIP_FIX otherwise
634 The caller may choose to reverse meaning if the sense of the test
638 cksum_test (char * pz_data
, tTestDesc
* p_test
, char * fname
)
643 * Testing is off in normal operation mode.
644 * So, in testing mode, APPLY_FIX is always returned.
646 if (fixinc_mode
!= TESTING_OFF
)
650 char * fnm
= strrchr(fname
, '/');
655 cksum
= (unsigned int)strtoul(p_test
->pz_test_text
, &fnm
, 10);
659 if (! ISSPACE(*fnm
++))
661 while (ISSPACE(*fnm
)) fnm
++;
663 if (! ISDIGIT(*fnm
++))
665 while (ISDIGIT(*fnm
)) fnm
++;
667 if (! ISSPACE(*fnm
++))
669 while (ISSPACE(*fnm
)) fnm
++;
671 if (strcmp(fnm
, fname
) != 0)
676 unsigned int sum
= 0;
677 while (*pz_data
!= NUL
) {
678 sum
= (sum
>> 1) + ((sum
& 1) << 15) + (unsigned)(*pz_data
++);
682 return (sum
== cksum
) ? APPLY_FIX
: SKIP_FIX
;
686 /* * * * * * * * * * * * *
688 quoted_file_exists Make sure that a file exists before we emit
689 the file name. If we emit the name, our invoking shell will try
690 to copy a non-existing file into the destination directory. */
693 quoted_file_exists (const char* pz_src_path
,
694 const char* pz_file_path
,
697 char z
[ MAXPATHLEN
];
699 sprintf (z
, "%s/%s/", pz_src_path
, pz_file_path
);
700 pz
= z
+ strlen ( z
);
703 char ch
= *pz_file
++;
713 if (stat (z
, &s
) != 0)
715 return S_ISREG( s
.st_mode
);
720 /* * * * * * * * * * * * *
724 The syntax, `#include "file.h"' specifies that the compiler is to
725 search the local directory of the current file before the include
726 list. Consequently, if we have modified a header and stored it in
727 another directory, any files that are included by that modified
728 file in that fashion must also be copied into this new directory.
729 This routine finds those flavors of #include and for each one found
732 1. source directory of the original file
733 2. the relative path file name of the #includ-ed file
734 3. the full destination path for this file
736 Input: the text of the file, the file name and a pointer to the
737 match list where the match information was stored.
738 Result: internally nothing. The results are written to stdout
739 for interpretation by the invoking shell */
743 extract_quoted_files (char* pz_data
,
744 const char* pz_fixed_file
,
745 regmatch_t
* p_re_match
)
747 char *pz_dir_end
= strrchr (pz_fixed_file
, '/');
748 char *pz_incl_quot
= pz_data
;
750 if (VLEVEL( VERB_APPLIES
))
751 fprintf (stderr
, "Quoted includes in %s\n", pz_fixed_file
);
753 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
754 If there is none, then it is in our current directory, ".". */
756 if (pz_dir_end
== (char *) NULL
)
763 pz_incl_quot
+= p_re_match
->rm_so
;
765 /* Skip forward to the included file name */
766 while (*pz_incl_quot
!= '"')
769 if (quoted_file_exists (pz_src_dir
, pz_fixed_file
, pz_incl_quot
))
771 /* Print the source directory and the subdirectory
772 of the file in question. */
773 printf ("%s %s/", pz_src_dir
, pz_fixed_file
);
774 pz_dir_end
= pz_incl_quot
;
776 /* Append to the directory the relative path of the desired file */
777 while (*pz_incl_quot
!= '"')
778 putc (*pz_incl_quot
++, stdout
);
780 /* Now print the destination directory appended with the
781 relative path of the desired file */
782 printf (" %s/%s/", pz_dest_dir
, pz_fixed_file
);
783 while (*pz_dir_end
!= '"')
784 putc (*pz_dir_end
++, stdout
);
790 /* Find the next entry */
791 if (xregexec (&incl_quote_re
, pz_incl_quot
, 1, p_re_match
, 0) != 0)
797 /* * * * * * * * * * * * *
799 Somebody wrote a *_fix subroutine that we must call.
801 #ifndef SEPARATE_FIX_PROC
803 internal_fix (int read_fd
, tFixDesc
* p_fixd
)
809 fprintf (stderr
, "Error %d on pipe(2) call\n", errno
);
815 pid_t childid
= fork();
838 fprintf (stderr
, z_fork_err
, errno
, xstrerror (errno
),
841 static int failCt
= 0;
842 if ((errno
!= EAGAIN
) || (++failCt
> 10))
849 * Close our current stdin and stdout
851 close (STDIN_FILENO
);
852 close (STDOUT_FILENO
);
856 * Make the fd passed in the stdin, and the write end of
857 * the new pipe become the stdout.
859 dup2 (fd
[1], STDOUT_FILENO
);
860 dup2 (read_fd
, STDIN_FILENO
);
862 apply_fix (p_fixd
, pz_curr_file
);
865 #endif /* !SEPARATE_FIX_PROC */
868 #ifdef SEPARATE_FIX_PROC
870 fix_with_system (tFixDesc
* p_fixd
,
879 if (p_fixd
->fd_flags
& FD_SUBROUTINE
)
881 static const char z_applyfix_prog
[] =
882 "/../fixincludes/applyfix" EXE_EXT
;
886 + strlen (pz_orig_dir
)
887 + sizeof (z_applyfix_prog
)
888 + strlen (pz_fix_file
)
889 + strlen (pz_file_source
)
890 + strlen (pz_temp_file
);
892 /* Allocate something sure to be big enough for our purposes */
893 pz_cmd
= XNEWVEC (char, argsize
);
894 strcpy (pz_cmd
, pz_orig_dir
);
895 pz_scan
= pz_cmd
+ strlen (pz_orig_dir
);
897 strcpy (pz_scan
, z_applyfix_prog
);
899 /* IF we can't find the "applyfix" executable file at the first guess,
900 try one level higher up */
901 if (stat (pz_cmd
, &buf
) == -1)
903 strcpy (pz_scan
, "/..");
904 strcpy (pz_scan
+3, z_applyfix_prog
);
907 pz_scan
+= strlen (pz_scan
);
910 * Now add the fix number and file names that may be needed
912 sprintf (pz_scan
, " %ld '%s' '%s' '%s'", (long) (p_fixd
- fixDescList
),
913 pz_fix_file
, pz_file_source
, pz_temp_file
);
915 else /* NOT an "internal" fix: */
918 #if defined(__MSDOS__) && !defined(__DJGPP__)
919 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
920 dst is a temporary file anyway, so we know there's no other
921 file by that name; and DOS's system(3) doesn't mind to
922 clobber existing file in redirection. Besides, with DOS 8+3
923 limited file namespace, we can easily lose if dst already has
924 an extension that is 3 or more characters long.
926 I do not think the 8+3 issue is relevant because all the files
927 we operate on are named "*.h", making 8+2 adequate. Anyway,
928 the following bizarre use of 'cat' only works on DOS boxes.
929 It causes the file to be dropped into a temporary file for
930 'cat' to read (pipes do not work on DOS). */
931 tSCC z_cmd_fmt
[] = " '%s' | cat > '%s'";
933 /* Don't use positional formatting arguments because some lame-o
934 implementations cannot cope :-(. */
935 tSCC z_cmd_fmt
[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
937 tSCC z_subshell_start
[] = "( ";
938 tSCC z_subshell_end
[] = " ) < ";
939 tCC
** ppArgs
= p_fixd
->patch_args
;
941 argsize
= sizeof( z_cmd_fmt
) + strlen( pz_temp_file
)
942 + strlen( pz_file_source
);
945 if (p_fixd
->fd_flags
& FD_SHELL_SCRIPT
)
947 argsize
+= strlen( z_subshell_start
) + strlen ( z_subshell_end
);
951 * Compute the size of the command line. Add lotsa extra space
952 * because some of the args to sed use lotsa single quotes.
953 * (This requires three extra bytes per quote. Here we allow
954 * for up to 8 single quotes for each argument, including the
955 * command name "sed" itself. Nobody will *ever* need more. :)
959 tCC
* p_arg
= *(ppArgs
++);
962 argsize
+= 24 + strlen( p_arg
);
965 /* Estimated buffer size we will need. */
966 pz_scan
= pz_cmd
= XNEWVEC (char, argsize
);
967 /* How much of it do we allot to the program name and its
969 parg_size
= argsize
- parg_size
;
971 ppArgs
= p_fixd
->patch_args
;
974 * If it's shell script, enclose it in parentheses and skip "sh -c".
976 if (p_fixd
->fd_flags
& FD_SHELL_SCRIPT
)
978 strcpy (pz_scan
, z_subshell_start
);
979 pz_scan
+= strlen (z_subshell_start
);
984 * Copy the program name, unquoted
987 tCC
* pArg
= *(ppArgs
++);
998 * Copy the program arguments, quoted
1002 tCC
* pArg
= *(ppArgs
++);
1007 pz_scan
= make_raw_shell_str( pz_scan_save
= pz_scan
, pArg
,
1008 parg_size
- (pz_scan
- pz_cmd
) );
1010 * Make sure we don't overflow the buffer due to sloppy
1013 while (pz_scan
== (char*)NULL
)
1015 size_t already_filled
= pz_scan_save
- pz_cmd
;
1016 pz_cmd
= xrealloc (pz_cmd
, argsize
+= 100);
1017 pz_scan_save
= pz_scan
= pz_cmd
+ already_filled
;
1019 pz_scan
= make_raw_shell_str( pz_scan
, pArg
,
1020 parg_size
- (pz_scan
- pz_cmd
) );
1025 * Close parenthesis if it's shell script.
1027 if (p_fixd
->fd_flags
& FD_SHELL_SCRIPT
)
1029 strcpy (pz_scan
, z_subshell_end
);
1030 pz_scan
+= strlen (z_subshell_end
);
1034 * add the file machinations.
1036 #if defined(__MSDOS__) && !defined(__DJGPP__)
1037 sprintf (pz_scan
, z_cmd_fmt
, pz_file_source
, pz_temp_file
);
1039 sprintf (pz_scan
, z_cmd_fmt
, pz_file_source
, pz_temp_file
,
1040 pz_temp_file
, pz_temp_file
, pz_temp_file
);
1043 system_with_shell (pz_cmd
);
1047 /* * * * * * * * * * * * *
1049 This loop should only cycle for 1/2 of one loop.
1050 "chain_open" starts a process that uses "read_fd" as
1051 its stdin and returns the new fd this process will use
1054 #else /* is *NOT* SEPARATE_FIX_PROC */
1056 start_fixer (int read_fd
, tFixDesc
* p_fixd
, char* pz_fix_file
)
1061 if ((p_fixd
->fd_flags
& FD_SUBROUTINE
) != 0)
1062 return internal_fix (read_fd
, p_fixd
);
1064 if ((p_fixd
->fd_flags
& FD_SHELL_SCRIPT
) == 0)
1071 tSCC z_cmd_fmt
[] = "file='%s'\n%s";
1072 pz_cmd
= XNEWVEC (char, strlen (p_fixd
->patch_args
[2])
1073 + sizeof (z_cmd_fmt
) + strlen (pz_fix_file
));
1074 sprintf (pz_cmd
, z_cmd_fmt
, pz_fix_file
, p_fixd
->patch_args
[2]);
1075 pz_cmd_save
= p_fixd
->patch_args
[2];
1076 p_fixd
->patch_args
[2] = pz_cmd
;
1079 /* Start a fix process, handing off the previous read fd for its
1080 stdin and getting a new fd that reads from the fix process' stdout.
1081 We normally will not loop, but we will up to 10 times if we keep
1082 getting "EAGAIN" errors.
1087 static int failCt
= 0;
1090 fd
= chain_open (read_fd
,
1091 (tCC
**) p_fixd
->patch_args
,
1092 (process_chain_head
== -1)
1093 ? &process_chain_head
: (pid_t
*) NULL
);
1101 fprintf (stderr
, z_fork_err
, errno
, xstrerror (errno
),
1104 if ((errno
!= EAGAIN
) || (++failCt
> 10))
1105 exit (EXIT_FAILURE
);
1109 /* IF we allocated a shell script command,
1110 THEN free it and restore the command format to the fix description */
1111 if (pz_cmd
!= (char*)NULL
)
1113 free ((void*)pz_cmd
);
1114 p_fixd
->patch_args
[2] = pz_cmd_save
;
1121 # define NOTE_SKIP(_ttyp) do { \
1122 if (VLEVEL( VERB_EVERYTHING )) \
1123 fprintf (stderr, z_failed, _ttyp, p_fixd->fix_name, \
1124 pz_fname, p_fixd->test_ct - test_ct); \
1127 # define NOTE_SKIP(_ttyp)
1130 /* * * * * * * * * * * * *
1132 * Process the potential fixes for a particular include file.
1133 * Input: the original text of the file and the file's name
1134 * Result: none. A new file may or may not be created.
1137 fix_applies (tFixDesc
* p_fixd
)
1139 const char *pz_fname
= pz_curr_file
;
1140 const char *pz_scan
= p_fixd
->file_list
;
1143 t_bool saw_sum_test
= BOOL_FALSE
;
1144 t_bool one_sum_passed
= BOOL_FALSE
;
1146 #if defined(__MSDOS__) && !defined(__DJGPP__)
1148 * There is only one fix that uses a shell script as of this writing.
1149 * I hope to nuke it anyway, it does not apply to DOS and it would
1150 * be painful to implement. Therefore, no "shell" fixes for DOS.
1152 if (p_fixd
->fd_flags
& (FD_SHELL_SCRIPT
| FD_SKIP_TEST
))
1155 if (p_fixd
->fd_flags
& FD_SKIP_TEST
)
1159 /* IF there is a file name restriction,
1160 THEN ensure the current file name matches one in the pattern */
1162 if (pz_scan
!= (char *) NULL
)
1164 while ((pz_fname
[0] == '.') && (pz_fname
[1] == '/'))
1169 if (fnmatch (pz_scan
, pz_fname
, 0) == 0)
1171 pz_scan
+= strlen (pz_scan
) + 1;
1172 if (*pz_scan
== NUL
)
1177 /* FOR each test, see if it fails.
1178 "sum" fails only if all "sum" tests fail.
1179 IF it does fail, then we go on to the next test */
1181 for (p_test
= p_fixd
->p_test_desc
, test_ct
= p_fixd
->test_ct
;
1185 switch (p_test
->type
)
1188 if (test_test (p_test
, pz_curr_file
) != APPLY_FIX
) {
1195 if (egrep_test (pz_curr_data
, p_test
) != APPLY_FIX
) {
1202 if (egrep_test (pz_curr_data
, p_test
) == APPLY_FIX
) {
1203 NOTE_SKIP("NEGREP");
1211 break; /* No need to check any more */
1213 saw_sum_test
= BOOL_TRUE
;
1214 if (cksum_test (pz_curr_data
, p_test
, pz_curr_file
) != APPLY_FIX
) {
1217 one_sum_passed
= BOOL_TRUE
;
1222 if (run_test (p_test
->pz_test_text
, pz_curr_file
, pz_curr_data
)
1232 return one_sum_passed
;
1238 /* * * * * * * * * * * * *
1240 Write out a replacement file */
1243 write_replacement (tFixDesc
* p_fixd
)
1245 const char* pz_text
= p_fixd
->patch_args
[0];
1247 if ((pz_text
== (char*)NULL
) || (*pz_text
== NUL
))
1251 FILE* out_fp
= create_file ();
1252 size_t sz
= strlen (pz_text
);
1253 fwrite (pz_text
, sz
, 1, out_fp
);
1254 if (pz_text
[ sz
-1 ] != '\n')
1255 fputc ('\n', out_fp
);
1261 /* * * * * * * * * * * * *
1263 We have work to do. Read back in the output
1264 of the filtering chain. Compare each byte as we read it with
1265 the contents of the original file. As soon as we find any
1266 difference, we will create the output file, write out all
1267 the matched text and then copy any remaining data from the
1268 output of the filter chain.
1271 test_for_changes (int read_fd
)
1273 FILE *in_fp
= fdopen (read_fd
, "r");
1274 FILE *out_fp
= (FILE *) NULL
;
1275 unsigned char *pz_cmp
= (unsigned char*)pz_curr_data
;
1287 ch
&= 0xFF; /* all bytes are 8 bits */
1289 /* IF we are emitting the output
1290 THEN emit this character, too.
1292 if (out_fp
!= (FILE *) NULL
)
1295 /* ELSE if this character does not match the original,
1296 THEN now is the time to start the output.
1298 else if (ch
!= *pz_cmp
)
1300 out_fp
= create_file ();
1305 /* IF there are matched data, write the matched part now. */
1306 if ((char*)pz_cmp
!= pz_curr_data
)
1307 fwrite (pz_curr_data
, (size_t)((char*)pz_cmp
- pz_curr_data
),
1310 /* Emit the current unmatching character */
1314 /* ELSE the character matches. Advance the compare ptr */
1318 /* IF we created the output file, ... */
1319 if (out_fp
!= (FILE *) NULL
)
1323 /* Close the file and see if we have to worry about
1324 `#include "file.h"' constructs. */
1326 if (xregexec (&incl_quote_re
, pz_curr_data
, 1, &match
, 0) == 0)
1327 extract_quoted_files (pz_curr_data
, pz_curr_file
, &match
);
1331 close (read_fd
); /* probably redundant, but I'm paranoid */
1335 /* * * * * * * * * * * * *
1337 Process the potential fixes for a particular include file.
1338 Input: the original text of the file and the file's name
1339 Result: none. A new file may or may not be created. */
1344 tFixDesc
*p_fixd
= fixDescList
;
1345 int todo_ct
= FIX_COUNT
;
1347 # ifndef SEPARATE_FIX_PROC
1348 int num_children
= 0;
1349 # else /* is SEPARATE_FIX_PROC */
1350 char* pz_file_source
= pz_curr_file
;
1353 if (access (pz_curr_file
, R_OK
) != 0)
1356 fprintf (stderr
, "Cannot access %s from %s\n\terror %d (%s)\n",
1357 pz_curr_file
, getcwd ((char *) NULL
, MAXPATHLEN
),
1358 erno
, xstrerror (erno
));
1362 pz_curr_data
= load_file (pz_curr_file
);
1363 if (pz_curr_data
== (char *) NULL
)
1369 if (VLEVEL( VERB_PROGRESS
) && have_tty
)
1370 fprintf (stderr
, "%6lu %-50s \r",
1371 (unsigned long) data_map_size
, pz_curr_file
);
1373 # ifndef SEPARATE_FIX_PROC
1374 process_chain_head
= NOPROCESS
;
1376 /* For every fix in our fix list, ... */
1377 for (; todo_ct
> 0; p_fixd
++, todo_ct
--)
1379 if (! fix_applies (p_fixd
))
1382 if (VLEVEL( VERB_APPLIES
))
1383 fprintf (stderr
, "Applying %-24s to %s\n",
1384 p_fixd
->fix_name
, pz_curr_file
);
1386 if (p_fixd
->fd_flags
& FD_REPLACEMENT
)
1388 write_replacement (p_fixd
);
1393 /* IF we do not have a read pointer,
1394 THEN this is the first fix for the current file.
1395 Open the source file. That will be used as stdin for
1396 the first fix. Any subsequent fixes will use the
1397 stdout descriptor of the previous fix for its stdin. */
1401 read_fd
= open (pz_curr_file
, O_RDONLY
);
1404 fprintf (stderr
, "Error %d (%s) opening %s\n", errno
,
1405 xstrerror (errno
), pz_curr_file
);
1406 exit (EXIT_FAILURE
);
1409 /* Ensure we do not get duplicate output */
1414 read_fd
= start_fixer (read_fd
, p_fixd
, pz_curr_file
);
1418 /* IF we have a read-back file descriptor,
1419 THEN check for changes and write output if changed. */
1423 test_for_changes (read_fd
);
1425 apply_ct
+= num_children
;
1427 /* Wait for child processes created by chain_open()
1428 to avoid leaving zombies. */
1430 wait ((int *) NULL
);
1431 } while (--num_children
> 0);
1434 # else /* is SEPARATE_FIX_PROC */
1436 for (; todo_ct
> 0; p_fixd
++, todo_ct
--)
1438 if (! fix_applies (p_fixd
))
1441 if (VLEVEL( VERB_APPLIES
))
1442 fprintf (stderr
, "Applying %-24s to %s\n",
1443 p_fixd
->fix_name
, pz_curr_file
);
1445 if (p_fixd
->fd_flags
& FD_REPLACEMENT
)
1447 write_replacement (p_fixd
);
1451 fix_with_system (p_fixd
, pz_curr_file
, pz_file_source
, pz_temp_file
);
1452 pz_file_source
= pz_temp_file
;
1455 read_fd
= open (pz_temp_file
, O_RDONLY
);
1458 if (errno
!= ENOENT
)
1459 fprintf (stderr
, "error %d (%s) opening output (%s) for read\n",
1460 errno
, xstrerror (errno
), pz_temp_file
);
1464 test_for_changes (read_fd
);
1465 /* Unlinking a file while it is still open is a Bad Idea on
1468 unlink (pz_temp_file
);