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, 1998, 1999 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 static const char gnu_lib_mark[] =
42 "This file is part of the GNU C Library";
44 /* The contents of this string are not very important. It is mostly
45 just used as part of the "I am alive and working" test. */
47 static const char program_id[] = "fixincl version 1.1";
51 Each fix may have associated tests that determine
52 whether the fix needs to be applied or not.
53 Each test has a type (from the te_test_type enumeration);
54 associated test text; and, if the test is TT_EGREP or
55 the negated form TT_NEGREP, a pointer to the compiled
56 version of the text string.
61 TT_TEST, TT_EGREP, TT_NEGREP, TT_FUNCTION
64 typedef struct test_desc tTestDesc;
69 const char *pz_test_text;
70 regex_t *p_test_regex;
73 typedef struct patch_desc tPatchDesc;
77 Everything you ever wanted to know about how to apply
78 a particular fix (which files, how to qualify them,
79 how to actually make the fix, etc...)
81 NB: the FD_ defines are BIT FLAGS
84 #define FD_MACH_ONLY 0x0000
85 #define FD_MACH_IFNOT 0x0001
86 #define FD_SHELL_SCRIPT 0x0002
87 #define FD_SUBROUTINE 0x0004
88 #define FD_REPLACEMENT 0x0008
89 #define FD_SKIP_TEST 0x8000
91 typedef struct fix_desc tFixDesc;
94 const char* fix_name; /* Name of the fix */
95 const char* file_list; /* List of files it applies to */
96 const char** papz_machs; /* List of machine/os-es it applies to */
100 tTestDesc* p_test_desc;
101 const char** patch_args;
104 /* Working environment strings. Essentially, invocation 'options'. */
105 char *pz_dest_dir = NULL;
106 char *pz_src_dir = NULL;
107 char *pz_machine = NULL;
108 int find_base_len = 0;
119 te_verbose verbose_level = VERB_PROGRESS;
121 #define VLEVEL(l) (verbose_level >= l)
122 #define NOT_SILENT VLEVEL(VERB_FIXES)
124 pid_t process_chain_head = (pid_t) -1;
126 char* pz_curr_file; /* name of the current file under test/fix */
127 char* pz_curr_data; /* original contents of that file */
128 t_bool curr_data_mapped;
130 size_t data_map_size;
131 size_t ttl_data_size = 0;
137 #endif /* DO_STATS */
140 #define UNLOAD_DATA() do { if (curr_data_mapped) { \
141 munmap ((void*)pz_curr_data, data_map_size); close (data_map_fd); } \
142 else free ((void*)pz_curr_data); } while(0)
144 #define UNLOAD_DATA() free ((void*)pz_curr_data)
147 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
148 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
149 regex_t incl_quote_re;
152 char *load_file _P_((const char *));
153 void process _P_((char *, const char *));
154 void run_compiles ();
158 /* External Source Code */
161 #include "fixtests.c"
162 #include "fixfixes.c"
164 /* * * * * * * * * * * * * * * * * * *
181 if (strcmp (argv[1], "-v") == 0)
183 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
185 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
186 errno, strerror (errno), argv[1] );
192 fputs ("fixincl ERROR: too many command line arguments\n", 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 ))
437 fprintf (stderr, "child process %d is hung on signal %d\n",
438 child, WSTOPSIG( status ));
441 if (WEXITSTATUS( status ) != 0)
444 fprintf (stderr, "child process %d exited with status %d\n",
445 child, WEXITSTATUS( status ));
448 break; /* normal child completion */
452 IF there is an error, THEN see if it is retryable.
453 If it is not retryable, then break out of this loop. */
454 if (dead_kid == NOPROCESS)
463 fprintf (stderr, "Error %d (%s) waiting for %d to finish\n",
464 errno, strerror( errno ), child );
467 case ECHILD: /* no children to wait for?? */
473 #endif /* NO_BOGOSITY */
475 /* * * * * * * * * * * * *
477 load_file loads all the contents of a file into malloc-ed memory.
478 Its argument is the name of the file to read in; the returned
479 result is the NUL terminated contents of the file. The file
480 is presumed to be an ASCII text file containing no NULs. */
488 if (stat (fname, &stbf) != 0)
491 fprintf (stderr, "error %d (%s) stat-ing %s\n",
492 errno, strerror (errno), fname );
493 return (char *) NULL;
495 if (stbf.st_size == 0)
498 data_map_size = stbf.st_size+1;
499 data_map_fd = open (fname, O_RDONLY);
500 ttl_data_size += data_map_size-1;
505 fprintf (stderr, "error %d (%s) opening %s for read\n",
506 errno, strerror (errno), fname);
511 curr_data_mapped = BOOL_TRUE;
512 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE,
514 if (res == (char*)BAD_ADDR)
516 curr_data_mapped = BOOL_FALSE;
517 res = load_file_data ( fdopen (data_map_fd, "r"));
520 curr_data_mapped = BOOL_FALSE;
521 res = load_file_data ( fdopen (data_map_fd, "r"));
528 /* * * * * * * * * * * * *
530 run_compiles run all the regexp compiles for all the fixes once.
535 tSCC z_bad_comp[] = "fixincl ERROR: cannot compile %s regex for %s\n\
536 \texpr = `%s'\n\terror %s\n";
537 tFixDesc *p_fixd = fixDescList;
538 int fix_ct = FIX_COUNT;
541 int re_ct = REGEX_COUNT;
543 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
545 if (p_re == (regex_t *) NULL)
547 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
548 REGEX_COUNT * sizeof (regex_t));
552 /* Make sure re_compile_pattern does not stumble across invalid
555 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
556 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
558 /* The patterns we search for are all egrep patterns.
559 In the shell version of this program, we invoke egrep
560 with the supplied pattern. Here, we will run
561 re_compile_pattern, but it must be using the same rules. */
563 re_set_syntax (RE_SYNTAX_EGREP);
564 pz_err = re_compile_pattern (incl_quote_pat, sizeof (incl_quote_pat)-1,
566 if (pz_err != (char *) NULL)
568 fprintf (stderr, z_bad_comp, "quoted include", "run_compiles",
569 incl_quote_pat, pz_err);
573 /* FOR every fixup, ... */
576 p_test = p_fixd->p_test_desc;
577 test_ct = p_fixd->test_ct;
579 /* IF the machine type pointer is not NULL (we are not in test mode)
580 AND this test is for or not done on particular machines
583 if ( (pz_machine != NULL)
584 && (p_fixd->papz_machs != (const char**) NULL) )
586 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
588 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
589 tSCC skip[] = "skip"; /* 4 bytes */
590 tSCC run[] = "run"; /* 3 bytes */
591 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
593 const char **papz_machs = p_fixd->papz_machs;
598 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
600 /* Start the case statement */
602 sprintf (cmd_buf, case_fmt, pz_machine);
603 pz = cmd_buf + strlen (cmd_buf);
605 /* Determine if a match means to apply the fix or not apply it */
607 if (p_fixd->fd_flags & FD_MACH_IFNOT)
618 /* Emit all the machine names. If there are more than one,
619 then we will insert " | \\\n" between the names */
623 const char* pz_mach = *(papz_machs++);
625 if (pz_mach == (const char*) NULL)
627 sprintf (pz, "%s%s", pz_sep, pz_mach);
632 /* Now emit the match and not-match actions and the esac */
634 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
637 The result will start either with 's' or 'r'. */
641 pz = run_shell (cmd_buf);
646 p_fixd->fd_flags |= FD_SKIP_TEST;
652 /* FOR every test for the fixup, ... */
654 while (--test_ct >= 0)
656 switch (p_test->type)
660 /* You might consider putting the following under #ifdef.
661 The number of re's used is computed by autogen.
662 So, it is static and known at compile time. */
666 fputs ("out of RE's\n", stderr);
670 p_test->p_test_regex = p_re++;
671 pz_err = re_compile_pattern (p_test->pz_test_text,
672 strlen (p_test->pz_test_text),
673 p_test->p_test_regex);
674 if (pz_err != (char *) NULL)
676 fprintf (stderr, z_bad_comp, "select test", p_fixd->fix_name,
677 p_test->pz_test_text, pz_err);
684 while (p_fixd++, --fix_ct > 0);
688 /* * * * * * * * * * * * *
690 create_file Create the output modified file.
691 Input: the name of the file to create
692 Returns: a file pointer to the new, open file */
694 #if defined(S_IRUSR) && defined(S_IWUSR) && \
695 defined(S_IRGRP) && defined(S_IROTH)
697 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
699 # define S_IRALL 0644
702 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
703 defined(S_IROTH) && defined(S_IXOTH)
705 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
707 # define S_DIRALL 0755
716 char fname[MAXPATHLEN];
718 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
720 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
722 /* We may need to create the directories needed... */
723 if ((fd < 0) && (errno == ENOENT))
725 char *pz_dir = strchr (fname + 1, '/');
728 while (pz_dir != (char *) NULL)
731 if (stat (fname, &stbf) < 0)
733 mkdir (fname, S_IFDIR | S_DIRALL);
737 pz_dir = strchr (pz_dir + 1, '/');
740 /* Now, lets try the open again... */
741 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
745 fprintf (stderr, "Error %d (%s) creating %s\n",
746 errno, strerror (errno), fname);
750 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
751 pf = fdopen (fd, "w");
755 static const char hdr[] =
756 "/* DO NOT EDIT THIS FILE.\n\n"
757 " It has been auto-edited by fixincludes from /usr/include/%s\n"
758 " This had to be done to correct non-standard usages in the\n"
759 " original, manufacturer supplied header file. */\n\n";
761 fprintf (pf, hdr, pz_curr_file);
768 /* * * * * * * * * * * * *
770 test_test make sure a shell-style test expression passes.
771 Input: a pointer to the descriptor of the test to run and
772 the name of the file that we might want to fix
773 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
774 shell script we run. */
777 test_test (p_test, pz_test_file)
783 if ( test %s ) > /dev/null 2>&1\n\
791 static char cmd_buf[4096];
793 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
794 pz_res = run_shell (cmd_buf);
797 free ((void *) pz_res);
802 /* * * * * * * * * * * * *
804 egrep_test make sure an egrep expression is found in the file text.
805 Input: a pointer to the descriptor of the test to run and
806 the pointer to the contents of the file under suspicion
807 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
809 The caller may choose to reverse meaning if the sense of the test
813 egrep_test (pz_data, p_test)
820 if (p_test->p_test_regex == 0)
821 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
822 p_test->pz_test_text);
824 if (regexec (p_test->p_test_regex, pz_data, 1, &match, 0) == 0)
830 /* * * * * * * * * * * * *
832 quoted_file_exists Make sure that a file exists before we emit
833 the file name. If we emit the name, our invoking shell will try
834 to copy a non-existing file into the destination directory. */
837 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
842 char z[ MAXPATHLEN ];
844 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
845 pz = z + strlen ( z );
848 char ch = *pz_file++;
858 if (stat (z, &s) != 0)
860 return S_ISREG( s.st_mode );
865 /* * * * * * * * * * * * *
869 The syntax, `#include "file.h"' specifies that the compiler is to
870 search the local directory of the current file before the include
871 list. Consequently, if we have modified a header and stored it in
872 another directory, any files that are included by that modified
873 file in that fashion must also be copied into this new directory.
874 This routine finds those flavors of #include and for each one found
877 1. source directory of the original file
878 2. the relative path file name of the #includ-ed file
879 3. the full destination path for this file
881 Input: the text of the file, the file name and a pointer to the
882 match list where the match information was stored.
883 Result: internally nothing. The results are written to stdout
884 for interpretation by the invoking shell */
888 extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
890 const char *pz_fixed_file;
891 regmatch_t *p_re_match;
893 char *pz_dir_end = strrchr (pz_fixed_file, '/');
894 char *pz_incl_quot = pz_data;
896 if (VLEVEL( VERB_APPLIES ))
897 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
899 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
900 If there is none, then it is in our current directory, ".". */
902 if (pz_dir_end == (char *) NULL)
909 pz_incl_quot += p_re_match->rm_so;
911 /* Skip forward to the included file name */
912 while (ISSPACE (*pz_incl_quot))
914 /* ISSPACE() may evaluate is argument more than once! */
915 while (++pz_incl_quot, ISSPACE (*pz_incl_quot))
917 pz_incl_quot += sizeof ("include") - 1;
918 while (*pz_incl_quot++ != '"')
921 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
923 /* Print the source directory and the subdirectory
924 of the file in question. */
925 printf ("%s %s/", pz_src_dir, pz_fixed_file);
926 pz_dir_end = pz_incl_quot;
928 /* Append to the directory the relative path of the desired file */
929 while (*pz_incl_quot != '"')
930 putc (*pz_incl_quot++, stdout);
932 /* Now print the destination directory appended with the
933 relative path of the desired file */
934 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
935 while (*pz_dir_end != '"')
936 putc (*pz_dir_end++, stdout);
942 /* Find the next entry */
943 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
949 /* * * * * * * * * * * * *
951 Somebody wrote a *_fix subroutine that we must call.
955 internal_fix (read_fd, p_fixd)
963 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
969 pid_t childid = fork();
992 fprintf (stderr, z_fork_err, errno, strerror (errno),
995 static int failCt = 0;
996 if ((errno != EAGAIN) || (++failCt > 10))
1003 * Close our current stdin and stdout
1005 close (STDIN_FILENO);
1006 close (STDOUT_FILENO);
1010 * Make the fd passed in the stdin, and the write end of
1011 * the new pipe become the stdout.
1013 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
1014 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
1015 fdopen (STDIN_FILENO, "r");
1016 fdopen (STDOUT_FILENO, "w");
1018 apply_fix (p_fixd->patch_args[0], pz_curr_file);
1023 /* * * * * * * * * * * * *
1025 This loop should only cycle for 1/2 of one loop.
1026 "chain_open" starts a process that uses "read_fd" as
1027 its stdin and returns the new fd this process will use
1031 start_fixer (read_fd, p_fixd, pz_fix_file)
1039 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1040 return internal_fix (read_fd, p_fixd);
1042 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1043 pz_cmd = (char*)NULL;
1046 tSCC z_cmd_fmt[] = "file='%s'\n%s";
1047 pz_cmd = (char*)malloc (strlen (p_fixd->patch_args[2])
1048 + sizeof( z_cmd_fmt )
1049 + strlen( pz_fix_file ));
1050 if (pz_cmd == (char*)NULL)
1052 fputs ("allocation failure\n", stderr);
1053 exit (EXIT_FAILURE);
1055 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
1056 pz_cmd_save = p_fixd->patch_args[2];
1057 p_fixd->patch_args[2] = pz_cmd;
1060 /* Start a fix process, handing off the previous read fd for its
1061 stdin and getting a new fd that reads from the fix process' stdout.
1062 We normally will not loop, but we will up to 10 times if we keep
1063 getting "EAGAIN" errors.
1068 static int failCt = 0;
1071 fd = chain_open (read_fd,
1072 (t_pchar *) p_fixd->patch_args,
1073 (process_chain_head == -1)
1074 ? &process_chain_head : (pid_t *) NULL);
1082 fprintf (stderr, z_fork_err, errno, strerror (errno),
1085 if ((errno != EAGAIN) || (++failCt > 10))
1086 exit (EXIT_FAILURE);
1090 /* IF we allocated a shell script command,
1091 THEN free it and restore the command format to the fix description */
1092 if (pz_cmd != (char*)NULL)
1094 free ((void*)pz_cmd);
1095 p_fixd->patch_args[2] = pz_cmd_save;
1102 /* * * * * * * * * * * * *
1104 Process the potential fixes for a particular include file.
1105 Input: the original text of the file and the file's name
1106 Result: none. A new file may or may not be created. */
1109 fix_applies (p_fixd)
1113 static const char z_failed[] = "not applying %s to %s - test %d failed\n";
1118 if (p_fixd->fd_flags & FD_SKIP_TEST)
1121 /* IF there is a file name restriction,
1122 THEN ensure the current file name matches one in the pattern */
1124 if (p_fixd->file_list != (char *) NULL)
1126 const char *pz_fname = pz_curr_file;
1127 const char *pz_scan = p_fixd->file_list;
1130 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1132 name_len = strlen (pz_fname);
1136 pz_scan = strstr (pz_scan + 1, pz_fname);
1137 /* IF we can't match the string at all,
1139 if (pz_scan == (char *) NULL) {
1141 if (VLEVEL( VERB_EVERYTHING ))
1142 fprintf (stderr, "file %s not in list for %s\n",
1143 pz_fname, p_fixd->fix_name );
1148 /* IF the match is surrounded by the '|' markers,
1149 THEN we found a full match -- time to run the tests */
1151 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1156 /* FOR each test, see if it fails.
1157 IF it does fail, then we go on to the next test */
1159 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1163 switch (p_test->type)
1166 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1168 if (VLEVEL( VERB_EVERYTHING ))
1169 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1170 p_fixd->test_ct - test_ct);
1177 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1179 if (VLEVEL( VERB_EVERYTHING ))
1180 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1181 p_fixd->test_ct - test_ct);
1188 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1190 if (VLEVEL( VERB_EVERYTHING ))
1191 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1192 p_fixd->test_ct - test_ct);
1200 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1203 if (VLEVEL( VERB_EVERYTHING ))
1204 fprintf (stderr, z_failed, p_fixd->fix_name, pz_fname,
1205 p_fixd->test_ct - test_ct);
1217 /* * * * * * * * * * * * *
1219 Write out a replacement file */
1222 write_replacement (p_fixd)
1225 const char* pz_text = p_fixd->patch_args[0];
1227 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1231 FILE* out_fp = create_file (pz_curr_file);
1232 fputs (pz_text, out_fp);
1238 /* * * * * * * * * * * * *
1240 We have work to do. Read back in the output
1241 of the filtering chain. Compare each byte as we read it with
1242 the contents of the original file. As soon as we find any
1243 difference, we will create the output file, write out all
1244 the matched text and then copy any remaining data from the
1245 output of the filter chain.
1248 test_for_changes (read_fd)
1251 FILE *in_fp = fdopen (read_fd, "r");
1252 FILE *out_fp = (FILE *) NULL;
1253 char *pz_cmp = pz_curr_data;
1266 /* IF we are emitting the output
1267 THEN emit this character, too.
1269 if (out_fp != (FILE *) NULL)
1272 /* ELSE if this character does not match the original,
1273 THEN now is the time to start the output.
1275 else if (ch != *pz_cmp)
1277 out_fp = create_file (pz_curr_file);
1282 /* IF there are matched data, write the matched part now. */
1283 if (pz_cmp != pz_curr_data)
1284 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1286 /* Emit the current unmatching character */
1290 /* ELSE the character matches. Advance the compare ptr */
1294 /* IF we created the output file, ... */
1295 if (out_fp != (FILE *) NULL)
1299 /* Close the file and see if we have to worry about
1300 `#include "file.h"' constructs. */
1302 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1303 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1307 close (read_fd); /* probably redundant, but I'm paranoid */
1311 /* * * * * * * * * * * * *
1313 Process the potential fixes for a particular include file.
1314 Input: the original text of the file and the file's name
1315 Result: none. A new file may or may not be created. */
1320 static char env_current_file[1024];
1321 tFixDesc *p_fixd = fixDescList;
1322 int todo_ct = FIX_COUNT;
1324 int num_children = 0;
1326 if (access (pz_curr_file, R_OK) != 0)
1329 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1330 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1331 erno, strerror (erno));
1335 pz_curr_data = load_file (pz_curr_file);
1336 if (pz_curr_data == (char *) NULL)
1342 if (VLEVEL( VERB_PROGRESS ))
1343 fprintf (stderr, "%6d %-50s \r", data_map_size, pz_curr_file );
1344 if (strstr (pz_curr_data, gnu_lib_mark) != (char *) NULL)
1350 process_chain_head = NOPROCESS;
1352 /* For every fix in our fix list, ... */
1353 for (; todo_ct > 0; p_fixd++, todo_ct--)
1355 if (! fix_applies (p_fixd))
1358 if (VLEVEL( VERB_APPLIES ))
1359 fprintf (stderr, "Applying %-24s to %s\n",
1360 p_fixd->fix_name, pz_curr_file);
1362 if (p_fixd->fd_flags & FD_REPLACEMENT)
1364 write_replacement (p_fixd);
1369 /* IF we do not have a read pointer,
1370 THEN this is the first fix for the current file.
1371 Open the source file. That will be used as stdin for
1372 the first fix. Any subsequent fixes will use the
1373 stdout descriptor of the previous fix for its stdin. */
1377 read_fd = open (pz_curr_file, O_RDONLY);
1380 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1381 strerror (errno), pz_curr_file);
1382 exit (EXIT_FAILURE);
1385 /* Ensure we do not get duplicate output */
1390 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1394 /* IF we have a read-back file descriptor,
1395 THEN check for changes and write output if changed. */
1399 test_for_changes (read_fd);
1401 apply_ct += num_children;
1403 /* Wait for child processes created by chain_open()
1404 to avoid leaving zombies. */
1406 wait ((int *) NULL);
1407 } while (--num_children > 0);