2 /* Install modified versions of certain ANSI-incompatible system header
3 files which are fixed to work correctly with ANSI C and placed in a
4 directory that GNU C will search.
6 Copyright (C) 1997-1999, 2000 Free Software Foundation, Inc.
8 This file is part of GNU CC.
10 GNU CC 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 2, or (at your option)
15 GNU CC 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 GNU CC; see the file COPYING. If not, write to
22 the Free Software Foundation, 59 Temple Place - Suite 330,
23 Boston, MA 02111-1307, USA. */
29 #define BAD_ADDR ((void*)-1)
36 /* Quality Assurance Marker :-)
38 Any file that contains this string is presumed to have
39 been carefully constructed and will not be fixed */
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";
48 Each fix may have associated tests that determine
49 whether the fix needs to be applied or not.
50 Each test has a type (from the te_test_type enumeration);
51 associated test text; and, if the test is TT_EGREP or
52 the negated form TT_NEGREP, a pointer to the compiled
53 version of the text string.
58 TT_TEST, TT_EGREP, TT_NEGREP, TT_FUNCTION
61 typedef struct test_desc tTestDesc;
66 const char *pz_test_text;
67 regex_t *p_test_regex;
70 typedef struct patch_desc tPatchDesc;
74 Everything you ever wanted to know about how to apply
75 a particular fix (which files, how to qualify them,
76 how to actually make the fix, etc...)
78 NB: the FD_ defines are BIT FLAGS
81 #define FD_MACH_ONLY 0x0000
82 #define FD_MACH_IFNOT 0x0001
83 #define FD_SHELL_SCRIPT 0x0002
84 #define FD_SUBROUTINE 0x0004
85 #define FD_REPLACEMENT 0x0008
86 #define FD_SKIP_TEST 0x8000
88 typedef struct fix_desc tFixDesc;
91 const char* fix_name; /* Name of the fix */
92 const char* file_list; /* List of files it applies to */
93 const char** papz_machs; /* List of machine/os-es it applies to */
97 tTestDesc* p_test_desc;
98 const char** patch_args;
101 /* Working environment strings. Essentially, invocation 'options'. */
102 char *pz_dest_dir = NULL;
103 char *pz_src_dir = NULL;
104 char *pz_machine = NULL;
105 int find_base_len = 0;
116 te_verbose verbose_level = VERB_PROGRESS;
119 #define VLEVEL(l) (verbose_level >= l)
120 #define NOT_SILENT VLEVEL(VERB_FIXES)
122 pid_t process_chain_head = (pid_t) -1;
124 char* pz_curr_file; /* name of the current file under test/fix */
125 char* pz_curr_data; /* original contents of that file */
126 t_bool curr_data_mapped;
128 size_t data_map_size;
129 size_t ttl_data_size = 0;
135 #endif /* DO_STATS */
138 #define UNLOAD_DATA() do { if (curr_data_mapped) { \
139 munmap ((void*)pz_curr_data, data_map_size); close (data_map_fd); } \
140 else free ((void*)pz_curr_data); } while(0)
142 #define UNLOAD_DATA() free ((void*)pz_curr_data)
145 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
146 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
147 regex_t incl_quote_re;
150 char *load_file _P_((const char *));
151 void process _P_((char *, const char *));
152 void run_compiles ();
156 /* External Source Code */
159 #include "fixtests.c"
160 #include "fixfixes.c"
162 /* * * * * * * * * * * * * * * * * * *
179 if (strcmp (argv[1], "-v") == 0)
181 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
183 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
184 errno, strerror (errno), argv[1] );
190 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
196 have_tty = isatty (fileno (stderr));
198 /* Before anything else, ensure we can allocate our file name buffer. */
199 file_name_buf = load_file_data (stdin);
201 /* Because of the way server shells work, you have to keep stdin, out
202 and err open so that the proper input file does not get closed
205 freopen ("/dev/null", "r", stdin);
207 if (file_name_buf == (char *) NULL)
209 fputs ("No file names listed for fixing\n", stderr);
217 /* skip to start of name, past any "./" prefixes */
219 while (ISSPACE (*file_name_buf)) file_name_buf++;
220 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
223 /* Check for end of list */
225 if (*file_name_buf == NUL)
228 /* Set global file name pointer and find end of name */
230 pz_curr_file = file_name_buf;
231 pz_end = strchr( pz_curr_file, '\n' );
232 if (pz_end == (char*)NULL)
233 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
235 file_name_buf = pz_end + 1;
237 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
239 /* IF no name is found (blank line) or comment marker, skip line */
241 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
248 /* Prevent duplicate output by child process */
254 void wait_for_pid _P_(( pid_t ));
255 pid_t child = fork ();
256 if (child == NULLPROCESS)
262 if (child == NOPROCESS)
264 fprintf (stderr, "Error %d (%s) forking in main\n",
265 errno, strerror (errno));
269 wait_for_pid( child );
275 if (VLEVEL( VERB_PROGRESS )) {
278 Processed %5d files containing %d bytes \n\
279 Applying %5d fixes to %d files\n\
280 Altering %5d of them\n";
282 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
283 fixed_ct, altered_ct);
285 #endif /* DO_STATS */
293 static const char zFmt[] = "echo '%s'";
296 /* The 'version' option is really used to test that:
297 1. The program loads correctly (no missing libraries)
298 2. we can correctly run our server shell process
299 3. that we can compile all the regular expressions.
302 sprintf (zBuf, zFmt, program_id);
303 fputs (zBuf + 5, stdout);
304 exit (strcmp (run_shell (zBuf), program_id));
307 /* * * * * * * * * * * * */
312 static const char var_not_found[] =
313 "fixincl ERROR: %s environment variable not defined\n\
314 \tTARGET_MACHINE, DESTDIR, SRCDIR and FIND_BASE are required\n";
317 static const char var[] = "TARGET_MACHINE";
318 pz_machine = getenv (var);
319 if (pz_machine == (char *) NULL)
321 fprintf (stderr, var_not_found, var);
327 static const char var[] = "DESTDIR";
328 pz_dest_dir = getenv (var);
329 if (pz_dest_dir == (char *) NULL)
331 fprintf (stderr, var_not_found, var);
337 static const char var[] = "SRCDIR";
338 pz_src_dir = getenv (var);
339 if (pz_src_dir == (char *) NULL)
341 fprintf (stderr, var_not_found, var);
347 static const char var[] = "VERBOSE";
348 char* pz = getenv (var);
349 if (pz != (char *) NULL)
352 verbose_level = (te_verbose)atoi( pz );
357 verbose_level = VERB_SILENT; break;
361 verbose_level = VERB_FIXES; break;
365 verbose_level = VERB_APPLIES; break;
369 verbose_level = VERB_PROGRESS; break;
373 verbose_level = VERB_TESTS; break;
377 verbose_level = VERB_EVERYTHING; break;
383 static const char var[] = "FIND_BASE";
384 char *pz = getenv (var);
385 if (pz == (char *) NULL)
387 fprintf (stderr, var_not_found, var);
390 while ((pz[0] == '.') && (pz[1] == '/'))
392 if ((pz[0] != '.') || (pz[1] != NUL))
393 find_base_len = strlen( pz );
396 /* Compile all the regular expressions now.
397 That way, it is done only once for the whole run.
401 signal (SIGQUIT, SIG_IGN);
402 signal (SIGIOT, SIG_IGN);
403 signal (SIGPIPE, SIG_IGN);
404 signal (SIGALRM, SIG_IGN);
405 signal (SIGTERM, SIG_IGN);
408 Make sure that if we opened a server process, we close it now.
409 This is the grandparent process. We don't need the server anymore
410 and our children should make their own. */
413 (void)wait ( (int*)NULL );
418 /* * * * * * * * * * * * *
420 wait_for_pid - Keep calling `wait(2)' until it returns
421 the process id we are looking for. Not every system has
422 `waitpid(2)'. We also ensure that the children exit with success. */
430 pid_t dead_kid = wait (&status);
432 if (dead_kid == child)
434 if (! WIFEXITED( status ))
436 if (WSTOPSIG( status ) == 0)
439 fprintf (stderr, "child process %d is hung on signal %d\n",
440 child, WSTOPSIG( status ));
443 if (WEXITSTATUS( status ) != 0)
445 fprintf (stderr, "child process %d exited with status %d\n",
446 child, WEXITSTATUS( status ));
449 break; /* normal child completion */
453 IF there is an error, THEN see if it is retryable.
454 If it is not retryable, then break out of this loop. */
455 if (dead_kid == NOPROCESS)
464 fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
465 errno, strerror( errno ), child );
468 case ECHILD: /* no children to wait for?? */
474 #endif /* NO_BOGOSITY */
476 /* * * * * * * * * * * * *
478 load_file loads all the contents of a file into malloc-ed memory.
479 Its argument is the name of the file to read in; the returned
480 result is the NUL terminated contents of the file. The file
481 is presumed to be an ASCII text file containing no NULs. */
489 if (stat (fname, &stbf) != 0)
492 fprintf (stderr, "error %d (%s) stat-ing %s\n",
493 errno, strerror (errno), fname );
494 return (char *) NULL;
496 if (stbf.st_size == 0)
499 data_map_size = stbf.st_size+1;
500 data_map_fd = open (fname, O_RDONLY);
501 ttl_data_size += data_map_size-1;
506 fprintf (stderr, "error %d (%s) opening %s for read\n",
507 errno, strerror (errno), fname);
512 curr_data_mapped = BOOL_TRUE;
513 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE,
515 if (res == (char*)BAD_ADDR)
517 curr_data_mapped = BOOL_FALSE;
518 res = load_file_data ( fdopen (data_map_fd, "r"));
521 curr_data_mapped = BOOL_FALSE;
522 res = load_file_data ( fdopen (data_map_fd, "r"));
529 /* * * * * * * * * * * * *
531 run_compiles run all the regexp compiles for all the fixes once.
536 tFixDesc *p_fixd = fixDescList;
537 int fix_ct = FIX_COUNT;
540 int re_ct = REGEX_COUNT;
542 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
544 if (p_re == (regex_t *) NULL)
546 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
547 REGEX_COUNT * sizeof (regex_t));
551 /* Make sure compile_re does not stumble across invalid data */
553 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
554 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
556 compile_re (incl_quote_pat, &incl_quote_re, 1,
557 "quoted include", "run_compiles");
559 /* FOR every fixup, ... */
562 p_test = p_fixd->p_test_desc;
563 test_ct = p_fixd->test_ct;
565 /* IF the machine type pointer is not NULL (we are not in test mode)
566 AND this test is for or not done on particular machines
569 if ( (pz_machine != NULL)
570 && (p_fixd->papz_machs != (const char**) NULL) )
572 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
574 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
575 tSCC skip[] = "skip"; /* 4 bytes */
576 tSCC run[] = "run"; /* 3 bytes */
577 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
579 const char **papz_machs = p_fixd->papz_machs;
584 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
586 /* Start the case statement */
588 sprintf (cmd_buf, case_fmt, pz_machine);
589 pz = cmd_buf + strlen (cmd_buf);
591 /* Determine if a match means to apply the fix or not apply it */
593 if (p_fixd->fd_flags & FD_MACH_IFNOT)
604 /* Emit all the machine names. If there are more than one,
605 then we will insert " | \\\n" between the names */
609 const char* pz_mach = *(papz_machs++);
611 if (pz_mach == (const char*) NULL)
613 sprintf (pz, "%s%s", pz_sep, pz_mach);
618 /* Now emit the match and not-match actions and the esac */
620 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
623 The result will start either with 's' or 'r'. */
627 pz = run_shell (cmd_buf);
632 p_fixd->fd_flags |= FD_SKIP_TEST;
638 /* FOR every test for the fixup, ... */
640 while (--test_ct >= 0)
642 switch (p_test->type)
646 /* You might consider putting the following under #ifdef.
647 The number of re's used is computed by autogen.
648 So, it is static and known at compile time. */
652 fputs ("out of RE's\n", stderr);
656 p_test->p_test_regex = p_re++;
657 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
658 "select test", p_fixd->fix_name);
663 while (p_fixd++, --fix_ct > 0);
667 /* * * * * * * * * * * * *
669 create_file Create the output modified file.
670 Input: the name of the file to create
671 Returns: a file pointer to the new, open file */
673 #if defined(S_IRUSR) && defined(S_IWUSR) && \
674 defined(S_IRGRP) && defined(S_IROTH)
676 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
678 # define S_IRALL 0644
681 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
682 defined(S_IROTH) && defined(S_IXOTH)
684 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
686 # define S_DIRALL 0755
695 char fname[MAXPATHLEN];
697 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
699 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
701 /* We may need to create the directories needed... */
702 if ((fd < 0) && (errno == ENOENT))
704 char *pz_dir = strchr (fname + 1, '/');
707 while (pz_dir != (char *) NULL)
710 if (stat (fname, &stbf) < 0)
712 mkdir (fname, S_IFDIR | S_DIRALL);
716 pz_dir = strchr (pz_dir + 1, '/');
719 /* Now, lets try the open again... */
720 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
724 fprintf (stderr, "Error %d (%s) creating %s\n",
725 errno, strerror (errno), fname);
729 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
730 pf = fdopen (fd, "w");
734 static const char hdr[] =
735 "/* DO NOT EDIT THIS FILE.\n\n"
736 " It has been auto-edited by fixincludes from /usr/include/%s\n"
737 " This had to be done to correct non-standard usages in the\n"
738 " original, manufacturer supplied header file. */\n\n";
740 fprintf (pf, hdr, pz_curr_file);
747 /* * * * * * * * * * * * *
749 test_test make sure a shell-style test expression passes.
750 Input: a pointer to the descriptor of the test to run and
751 the name of the file that we might want to fix
752 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
753 shell script we run. */
756 test_test (p_test, pz_test_file)
762 if ( test %s ) > /dev/null 2>&1\n\
770 static char cmd_buf[4096];
772 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
773 pz_res = run_shell (cmd_buf);
776 free ((void *) pz_res);
781 /* * * * * * * * * * * * *
783 egrep_test make sure an egrep expression is found in the file text.
784 Input: a pointer to the descriptor of the test to run and
785 the pointer to the contents of the file under suspicion
786 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
788 The caller may choose to reverse meaning if the sense of the test
792 egrep_test (pz_data, p_test)
797 if (p_test->p_test_regex == 0)
798 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
799 p_test->pz_test_text);
801 if (regexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
807 /* * * * * * * * * * * * *
809 quoted_file_exists Make sure that a file exists before we emit
810 the file name. If we emit the name, our invoking shell will try
811 to copy a non-existing file into the destination directory. */
814 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
819 char z[ MAXPATHLEN ];
821 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
822 pz = z + strlen ( z );
825 char ch = *pz_file++;
835 if (stat (z, &s) != 0)
837 return S_ISREG( s.st_mode );
842 /* * * * * * * * * * * * *
846 The syntax, `#include "file.h"' specifies that the compiler is to
847 search the local directory of the current file before the include
848 list. Consequently, if we have modified a header and stored it in
849 another directory, any files that are included by that modified
850 file in that fashion must also be copied into this new directory.
851 This routine finds those flavors of #include and for each one found
854 1. source directory of the original file
855 2. the relative path file name of the #includ-ed file
856 3. the full destination path for this file
858 Input: the text of the file, the file name and a pointer to the
859 match list where the match information was stored.
860 Result: internally nothing. The results are written to stdout
861 for interpretation by the invoking shell */
865 extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
867 const char *pz_fixed_file;
868 regmatch_t *p_re_match;
870 char *pz_dir_end = strrchr (pz_fixed_file, '/');
871 char *pz_incl_quot = pz_data;
873 if (VLEVEL( VERB_APPLIES ))
874 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
876 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
877 If there is none, then it is in our current directory, ".". */
879 if (pz_dir_end == (char *) NULL)
886 pz_incl_quot += p_re_match->rm_so;
888 /* Skip forward to the included file name */
889 while (ISSPACE (*pz_incl_quot))
891 /* ISSPACE() may evaluate is argument more than once! */
892 while (++pz_incl_quot, ISSPACE (*pz_incl_quot))
894 pz_incl_quot += sizeof ("include") - 1;
895 while (*pz_incl_quot++ != '"')
898 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
900 /* Print the source directory and the subdirectory
901 of the file in question. */
902 printf ("%s %s/", pz_src_dir, pz_fixed_file);
903 pz_dir_end = pz_incl_quot;
905 /* Append to the directory the relative path of the desired file */
906 while (*pz_incl_quot != '"')
907 putc (*pz_incl_quot++, stdout);
909 /* Now print the destination directory appended with the
910 relative path of the desired file */
911 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
912 while (*pz_dir_end != '"')
913 putc (*pz_dir_end++, stdout);
919 /* Find the next entry */
920 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
926 /* * * * * * * * * * * * *
928 Somebody wrote a *_fix subroutine that we must call.
932 internal_fix (read_fd, p_fixd)
940 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
946 pid_t childid = fork();
969 fprintf (stderr, z_fork_err, errno, strerror (errno),
972 static int failCt = 0;
973 if ((errno != EAGAIN) || (++failCt > 10))
980 * Close our current stdin and stdout
982 close (STDIN_FILENO);
983 close (STDOUT_FILENO);
987 * Make the fd passed in the stdin, and the write end of
988 * the new pipe become the stdout.
990 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
991 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
992 fdopen (STDIN_FILENO, "r");
993 fdopen (STDOUT_FILENO, "w");
995 apply_fix (p_fixd->patch_args[0], pz_curr_file);
1000 /* * * * * * * * * * * * *
1002 This loop should only cycle for 1/2 of one loop.
1003 "chain_open" starts a process that uses "read_fd" as
1004 its stdin and returns the new fd this process will use
1008 start_fixer (read_fd, p_fixd, pz_fix_file)
1016 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1017 return internal_fix (read_fd, p_fixd);
1019 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1020 pz_cmd = (char*)NULL;
1023 tSCC z_cmd_fmt[] = "file='%s'\n%s";
1024 pz_cmd = (char*)malloc (strlen (p_fixd->patch_args[2])
1025 + sizeof( z_cmd_fmt )
1026 + strlen( pz_fix_file ));
1027 if (pz_cmd == (char*)NULL)
1029 fputs ("allocation failure\n", stderr);
1030 exit (EXIT_FAILURE);
1032 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
1033 pz_cmd_save = p_fixd->patch_args[2];
1034 p_fixd->patch_args[2] = pz_cmd;
1037 /* Start a fix process, handing off the previous read fd for its
1038 stdin and getting a new fd that reads from the fix process' stdout.
1039 We normally will not loop, but we will up to 10 times if we keep
1040 getting "EAGAIN" errors.
1045 static int failCt = 0;
1048 fd = chain_open (read_fd,
1049 (t_pchar *) p_fixd->patch_args,
1050 (process_chain_head == -1)
1051 ? &process_chain_head : (pid_t *) NULL);
1059 fprintf (stderr, z_fork_err, errno, strerror (errno),
1062 if ((errno != EAGAIN) || (++failCt > 10))
1063 exit (EXIT_FAILURE);
1067 /* IF we allocated a shell script command,
1068 THEN free it and restore the command format to the fix description */
1069 if (pz_cmd != (char*)NULL)
1071 free ((void*)pz_cmd);
1072 p_fixd->patch_args[2] = pz_cmd_save;
1079 /* * * * * * * * * * * * *
1081 Process the potential fixes for a particular include file.
1082 Input: the original text of the file and the file's name
1083 Result: none. A new file may or may not be created. */
1086 fix_applies (p_fixd)
1090 static const char z_failed[] = "not applying %s to %s - test %d failed\n";
1095 if (p_fixd->fd_flags & FD_SKIP_TEST)
1098 /* IF there is a file name restriction,
1099 THEN ensure the current file name matches one in the pattern */
1101 if (p_fixd->file_list != (char *) NULL)
1103 const char *pz_fname = pz_curr_file;
1104 const char *pz_scan = p_fixd->file_list;
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) {
1118 if (VLEVEL( VERB_EVERYTHING ))
1119 fprintf (stderr, "file %s not in list for %s\n",
1120 pz_fname, p_fixd->fix_name );
1125 /* IF the match is surrounded by the '|' markers,
1126 THEN we found a full match -- time to run the tests */
1128 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1133 /* FOR each test, see if it fails.
1134 IF it does fail, then we go on to the next test */
1136 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1140 switch (p_test->type)
1143 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1145 if (VLEVEL( VERB_EVERYTHING ))
1146 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1147 p_fixd->test_ct - test_ct);
1154 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1156 if (VLEVEL( VERB_EVERYTHING ))
1157 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1158 p_fixd->test_ct - test_ct);
1165 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1167 if (VLEVEL( VERB_EVERYTHING ))
1168 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1169 p_fixd->test_ct - test_ct);
1177 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1180 if (VLEVEL( VERB_EVERYTHING ))
1181 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1182 p_fixd->test_ct - test_ct);
1194 /* * * * * * * * * * * * *
1196 Write out a replacement file */
1199 write_replacement (p_fixd)
1202 const char* pz_text = p_fixd->patch_args[0];
1204 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1208 FILE* out_fp = create_file (pz_curr_file);
1209 fputs (pz_text, out_fp);
1215 /* * * * * * * * * * * * *
1217 We have work to do. Read back in the output
1218 of the filtering chain. Compare each byte as we read it with
1219 the contents of the original file. As soon as we find any
1220 difference, we will create the output file, write out all
1221 the matched text and then copy any remaining data from the
1222 output of the filter chain.
1225 test_for_changes (read_fd)
1228 FILE *in_fp = fdopen (read_fd, "r");
1229 FILE *out_fp = (FILE *) NULL;
1230 char *pz_cmp = pz_curr_data;
1243 /* IF we are emitting the output
1244 THEN emit this character, too.
1246 if (out_fp != (FILE *) NULL)
1249 /* ELSE if this character does not match the original,
1250 THEN now is the time to start the output.
1252 else if (ch != *pz_cmp)
1254 out_fp = create_file (pz_curr_file);
1259 /* IF there are matched data, write the matched part now. */
1260 if (pz_cmp != pz_curr_data)
1261 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1263 /* Emit the current unmatching character */
1267 /* ELSE the character matches. Advance the compare ptr */
1271 /* IF we created the output file, ... */
1272 if (out_fp != (FILE *) NULL)
1276 /* Close the file and see if we have to worry about
1277 `#include "file.h"' constructs. */
1279 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1280 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1284 close (read_fd); /* probably redundant, but I'm paranoid */
1288 /* * * * * * * * * * * * *
1290 Process the potential fixes for a particular include file.
1291 Input: the original text of the file and the file's name
1292 Result: none. A new file may or may not be created. */
1297 static char env_current_file[1024];
1298 tFixDesc *p_fixd = fixDescList;
1299 int todo_ct = FIX_COUNT;
1301 int num_children = 0;
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, strerror (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, "%6d %-50s \r", data_map_size, pz_curr_file );
1322 process_chain_head = NOPROCESS;
1324 /* For every fix in our fix list, ... */
1325 for (; todo_ct > 0; p_fixd++, todo_ct--)
1327 if (! fix_applies (p_fixd))
1330 if (VLEVEL( VERB_APPLIES ))
1331 fprintf (stderr, "Applying %-24s to %s\n",
1332 p_fixd->fix_name, pz_curr_file);
1334 if (p_fixd->fd_flags & FD_REPLACEMENT)
1336 write_replacement (p_fixd);
1341 /* IF we do not have a read pointer,
1342 THEN this is the first fix for the current file.
1343 Open the source file. That will be used as stdin for
1344 the first fix. Any subsequent fixes will use the
1345 stdout descriptor of the previous fix for its stdin. */
1349 read_fd = open (pz_curr_file, O_RDONLY);
1352 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1353 strerror (errno), pz_curr_file);
1354 exit (EXIT_FAILURE);
1357 /* Ensure we do not get duplicate output */
1362 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1366 /* IF we have a read-back file descriptor,
1367 THEN check for changes and write output if changed. */
1371 test_for_changes (read_fd);
1373 apply_ct += num_children;
1375 /* Wait for child processes created by chain_open()
1376 to avoid leaving zombies. */
1378 wait ((int *) NULL);
1379 } while (--num_children > 0);