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. */
28 #if defined( HAVE_MMAP_FILE )
30 #define BAD_ADDR ((void*)-1)
33 #ifndef SEPARATE_FIX_PROC
37 /* The contents of this string are not very important. It is mostly
38 just used as part of the "I am alive and working" test. */
40 static const char program_id
[] = "fixincl version 1.1";
42 /* This format will be used at the start of every generated file */
44 static const char z_std_preamble
[] =
45 "/* DO NOT EDIT THIS FILE.\n\n\
46 It has been auto-edited by fixincludes from:\n\n\
48 This had to be done to correct non-standard usages in the\n\
49 original, manufacturer supplied header file. */\n\n";
51 int find_base_len
= 0;
62 te_verbose verbose_level
= VERB_PROGRESS
;
65 #define VLEVEL(l) ((unsigned int) verbose_level >= (unsigned int) l)
66 #define NOT_SILENT VLEVEL(VERB_FIXES)
68 pid_t process_chain_head
= (pid_t
) -1;
70 char* pz_curr_file
; /* name of the current file under test/fix */
71 char* pz_curr_data
; /* original contents of that file */
72 char* pz_temp_file
; /* for DOS, a place to stash the temporary
73 fixed data between system(3) calls */
74 t_bool curr_data_mapped
;
77 size_t ttl_data_size
= 0;
86 const char incl_quote_pat
[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
87 tSCC z_fork_err
[] = "Error %d (%s) starting filter process for %s\n";
88 regex_t incl_quote_re
;
90 static void do_version (void) ATTRIBUTE_NORETURN
;
91 char *load_file (const char *);
92 void run_compiles (void);
93 void initialize (int argc
, char** argv
);
96 /* External Source Code */
100 /* * * * * * * * * * * * * * * * * * *
104 extern int main (int, char **);
106 main (int argc
, char** argv
)
110 initialize ( argc
, argv
);
112 have_tty
= isatty (fileno (stderr
));
114 /* Before anything else, ensure we can allocate our file name buffer. */
115 file_name_buf
= load_file_data (stdin
);
117 /* Because of the way server shells work, you have to keep stdin, out
118 and err open so that the proper input file does not get closed
121 freopen ("/dev/null", "r", stdin
);
123 if (file_name_buf
== (char *) NULL
)
125 fputs ("No file names listed for fixing\n", stderr
);
133 /* skip to start of name, past any "./" prefixes */
135 while (ISSPACE (*file_name_buf
)) file_name_buf
++;
136 while ((file_name_buf
[0] == '.') && (file_name_buf
[1] == '/'))
139 /* Check for end of list */
141 if (*file_name_buf
== NUL
)
144 /* Set global file name pointer and find end of name */
146 pz_curr_file
= file_name_buf
;
147 pz_end
= strchr( pz_curr_file
, '\n' );
148 if (pz_end
== (char*)NULL
)
149 pz_end
= file_name_buf
= pz_curr_file
+ strlen (pz_curr_file
);
151 file_name_buf
= pz_end
+ 1;
153 while ((pz_end
> pz_curr_file
) && ISSPACE( pz_end
[-1])) pz_end
--;
155 /* IF no name is found (blank line) or comment marker, skip line */
157 if ((pz_curr_file
== pz_end
) || (*pz_curr_file
== '#'))
165 if (VLEVEL( VERB_PROGRESS
)) {
168 Processed %5d files containing %d bytes \n\
169 Applying %5d fixes to %d files\n\
170 Altering %5d of them\n";
172 fprintf (stderr
, zFmt
, process_ct
, ttl_data_size
, apply_ct
,
173 fixed_ct
, altered_ct
);
175 #endif /* DO_STATS */
177 # ifdef SEPARATE_FIX_PROC
178 unlink( pz_temp_file
);
187 static const char zFmt
[] = "echo '%s'";
190 /* The 'version' option is really used to test that:
191 1. The program loads correctly (no missing libraries)
192 2. that we can compile all the regular expressions.
193 3. we can correctly run our server shell process
196 sprintf (zBuf
, zFmt
, program_id
);
197 #ifndef SEPARATE_FIX_PROC
199 exit (strcmp (run_shell (zBuf
), program_id
));
201 exit (system (zBuf
));
205 /* * * * * * * * * * * * */
208 initialize ( int argc
, char** argv
)
210 xmalloc_set_program_name (argv
[0]);
218 if (strcmp (argv
[1], "-v") == 0)
220 if (freopen (argv
[1], "r", stdin
) == (FILE*)NULL
)
222 fprintf (stderr
, "Error %d (%s) reopening %s as stdin\n",
223 errno
, xstrerror (errno
), argv
[1] );
229 fputs ("fixincl ERROR: too many command line arguments\n", stderr
);
234 /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
235 receive the signal. A different setting is inheritable */
236 signal (SIGCHLD
, SIG_DFL
);
241 if (ISDIGIT ( *pz_verbose
))
242 verbose_level
= (te_verbose
)atoi( pz_verbose
);
244 switch (*pz_verbose
) {
247 verbose_level
= VERB_SILENT
; break;
251 verbose_level
= VERB_FIXES
; break;
255 verbose_level
= VERB_APPLIES
; break;
260 verbose_level
= VERB_PROGRESS
; break;
264 verbose_level
= VERB_TESTS
; break;
268 verbose_level
= VERB_EVERYTHING
; break;
270 if (verbose_level
>= VERB_EVERYTHING
) {
271 verbose_level
= VERB_EVERYTHING
;
272 fputs ("fixinc verbosity: EVERYTHING\n", stderr
);
274 while ((pz_find_base
[0] == '.') && (pz_find_base
[1] == '/'))
276 if ((pz_find_base
[0] != '.') || (pz_find_base
[1] != NUL
))
277 find_base_len
= strlen( pz_find_base
);
279 /* Compile all the regular expressions now.
280 That way, it is done only once for the whole run.
284 # ifdef SEPARATE_FIX_PROC
285 /* NULL as the first argument to `tempnam' causes it to DTRT
286 wrt the temporary directory where the file will be created. */
287 pz_temp_file
= tempnam( NULL
, "fxinc" );
290 signal (SIGQUIT
, SIG_IGN
);
291 signal (SIGIOT
, SIG_IGN
);
292 signal (SIGPIPE
, SIG_IGN
);
293 signal (SIGALRM
, SIG_IGN
);
294 signal (SIGTERM
, SIG_IGN
);
297 /* * * * * * * * * * * * *
299 load_file loads all the contents of a file into malloc-ed memory.
300 Its argument is the name of the file to read in; the returned
301 result is the NUL terminated contents of the file. The file
302 is presumed to be an ASCII text file containing no NULs. */
304 load_file ( const char* fname
)
309 if (stat (fname
, &stbf
) != 0)
312 fprintf (stderr
, "error %d (%s) stat-ing %s\n",
313 errno
, xstrerror (errno
), fname
);
314 return (char *) NULL
;
316 if (stbf
.st_size
== 0)
319 /* Make the data map size one larger than the file size for documentation
320 purposes. Truth is that there will be a following NUL character if
321 the file size is not a multiple of the page size. If it is a multiple,
322 then this adjustment sometimes fails anyway. */
323 data_map_size
= stbf
.st_size
+1;
324 data_map_fd
= open (fname
, O_RDONLY
);
325 ttl_data_size
+= data_map_size
-1;
330 fprintf (stderr
, "error %d (%s) opening %s for read\n",
331 errno
, xstrerror (errno
), fname
);
335 #ifdef HAVE_MMAP_FILE
336 curr_data_mapped
= BOOL_TRUE
;
338 /* IF the file size is a multiple of the page size,
339 THEN sometimes you will seg fault trying to access a trailing byte */
340 if ((stbf
.st_size
& (getpagesize()-1)) == 0)
341 res
= (char*)BAD_ADDR
;
343 res
= (char*)mmap ((void*)NULL
, data_map_size
, PROT_READ
,
344 MAP_PRIVATE
, data_map_fd
, 0);
345 if (res
== (char*)BAD_ADDR
)
348 FILE* fp
= fdopen (data_map_fd
, "r");
349 curr_data_mapped
= BOOL_FALSE
;
350 res
= load_file_data (fp
);
358 machine_matches( tFixDesc
* p_fixd
)
360 # ifndef SEPARATE_FIX_PROC
361 tSCC case_fmt
[] = "case %s in\n"; /* 9 bytes, plus string */
363 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
364 tSCC skip
[] = "skip"; /* 4 bytes */
365 tSCC run
[] = "run"; /* 3 bytes */
366 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
368 const char **papz_machs
= p_fixd
->papz_machs
;
370 const char *pz_sep
= "";
373 char cmd_buf
[ MACH_LIST_SIZE_LIMIT
]; /* size lim from fixincl.tpl */
375 /* Start the case statement */
377 sprintf (cmd_buf
, case_fmt
, pz_machine
);
378 pz
= cmd_buf
+ strlen (cmd_buf
);
380 /* Determine if a match means to apply the fix or not apply it */
382 if (p_fixd
->fd_flags
& FD_MACH_IFNOT
)
393 /* Emit all the machine names. If there are more than one,
394 then we will insert " | \\\n" between the names */
398 const char* pz_mach
= *(papz_machs
++);
400 if (pz_mach
== (const char*) NULL
)
402 sprintf (pz
, "%s%s", pz_sep
, pz_mach
);
407 /* Now emit the match and not-match actions and the esac */
409 sprintf (pz
, esac_fmt
, pz_if_true
, pz_if_false
);
412 The result will start either with 's' or 'r'. */
416 pz
= run_shell (cmd_buf
);
421 p_fixd
->fd_flags
|= FD_SKIP_TEST
;
427 # else /* is SEPARATE_FIX_PROC */
428 const char **papz_machs
= p_fixd
->papz_machs
;
429 int invert
= (p_fixd
->fd_flags
& FD_MACH_IFNOT
) != 0;
432 const char* pz_mach
= *(papz_machs
++);
434 if (pz_mach
== (const char*) NULL
)
436 if (strstr (pz_mach
, "dos") != NULL
&& !invert
)
440 p_fixd
->fd_flags
|= FD_SKIP_TEST
;
445 /* * * * * * * * * * * * *
447 run_compiles run all the regexp compiles for all the fixes once.
452 tFixDesc
*p_fixd
= fixDescList
;
453 int fix_ct
= FIX_COUNT
;
454 regex_t
*p_re
= xcalloc (REGEX_COUNT
, sizeof (regex_t
));
456 /* Make sure compile_re does not stumble across invalid data */
458 memset (&incl_quote_re
, '\0', sizeof (regex_t
));
460 compile_re (incl_quote_pat
, &incl_quote_re
, 1,
461 "quoted include", "run_compiles");
463 /* Allow machine name tests to be ignored (testing, mainly) */
465 if (pz_machine
&& ((*pz_machine
== '\0') || (*pz_machine
== '*')))
466 pz_machine
= (char*)NULL
;
468 /* FOR every fixup, ... */
471 tTestDesc
*p_test
= p_fixd
->p_test_desc
;
472 int test_ct
= p_fixd
->test_ct
;
474 /* IF the machine type pointer is not NULL (we are not in test mode)
475 AND this test is for or not done on particular machines
478 if ( (pz_machine
!= NULL
)
479 && (p_fixd
->papz_machs
!= (const char**) NULL
)
480 && ! machine_matches (p_fixd
) )
483 /* FOR every test for the fixup, ... */
485 while (--test_ct
>= 0)
487 switch (p_test
->type
)
491 p_test
->p_test_regex
= p_re
++;
492 compile_re (p_test
->pz_test_text
, p_test
->p_test_regex
, 0,
493 "select test", p_fixd
->fix_name
);
499 while (p_fixd
++, --fix_ct
> 0);
503 /* * * * * * * * * * * * *
505 create_file Create the output modified file.
506 Input: the name of the file to create
507 Returns: a file pointer to the new, open file */
509 #if defined(S_IRUSR) && defined(S_IWUSR) && \
510 defined(S_IRGRP) && defined(S_IROTH)
512 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
514 # define S_IRALL 0644
517 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
518 defined(S_IROTH) && defined(S_IXOTH)
520 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
522 # define S_DIRALL 0755
531 char fname
[MAXPATHLEN
];
533 sprintf (fname
, "%s/%s", pz_dest_dir
, pz_curr_file
+ find_base_len
);
535 fd
= open (fname
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRALL
);
537 /* We may need to create the directories needed... */
538 if ((fd
< 0) && (errno
== ENOENT
))
540 char *pz_dir
= strchr (fname
+ 1, '/');
543 while (pz_dir
!= (char *) NULL
)
546 if (stat (fname
, &stbf
) < 0)
551 mkdir (fname
, S_IFDIR
| S_DIRALL
);
556 pz_dir
= strchr (pz_dir
+ 1, '/');
559 /* Now, lets try the open again... */
560 fd
= open (fname
, O_WRONLY
| O_CREAT
| O_TRUNC
, S_IRALL
);
564 fprintf (stderr
, "Error %d (%s) creating %s\n",
565 errno
, xstrerror (errno
), fname
);
569 fprintf (stderr
, "Fixed: %s\n", pz_curr_file
);
570 pf
= fdopen (fd
, "w");
573 * IF pz_machine is NULL, then we are in some sort of test mode.
574 * Do not insert the current directory name. Use a constant string.
576 fprintf (pf
, z_std_preamble
,
586 /* * * * * * * * * * * * *
588 test_test make sure a shell-style test expression passes.
589 Input: a pointer to the descriptor of the test to run and
590 the name of the file that we might want to fix
591 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
592 shell script we run. */
593 #ifndef SEPARATE_FIX_PROC
595 test_test (tTestDesc
* p_test
, char* pz_test_file
)
599 if ( test %s ) > /dev/null 2>&1\n\
607 static char cmd_buf
[4096];
609 sprintf (cmd_buf
, cmd_fmt
, pz_test_file
, p_test
->pz_test_text
);
610 pz_res
= run_shell (cmd_buf
);
622 fprintf (stderr
, "Script yielded bogus result of `%s':\n%s\n\n",
627 free ((void *) pz_res
);
632 * IF we are in MS-DOS land, then whatever shell-type test is required
633 * will, by definition, fail
635 #define test_test(t,tf) SKIP_FIX
638 /* * * * * * * * * * * * *
640 egrep_test make sure an egrep expression is found in the file text.
641 Input: a pointer to the descriptor of the test to run and
642 the pointer to the contents of the file under suspicion
643 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
645 The caller may choose to reverse meaning if the sense of the test
649 egrep_test (char* pz_data
, tTestDesc
* p_test
)
652 if (p_test
->p_test_regex
== 0)
653 fprintf (stderr
, "fixincl ERROR RE not compiled: `%s'\n",
654 p_test
->pz_test_text
);
656 if (xregexec (p_test
->p_test_regex
, pz_data
, 0, 0, 0) == 0)
662 /* * * * * * * * * * * * *
664 quoted_file_exists Make sure that a file exists before we emit
665 the file name. If we emit the name, our invoking shell will try
666 to copy a non-existing file into the destination directory. */
669 quoted_file_exists (const char* pz_src_path
,
670 const char* pz_file_path
,
673 char z
[ MAXPATHLEN
];
675 sprintf (z
, "%s/%s/", pz_src_path
, pz_file_path
);
676 pz
= z
+ strlen ( z
);
679 char ch
= *pz_file
++;
689 if (stat (z
, &s
) != 0)
691 return S_ISREG( s
.st_mode
);
696 /* * * * * * * * * * * * *
700 The syntax, `#include "file.h"' specifies that the compiler is to
701 search the local directory of the current file before the include
702 list. Consequently, if we have modified a header and stored it in
703 another directory, any files that are included by that modified
704 file in that fashion must also be copied into this new directory.
705 This routine finds those flavors of #include and for each one found
708 1. source directory of the original file
709 2. the relative path file name of the #includ-ed file
710 3. the full destination path for this file
712 Input: the text of the file, the file name and a pointer to the
713 match list where the match information was stored.
714 Result: internally nothing. The results are written to stdout
715 for interpretation by the invoking shell */
719 extract_quoted_files (char* pz_data
,
720 const char* pz_fixed_file
,
721 regmatch_t
* p_re_match
)
723 char *pz_dir_end
= strrchr (pz_fixed_file
, '/');
724 char *pz_incl_quot
= pz_data
;
726 if (VLEVEL( VERB_APPLIES
))
727 fprintf (stderr
, "Quoted includes in %s\n", pz_fixed_file
);
729 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
730 If there is none, then it is in our current directory, ".". */
732 if (pz_dir_end
== (char *) NULL
)
739 pz_incl_quot
+= p_re_match
->rm_so
;
741 /* Skip forward to the included file name */
742 while (*pz_incl_quot
!= '"')
745 if (quoted_file_exists (pz_src_dir
, pz_fixed_file
, pz_incl_quot
))
747 /* Print the source directory and the subdirectory
748 of the file in question. */
749 printf ("%s %s/", pz_src_dir
, pz_fixed_file
);
750 pz_dir_end
= pz_incl_quot
;
752 /* Append to the directory the relative path of the desired file */
753 while (*pz_incl_quot
!= '"')
754 putc (*pz_incl_quot
++, stdout
);
756 /* Now print the destination directory appended with the
757 relative path of the desired file */
758 printf (" %s/%s/", pz_dest_dir
, pz_fixed_file
);
759 while (*pz_dir_end
!= '"')
760 putc (*pz_dir_end
++, stdout
);
766 /* Find the next entry */
767 if (xregexec (&incl_quote_re
, pz_incl_quot
, 1, p_re_match
, 0) != 0)
773 /* * * * * * * * * * * * *
775 Somebody wrote a *_fix subroutine that we must call.
777 #ifndef SEPARATE_FIX_PROC
779 internal_fix (int read_fd
, tFixDesc
* p_fixd
)
785 fprintf (stderr
, "Error %d on pipe(2) call\n", errno
);
791 pid_t childid
= fork();
814 fprintf (stderr
, z_fork_err
, errno
, xstrerror (errno
),
817 static int failCt
= 0;
818 if ((errno
!= EAGAIN
) || (++failCt
> 10))
825 * Close our current stdin and stdout
827 close (STDIN_FILENO
);
828 close (STDOUT_FILENO
);
832 * Make the fd passed in the stdin, and the write end of
833 * the new pipe become the stdout.
835 dup2 (fd
[1], STDOUT_FILENO
);
836 dup2 (read_fd
, STDIN_FILENO
);
838 apply_fix (p_fixd
, pz_curr_file
);
841 #endif /* !SEPARATE_FIX_PROC */
844 #ifdef SEPARATE_FIX_PROC
846 fix_with_system (tFixDesc
* p_fixd
,
855 if (p_fixd
->fd_flags
& FD_SUBROUTINE
)
857 static const char z_applyfix_prog
[] =
858 "/../fixincludes/applyfix" EXE_EXT
;
862 + strlen (pz_orig_dir
)
863 + sizeof (z_applyfix_prog
)
864 + strlen (pz_fix_file
)
865 + strlen (pz_file_source
)
866 + strlen (pz_temp_file
);
868 /* Allocate something sure to be big enough for our purposes */
869 pz_cmd
= xmalloc (argsize
);
870 strcpy (pz_cmd
, pz_orig_dir
);
871 pz_scan
= pz_cmd
+ strlen (pz_orig_dir
);
873 strcpy (pz_scan
, z_applyfix_prog
);
875 /* IF we can't find the "applyfix" executable file at the first guess,
876 try one level higher up */
877 if (stat (pz_cmd
, &buf
) == -1)
879 strcpy (pz_scan
, "/..");
880 strcpy (pz_scan
+3, z_applyfix_prog
);
883 pz_scan
+= strlen (pz_scan
);
886 * Now add the fix number and file names that may be needed
888 sprintf (pz_scan
, " %ld '%s' '%s' '%s'", p_fixd
- fixDescList
,
889 pz_fix_file
, pz_file_source
, pz_temp_file
);
891 else /* NOT an "internal" fix: */
895 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
896 dst is a temporary file anyway, so we know there's no other
897 file by that name; and DOS's system(3) doesn't mind to
898 clobber existing file in redirection. Besides, with DOS 8+3
899 limited file namespace, we can easily lose if dst already has
900 an extension that is 3 or more characters long.
902 I do not think the 8+3 issue is relevant because all the files
903 we operate on are named "*.h", making 8+2 adequate. Anyway,
904 the following bizarre use of 'cat' only works on DOS boxes.
905 It causes the file to be dropped into a temporary file for
906 'cat' to read (pipes do not work on DOS). */
907 tSCC z_cmd_fmt
[] = " '%s' | cat > '%s'";
909 /* Don't use positional formatting arguments because some lame-o
910 implementations cannot cope :-(. */
911 tSCC z_cmd_fmt
[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
913 tCC
** ppArgs
= p_fixd
->patch_args
;
915 argsize
= sizeof( z_cmd_fmt
) + strlen( pz_temp_file
)
916 + strlen( pz_file_source
);
921 * Compute the size of the command line. Add lotsa extra space
922 * because some of the args to sed use lotsa single quotes.
923 * (This requires three extra bytes per quote. Here we allow
924 * for up to 8 single quotes for each argument, including the
925 * command name "sed" itself. Nobody will *ever* need more. :)
929 tCC
* p_arg
= *(ppArgs
++);
932 argsize
+= 24 + strlen( p_arg
);
935 /* Estimated buffer size we will need. */
936 pz_scan
= pz_cmd
= xmalloc (argsize
);
937 /* How much of it do we allot to the program name and its
939 parg_size
= argsize
- parg_size
;
941 ppArgs
= p_fixd
->patch_args
;
944 * Copy the program name, unquoted
947 tCC
* pArg
= *(ppArgs
++);
958 * Copy the program arguments, quoted
962 tCC
* pArg
= *(ppArgs
++);
967 pz_scan
= make_raw_shell_str( pz_scan_save
= pz_scan
, pArg
,
968 parg_size
- (pz_scan
- pz_cmd
) );
970 * Make sure we don't overflow the buffer due to sloppy
973 while (pz_scan
== (char*)NULL
)
975 size_t already_filled
= pz_scan_save
- pz_cmd
;
976 pz_cmd
= xrealloc (pz_cmd
, argsize
+= 100);
977 pz_scan_save
= pz_scan
= pz_cmd
+ already_filled
;
979 pz_scan
= make_raw_shell_str( pz_scan
, pArg
,
980 parg_size
- (pz_scan
- pz_cmd
) );
985 * add the file machinations.
988 sprintf (pz_scan
, z_cmd_fmt
, pz_file_source
, pz_temp_file
);
990 sprintf (pz_scan
, z_cmd_fmt
, pz_file_source
, pz_temp_file
,
991 pz_temp_file
, pz_temp_file
, pz_temp_file
);
995 free( (void*)pz_cmd
);
998 /* * * * * * * * * * * * *
1000 This loop should only cycle for 1/2 of one loop.
1001 "chain_open" starts a process that uses "read_fd" as
1002 its stdin and returns the new fd this process will use
1005 #else /* is *NOT* SEPARATE_FIX_PROC */
1007 start_fixer (int read_fd
, tFixDesc
* p_fixd
, char* pz_fix_file
)
1012 if ((p_fixd
->fd_flags
& FD_SUBROUTINE
) != 0)
1013 return internal_fix (read_fd
, p_fixd
);
1015 if ((p_fixd
->fd_flags
& FD_SHELL_SCRIPT
) == 0)
1022 tSCC z_cmd_fmt
[] = "file='%s'\n%s";
1023 pz_cmd
= xmalloc (strlen (p_fixd
->patch_args
[2])
1024 + sizeof (z_cmd_fmt
) + strlen (pz_fix_file
));
1025 sprintf (pz_cmd
, z_cmd_fmt
, pz_fix_file
, p_fixd
->patch_args
[2]);
1026 pz_cmd_save
= p_fixd
->patch_args
[2];
1027 p_fixd
->patch_args
[2] = pz_cmd
;
1030 /* Start a fix process, handing off the previous read fd for its
1031 stdin and getting a new fd that reads from the fix process' stdout.
1032 We normally will not loop, but we will up to 10 times if we keep
1033 getting "EAGAIN" errors.
1038 static int failCt
= 0;
1041 fd
= chain_open (read_fd
,
1042 (tCC
**) p_fixd
->patch_args
,
1043 (process_chain_head
== -1)
1044 ? &process_chain_head
: (pid_t
*) NULL
);
1052 fprintf (stderr
, z_fork_err
, errno
, xstrerror (errno
),
1055 if ((errno
!= EAGAIN
) || (++failCt
> 10))
1056 exit (EXIT_FAILURE
);
1060 /* IF we allocated a shell script command,
1061 THEN free it and restore the command format to the fix description */
1062 if (pz_cmd
!= (char*)NULL
)
1064 free ((void*)pz_cmd
);
1065 p_fixd
->patch_args
[2] = pz_cmd_save
;
1073 /* * * * * * * * * * * * *
1075 Process the potential fixes for a particular include file.
1076 Input: the original text of the file and the file's name
1077 Result: none. A new file may or may not be created. */
1080 fix_applies (tFixDesc
* p_fixd
)
1082 const char *pz_fname
= pz_curr_file
;
1083 const char *pz_scan
= p_fixd
->file_list
;
1087 # ifdef SEPARATE_FIX_PROC
1089 * There is only one fix that uses a shell script as of this writing.
1090 * I hope to nuke it anyway, it does not apply to DOS and it would
1091 * be painful to implement. Therefore, no "shell" fixes for DOS.
1093 if (p_fixd
->fd_flags
& (FD_SHELL_SCRIPT
| FD_SKIP_TEST
))
1096 if (p_fixd
->fd_flags
& FD_SKIP_TEST
)
1100 /* IF there is a file name restriction,
1101 THEN ensure the current file name matches one in the pattern */
1103 if (pz_scan
!= (char *) NULL
)
1107 while ((pz_fname
[0] == '.') && (pz_fname
[1] == '/'))
1109 name_len
= strlen (pz_fname
);
1113 pz_scan
= strstr (pz_scan
+ 1, pz_fname
);
1114 /* IF we can't match the string at all,
1116 if (pz_scan
== (char *) NULL
)
1119 /* IF the match is surrounded by the '|' markers,
1120 THEN we found a full match -- time to run the tests */
1122 if ((pz_scan
[-1] == '|') && (pz_scan
[name_len
] == '|'))
1127 /* FOR each test, see if it fails.
1128 IF it does fail, then we go on to the next test */
1130 for (p_test
= p_fixd
->p_test_desc
, test_ct
= p_fixd
->test_ct
;
1134 switch (p_test
->type
)
1137 if (test_test (p_test
, pz_curr_file
) != APPLY_FIX
) {
1139 if (VLEVEL( VERB_EVERYTHING
))
1140 fprintf (stderr
, z_failed
, "TEST", p_fixd
->fix_name
,
1141 pz_fname
, p_fixd
->test_ct
- test_ct
);
1148 if (egrep_test (pz_curr_data
, p_test
) != APPLY_FIX
) {
1150 if (VLEVEL( VERB_EVERYTHING
))
1151 fprintf (stderr
, z_failed
, "EGREP", p_fixd
->fix_name
,
1152 pz_fname
, p_fixd
->test_ct
- test_ct
);
1159 if (egrep_test (pz_curr_data
, p_test
) == APPLY_FIX
) {
1161 if (VLEVEL( VERB_EVERYTHING
))
1162 fprintf (stderr
, z_failed
, "NEGREP", p_fixd
->fix_name
,
1163 pz_fname
, p_fixd
->test_ct
- test_ct
);
1171 if (run_test (p_test
->pz_test_text
, pz_curr_file
, pz_curr_data
)
1174 if (VLEVEL( VERB_EVERYTHING
))
1175 fprintf (stderr
, z_failed
, "FTEST", p_fixd
->fix_name
,
1176 pz_fname
, p_fixd
->test_ct
- test_ct
);
1188 /* * * * * * * * * * * * *
1190 Write out a replacement file */
1193 write_replacement (tFixDesc
* p_fixd
)
1195 const char* pz_text
= p_fixd
->patch_args
[0];
1197 if ((pz_text
== (char*)NULL
) || (*pz_text
== NUL
))
1201 FILE* out_fp
= create_file ();
1202 fputs (pz_text
, out_fp
);
1208 /* * * * * * * * * * * * *
1210 We have work to do. Read back in the output
1211 of the filtering chain. Compare each byte as we read it with
1212 the contents of the original file. As soon as we find any
1213 difference, we will create the output file, write out all
1214 the matched text and then copy any remaining data from the
1215 output of the filter chain.
1218 test_for_changes (int read_fd
)
1220 FILE *in_fp
= fdopen (read_fd
, "r");
1221 FILE *out_fp
= (FILE *) NULL
;
1222 unsigned char *pz_cmp
= (unsigned char*)pz_curr_data
;
1234 ch
&= 0xFF; /* all bytes are 8 bits */
1236 /* IF we are emitting the output
1237 THEN emit this character, too.
1239 if (out_fp
!= (FILE *) NULL
)
1242 /* ELSE if this character does not match the original,
1243 THEN now is the time to start the output.
1245 else if (ch
!= *pz_cmp
)
1247 out_fp
= create_file ();
1252 /* IF there are matched data, write the matched part now. */
1253 if ((char*)pz_cmp
!= pz_curr_data
)
1254 fwrite (pz_curr_data
, (size_t)((char*)pz_cmp
- pz_curr_data
),
1257 /* Emit the current unmatching character */
1261 /* ELSE the character matches. Advance the compare ptr */
1265 /* IF we created the output file, ... */
1266 if (out_fp
!= (FILE *) NULL
)
1270 /* Close the file and see if we have to worry about
1271 `#include "file.h"' constructs. */
1273 if (xregexec (&incl_quote_re
, pz_curr_data
, 1, &match
, 0) == 0)
1274 extract_quoted_files (pz_curr_data
, pz_curr_file
, &match
);
1278 close (read_fd
); /* probably redundant, but I'm paranoid */
1282 /* * * * * * * * * * * * *
1284 Process the potential fixes for a particular include file.
1285 Input: the original text of the file and the file's name
1286 Result: none. A new file may or may not be created. */
1291 tFixDesc
*p_fixd
= fixDescList
;
1292 int todo_ct
= FIX_COUNT
;
1294 # ifndef SEPARATE_FIX_PROC
1295 int num_children
= 0;
1296 # else /* is SEPARATE_FIX_PROC */
1297 char* pz_file_source
= pz_curr_file
;
1300 if (access (pz_curr_file
, R_OK
) != 0)
1303 fprintf (stderr
, "Cannot access %s from %s\n\terror %d (%s)\n",
1304 pz_curr_file
, getcwd ((char *) NULL
, MAXPATHLEN
),
1305 erno
, xstrerror (erno
));
1309 pz_curr_data
= load_file (pz_curr_file
);
1310 if (pz_curr_data
== (char *) NULL
)
1316 if (VLEVEL( VERB_PROGRESS
) && have_tty
)
1317 fprintf (stderr
, "%6lu %-50s \r",
1318 (unsigned long) data_map_size
, pz_curr_file
);
1320 # ifndef SEPARATE_FIX_PROC
1321 process_chain_head
= NOPROCESS
;
1323 /* For every fix in our fix list, ... */
1324 for (; todo_ct
> 0; p_fixd
++, todo_ct
--)
1326 if (! fix_applies (p_fixd
))
1329 if (VLEVEL( VERB_APPLIES
))
1330 fprintf (stderr
, "Applying %-24s to %s\n",
1331 p_fixd
->fix_name
, pz_curr_file
);
1333 if (p_fixd
->fd_flags
& FD_REPLACEMENT
)
1335 write_replacement (p_fixd
);
1340 /* IF we do not have a read pointer,
1341 THEN this is the first fix for the current file.
1342 Open the source file. That will be used as stdin for
1343 the first fix. Any subsequent fixes will use the
1344 stdout descriptor of the previous fix for its stdin. */
1348 read_fd
= open (pz_curr_file
, O_RDONLY
);
1351 fprintf (stderr
, "Error %d (%s) opening %s\n", errno
,
1352 xstrerror (errno
), pz_curr_file
);
1353 exit (EXIT_FAILURE
);
1356 /* Ensure we do not get duplicate output */
1361 read_fd
= start_fixer (read_fd
, p_fixd
, pz_curr_file
);
1365 /* IF we have a read-back file descriptor,
1366 THEN check for changes and write output if changed. */
1370 test_for_changes (read_fd
);
1372 apply_ct
+= num_children
;
1374 /* Wait for child processes created by chain_open()
1375 to avoid leaving zombies. */
1377 wait ((int *) NULL
);
1378 } while (--num_children
> 0);
1381 # else /* is SEPARATE_FIX_PROC */
1383 for (; todo_ct
> 0; p_fixd
++, todo_ct
--)
1385 if (! fix_applies (p_fixd
))
1388 if (VLEVEL( VERB_APPLIES
))
1389 fprintf (stderr
, "Applying %-24s to %s\n",
1390 p_fixd
->fix_name
, pz_curr_file
);
1392 if (p_fixd
->fd_flags
& FD_REPLACEMENT
)
1394 write_replacement (p_fixd
);
1398 fix_with_system (p_fixd
, pz_curr_file
, pz_file_source
, pz_temp_file
);
1399 pz_file_source
= pz_temp_file
;
1402 read_fd
= open (pz_temp_file
, O_RDONLY
);
1405 if (errno
!= ENOENT
)
1406 fprintf (stderr
, "error %d (%s) opening output (%s) for read\n",
1407 errno
, xstrerror (errno
), pz_temp_file
);
1411 test_for_changes (read_fd
);
1412 /* Unlinking a file while it is still open is a Bad Idea on
1415 unlink (pz_temp_file
);