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, 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)
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 /* Working environment strings. Essentially, invocation 'options'. */
53 #define _ENV_(v,m,n,t) tCC* v = NULL;
57 int find_base_len = 0;
68 te_verbose verbose_level = VERB_PROGRESS;
71 #define VLEVEL(l) (verbose_level >= l)
72 #define NOT_SILENT VLEVEL(VERB_FIXES)
74 pid_t process_chain_head = (pid_t) -1;
76 char* pz_curr_file; /* name of the current file under test/fix */
77 char* pz_curr_data; /* original contents of that file */
78 char* pz_temp_file; /* for DOS, a place to stash the temporary
79 fixed data between system(3) calls */
80 t_bool curr_data_mapped;
83 size_t ttl_data_size = 0;
92 const char incl_quote_pat[] = "^[ \t]*#[ \t]*include[ \t]*\"[^/]";
93 tSCC z_fork_err[] = "Error %d (%s) starting filter process for %s\n";
94 regex_t incl_quote_re;
97 char *load_file _P_((const char *));
98 void process _P_((char *, const char *));
100 void initialize _P_((int argc,char** argv));
103 /* External Source Code */
107 /* * * * * * * * * * * * * * * * * * *
118 initialize ( argc, argv );
120 have_tty = isatty (fileno (stderr));
122 /* Before anything else, ensure we can allocate our file name buffer. */
123 file_name_buf = load_file_data (stdin);
125 /* Because of the way server shells work, you have to keep stdin, out
126 and err open so that the proper input file does not get closed
129 freopen ("/dev/null", "r", stdin);
131 if (file_name_buf == (char *) NULL)
133 fputs ("No file names listed for fixing\n", stderr);
141 /* skip to start of name, past any "./" prefixes */
143 while (ISSPACE (*file_name_buf)) file_name_buf++;
144 while ((file_name_buf[0] == '.') && (file_name_buf[1] == '/'))
147 /* Check for end of list */
149 if (*file_name_buf == NUL)
152 /* Set global file name pointer and find end of name */
154 pz_curr_file = file_name_buf;
155 pz_end = strchr( pz_curr_file, '\n' );
156 if (pz_end == (char*)NULL)
157 pz_end = file_name_buf = pz_curr_file + strlen (pz_curr_file);
159 file_name_buf = pz_end + 1;
161 while ((pz_end > pz_curr_file) && ISSPACE( pz_end[-1])) pz_end--;
163 /* IF no name is found (blank line) or comment marker, skip line */
165 if ((pz_curr_file == pz_end) || (*pz_curr_file == '#'))
173 if (VLEVEL( VERB_PROGRESS )) {
176 Processed %5d files containing %d bytes \n\
177 Applying %5d fixes to %d files\n\
178 Altering %5d of them\n";
180 fprintf (stderr, zFmt, process_ct, ttl_data_size, apply_ct,
181 fixed_ct, altered_ct);
183 #endif /* DO_STATS */
186 unlink( pz_temp_file );
195 static const char zFmt[] = "echo '%s'";
198 /* The 'version' option is really used to test that:
199 1. The program loads correctly (no missing libraries)
200 2. that we can compile all the regular expressions.
201 3. we can correctly run our server shell process
204 sprintf (zBuf, zFmt, program_id);
207 exit (strcmp (run_shell (zBuf), program_id));
209 exit (system (zBuf));
213 /* * * * * * * * * * * * */
216 initialize ( argc, argv )
220 static const char var_not_found[] =
221 "fixincl ERROR: %s environment variable not defined\n"
223 "each of these must be defined:\n"
224 #define _ENV_(v,m,n,t) "\t" n " - " t "\n"
230 xmalloc_set_program_name (argv[0]);
238 if (strcmp (argv[1], "-v") == 0)
240 if (freopen (argv[1], "r", stdin) == (FILE*)NULL)
242 fprintf (stderr, "Error %d (%s) reopening %s as stdin\n",
243 errno, xstrerror (errno), argv[1] );
249 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
253 #define _ENV_(v,m,n,t) { tSCC var[] = n; \
254 v = getenv (var); if (m && (v == NULL)) { \
255 fprintf (stderr, var_not_found, var); \
256 exit (EXIT_FAILURE); } }
262 if (isdigit( *pz_verbose ))
263 verbose_level = (te_verbose)atoi( pz_verbose );
265 switch (*pz_verbose) {
268 verbose_level = VERB_SILENT; break;
272 verbose_level = VERB_FIXES; break;
276 verbose_level = VERB_APPLIES; break;
280 verbose_level = VERB_PROGRESS; break;
284 verbose_level = VERB_TESTS; break;
288 verbose_level = VERB_EVERYTHING; break;
291 while ((pz_find_base[0] == '.') && (pz_find_base[1] == '/'))
293 if ((pz_find_base[0] != '.') || (pz_find_base[1] != NUL))
294 find_base_len = strlen( pz_find_base );
296 /* Compile all the regular expressions now.
297 That way, it is done only once for the whole run.
302 /* NULL as the first argument to `tempnam' causes it to DTRT
303 wrt the temporary directory where the file will be created. */
304 pz_temp_file = tempnam( NULL, "fxinc" );
307 signal (SIGQUIT, SIG_IGN);
309 signal (SIGIOT, SIG_IGN);
312 signal (SIGPIPE, SIG_IGN);
314 signal (SIGALRM, SIG_IGN);
315 signal (SIGTERM, SIG_IGN);
318 /* * * * * * * * * * * * *
320 load_file loads all the contents of a file into malloc-ed memory.
321 Its argument is the name of the file to read in; the returned
322 result is the NUL terminated contents of the file. The file
323 is presumed to be an ASCII text file containing no NULs. */
331 if (stat (fname, &stbf) != 0)
334 fprintf (stderr, "error %d (%s) stat-ing %s\n",
335 errno, xstrerror (errno), fname );
336 return (char *) NULL;
338 if (stbf.st_size == 0)
341 data_map_size = stbf.st_size+1;
342 data_map_fd = open (fname, O_RDONLY);
343 ttl_data_size += data_map_size-1;
348 fprintf (stderr, "error %d (%s) opening %s for read\n",
349 errno, xstrerror (errno), fname);
353 #ifdef HAVE_MMAP_FILE
354 curr_data_mapped = BOOL_TRUE;
355 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ, MAP_PRIVATE,
357 if (res == (char*)BAD_ADDR)
359 curr_data_mapped = BOOL_FALSE;
360 res = load_file_data ( fdopen (data_map_fd, "r"));
363 curr_data_mapped = BOOL_FALSE;
364 res = load_file_data ( fdopen (data_map_fd, "r"));
371 machine_matches( p_fixd )
375 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
377 " )\n echo %s ;;\n* ) echo %s ;;\nesac";/* 4 bytes */
378 tSCC skip[] = "skip"; /* 4 bytes */
379 tSCC run[] = "run"; /* 3 bytes */
380 /* total bytes to add to machine sum: 49 - see fixincl.tpl */
382 const char **papz_machs = p_fixd->papz_machs;
387 char cmd_buf[ MACH_LIST_SIZE_LIMIT ]; /* size lim from fixincl.tpl */
389 /* Start the case statement */
391 sprintf (cmd_buf, case_fmt, pz_machine);
392 pz = cmd_buf + strlen (cmd_buf);
394 /* Determine if a match means to apply the fix or not apply it */
396 if (p_fixd->fd_flags & FD_MACH_IFNOT)
407 /* Emit all the machine names. If there are more than one,
408 then we will insert " | \\\n" between the names */
412 const char* pz_mach = *(papz_machs++);
414 if (pz_mach == (const char*) NULL)
416 sprintf (pz, "%s%s", pz_sep, pz_mach);
421 /* Now emit the match and not-match actions and the esac */
423 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
426 The result will start either with 's' or 'r'. */
430 pz = run_shell (cmd_buf);
435 p_fixd->fd_flags |= FD_SKIP_TEST;
441 # else /* is __MSDOS__ */
442 const char **papz_machs = p_fixd->papz_machs;
443 int invert = (p_fixd->fd_flags & FD_MACH_IFNOT) != 0;
446 const char* pz_mach = *(papz_machs++);
448 if (pz_mach == (const char*) NULL)
450 if (strstr (pz_mach, "dos") != NULL && !invert)
454 p_fixd->fd_flags |= FD_SKIP_TEST;
459 /* * * * * * * * * * * * *
461 run_compiles run all the regexp compiles for all the fixes once.
466 tFixDesc *p_fixd = fixDescList;
467 int fix_ct = FIX_COUNT;
468 regex_t *p_re = (regex_t *) malloc (REGEX_COUNT * sizeof (regex_t));
470 if (p_re == (regex_t *) NULL)
472 fprintf (stderr, "fixincl ERROR: cannot allocate %d bytes for regex\n",
473 REGEX_COUNT * sizeof (regex_t));
477 /* Make sure compile_re does not stumble across invalid data */
479 memset ( (void*)p_re, '\0', REGEX_COUNT * sizeof (regex_t) );
480 memset ( (void*)&incl_quote_re, '\0', sizeof (regex_t) );
482 compile_re (incl_quote_pat, &incl_quote_re, 1,
483 "quoted include", "run_compiles");
485 /* Allow machine name tests to be ignored (testing, mainly) */
487 if (pz_machine && ((*pz_machine == '\0') || (*pz_machine == '*')))
488 pz_machine = (char*)NULL;
490 /* FOR every fixup, ... */
493 tTestDesc *p_test = p_fixd->p_test_desc;
494 int test_ct = p_fixd->test_ct;
496 /* IF the machine type pointer is not NULL (we are not in test mode)
497 AND this test is for or not done on particular machines
500 if ( (pz_machine != NULL)
501 && (p_fixd->papz_machs != (const char**) NULL)
502 && ! machine_matches (p_fixd) )
505 /* FOR every test for the fixup, ... */
507 while (--test_ct >= 0)
509 switch (p_test->type)
513 p_test->p_test_regex = p_re++;
514 compile_re (p_test->pz_test_text, p_test->p_test_regex, 0,
515 "select test", p_fixd->fix_name);
520 while (p_fixd++, --fix_ct > 0);
524 /* * * * * * * * * * * * *
526 create_file Create the output modified file.
527 Input: the name of the file to create
528 Returns: a file pointer to the new, open file */
530 #if defined(S_IRUSR) && defined(S_IWUSR) && \
531 defined(S_IRGRP) && defined(S_IROTH)
533 # define S_IRALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
535 # define S_IRALL 0644
538 #if defined(S_IRWXU) && defined(S_IRGRP) && defined(S_IXGRP) && \
539 defined(S_IROTH) && defined(S_IXOTH)
541 # define S_DIRALL (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
543 # define S_DIRALL 0755
552 char fname[MAXPATHLEN];
554 sprintf (fname, "%s/%s", pz_dest_dir, pz_curr_file + find_base_len);
556 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
558 /* We may need to create the directories needed... */
559 if ((fd < 0) && (errno == ENOENT))
561 char *pz_dir = strchr (fname + 1, '/');
564 while (pz_dir != (char *) NULL)
567 if (stat (fname, &stbf) < 0)
569 mkdir (fname, S_IFDIR | S_DIRALL);
573 pz_dir = strchr (pz_dir + 1, '/');
576 /* Now, lets try the open again... */
577 fd = open (fname, O_WRONLY | O_CREAT | O_TRUNC, S_IRALL);
581 fprintf (stderr, "Error %d (%s) creating %s\n",
582 errno, xstrerror (errno), fname);
586 fprintf (stderr, "Fixed: %s\n", pz_curr_file);
587 pf = fdopen (fd, "w");
590 * IF pz_machine is NULL, then we are in some sort of test mode.
591 * Do not insert the current directory name. Use a constant string.
593 fprintf (pf, z_std_preamble,
603 /* * * * * * * * * * * * *
605 test_test make sure a shell-style test expression passes.
606 Input: a pointer to the descriptor of the test to run and
607 the name of the file that we might want to fix
608 Result: APPLY_FIX or SKIP_FIX, depending on the result of the
609 shell script we run. */
612 test_test (p_test, pz_test_file)
618 if ( test %s ) > /dev/null 2>&1\n\
626 static char cmd_buf[4096];
628 sprintf (cmd_buf, cmd_fmt, pz_test_file, p_test->pz_test_text);
629 pz_res = run_shell (cmd_buf);
641 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
645 free ((void *) pz_res);
650 * IF we are in MS-DOS land, then whatever shell-type test is required
651 * will, by definition, fail
653 #define test_test(t,tf) SKIP_FIX
656 /* * * * * * * * * * * * *
658 egrep_test make sure an egrep expression is found in the file text.
659 Input: a pointer to the descriptor of the test to run and
660 the pointer to the contents of the file under suspicion
661 Result: APPLY_FIX if the pattern is found, SKIP_FIX otherwise
663 The caller may choose to reverse meaning if the sense of the test
667 egrep_test (pz_data, p_test)
672 if (p_test->p_test_regex == 0)
673 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
674 p_test->pz_test_text);
676 if (regexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
682 /* * * * * * * * * * * * *
684 quoted_file_exists Make sure that a file exists before we emit
685 the file name. If we emit the name, our invoking shell will try
686 to copy a non-existing file into the destination directory. */
689 quoted_file_exists (pz_src_path, pz_file_path, pz_file)
694 char z[ MAXPATHLEN ];
696 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
697 pz = z + strlen ( z );
700 char ch = *pz_file++;
710 if (stat (z, &s) != 0)
712 return S_ISREG( s.st_mode );
717 /* * * * * * * * * * * * *
721 The syntax, `#include "file.h"' specifies that the compiler is to
722 search the local directory of the current file before the include
723 list. Consequently, if we have modified a header and stored it in
724 another directory, any files that are included by that modified
725 file in that fashion must also be copied into this new directory.
726 This routine finds those flavors of #include and for each one found
729 1. source directory of the original file
730 2. the relative path file name of the #includ-ed file
731 3. the full destination path for this file
733 Input: the text of the file, the file name and a pointer to the
734 match list where the match information was stored.
735 Result: internally nothing. The results are written to stdout
736 for interpretation by the invoking shell */
740 extract_quoted_files (pz_data, pz_fixed_file, p_re_match)
742 const char *pz_fixed_file;
743 regmatch_t *p_re_match;
745 char *pz_dir_end = strrchr (pz_fixed_file, '/');
746 char *pz_incl_quot = pz_data;
748 if (VLEVEL( VERB_APPLIES ))
749 fprintf (stderr, "Quoted includes in %s\n", pz_fixed_file);
751 /* Set "pz_fixed_file" to point to the containing subdirectory of the source
752 If there is none, then it is in our current directory, ".". */
754 if (pz_dir_end == (char *) NULL)
761 pz_incl_quot += p_re_match->rm_so;
763 /* Skip forward to the included file name */
764 while (ISSPACE (*pz_incl_quot))
766 /* ISSPACE() may evaluate its argument more than once! */
767 while (++pz_incl_quot, ISSPACE (*pz_incl_quot))
769 pz_incl_quot += sizeof ("include") - 1;
770 while (*pz_incl_quot++ != '"')
773 if (quoted_file_exists (pz_src_dir, pz_fixed_file, pz_incl_quot))
775 /* Print the source directory and the subdirectory
776 of the file in question. */
777 printf ("%s %s/", pz_src_dir, pz_fixed_file);
778 pz_dir_end = pz_incl_quot;
780 /* Append to the directory the relative path of the desired file */
781 while (*pz_incl_quot != '"')
782 putc (*pz_incl_quot++, stdout);
784 /* Now print the destination directory appended with the
785 relative path of the desired file */
786 printf (" %s/%s/", pz_dest_dir, pz_fixed_file);
787 while (*pz_dir_end != '"')
788 putc (*pz_dir_end++, stdout);
794 /* Find the next entry */
795 if (regexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
801 /* * * * * * * * * * * * *
803 Somebody wrote a *_fix subroutine that we must call.
807 internal_fix (read_fd, p_fixd)
815 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
821 pid_t childid = fork();
844 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
847 static int failCt = 0;
848 if ((errno != EAGAIN) || (++failCt > 10))
855 * Close our current stdin and stdout
857 close (STDIN_FILENO);
858 close (STDOUT_FILENO);
862 * Make the fd passed in the stdin, and the write end of
863 * the new pipe become the stdout.
865 fcntl (fd[1], F_DUPFD, STDOUT_FILENO);
866 fcntl (read_fd, F_DUPFD, STDIN_FILENO);
868 apply_fix (p_fixd, pz_curr_file);
871 #endif /* !__MSDOS__ */
876 fix_with_system (p_fixd, pz_fix_file, pz_file_source, pz_temp_file)
886 if (p_fixd->fd_flags & FD_SUBROUTINE)
888 tSCC z_applyfix_prog[] = "/fixinc/applyfix";
891 + strlen( pz_orig_dir )
892 + sizeof( z_applyfix_prog )
893 + strlen( pz_fix_file )
894 + strlen( pz_file_source )
895 + strlen( pz_temp_file );
897 pz_cmd = (char*)xmalloc( argsize );
899 strcpy( pz_cmd, pz_orig_dir );
900 pz_scan = pz_cmd + strlen( pz_orig_dir );
901 strcpy( pz_scan, z_applyfix_prog );
902 pz_scan += sizeof( z_applyfix_prog ) - 1;
906 * Now add the fix number and file names that may be needed
908 sprintf (pz_scan, "%ld %s %s %s", p_fixd - fixDescList,
909 pz_fix_file, pz_file_source, pz_temp_file);
911 else /* NOT an "internal" fix: */
914 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
915 dst is a temporary file anyway, so we know there's no other
916 file by that name; and DOS's system(3) doesn't mind to
917 clobber existing file in redirection. Besides, with DOS 8+3
918 limited file namespace, we can easily lose if dst already has
919 an extension that is 3 or more characters long.
920 The following bizarre use of 'cat' only works on DOS boxes.
921 It is causing the file to be dropped into a temporary file for
922 'cat' to read (pipes do not work on DOS). */
923 tSCC z_cmd_fmt[] = " %s | cat > %s";
924 tCC** ppArgs = p_fixd->patch_args;
926 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
927 + strlen( pz_file_source );
932 * Compute the size of the command line. Add lotsa extra space
933 * because some of the args to sed use lotsa single quotes.
934 * (This requires three extra bytes per quote. Here we allow
935 * for up to 8 single quotes for each argument, including the
936 * command name "sed" itself. Nobody will *ever* need more. :)
940 tCC* p_arg = *(ppArgs++);
943 argsize += 24 + strlen( p_arg );
946 /* Estimated buffer size we will need. */
947 pz_scan = pz_cmd = (char*)xmalloc( argsize );
948 /* How much of it do we allot to the program name and its
950 parg_size = argsize - parg_size;
952 ppArgs = p_fixd->patch_args;
955 * Copy the program name, unquoted
958 tCC* pArg = *(ppArgs++);
969 * Copy the program arguments, quoted
973 tCC* pArg = *(ppArgs++);
978 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
979 parg_size - (pz_scan - pz_cmd) );
981 * Make sure we don't overflow the buffer due to sloppy
984 while (pz_scan == (char*)NULL)
986 size_t already_filled = pz_scan_save - pz_cmd;
987 pz_cmd = (char*)xrealloc( pz_cmd, argsize += 100 );
988 pz_scan_save = pz_scan = pz_cmd + already_filled;
990 pz_scan = make_raw_shell_str( pz_scan, pArg,
991 parg_size - (pz_scan - pz_cmd) );
996 * add the file machinations.
998 sprintf( pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
1001 free( (void*)pz_cmd );
1004 /* * * * * * * * * * * * *
1006 This loop should only cycle for 1/2 of one loop.
1007 "chain_open" starts a process that uses "read_fd" as
1008 its stdin and returns the new fd this process will use
1011 #else /* is *NOT* __MSDOS__ */
1013 start_fixer (read_fd, p_fixd, pz_fix_file)
1021 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1022 return internal_fix (read_fd, p_fixd);
1024 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1025 pz_cmd = (char*)NULL;
1028 tSCC z_cmd_fmt[] = "file='%s'\n%s";
1029 pz_cmd = (char*)malloc (strlen (p_fixd->patch_args[2])
1030 + sizeof( z_cmd_fmt )
1031 + strlen( pz_fix_file ));
1032 if (pz_cmd == (char*)NULL)
1034 fputs ("allocation failure\n", stderr);
1035 exit (EXIT_FAILURE);
1037 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
1038 pz_cmd_save = p_fixd->patch_args[2];
1039 p_fixd->patch_args[2] = pz_cmd;
1042 /* Start a fix process, handing off the previous read fd for its
1043 stdin and getting a new fd that reads from the fix process' stdout.
1044 We normally will not loop, but we will up to 10 times if we keep
1045 getting "EAGAIN" errors.
1050 static int failCt = 0;
1053 fd = chain_open (read_fd,
1054 (t_pchar *) p_fixd->patch_args,
1055 (process_chain_head == -1)
1056 ? &process_chain_head : (pid_t *) NULL);
1064 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
1067 if ((errno != EAGAIN) || (++failCt > 10))
1068 exit (EXIT_FAILURE);
1072 /* IF we allocated a shell script command,
1073 THEN free it and restore the command format to the fix description */
1074 if (pz_cmd != (char*)NULL)
1076 free ((void*)pz_cmd);
1077 p_fixd->patch_args[2] = pz_cmd_save;
1085 /* * * * * * * * * * * * *
1087 Process the potential fixes for a particular include file.
1088 Input: the original text of the file and the file's name
1089 Result: none. A new file may or may not be created. */
1092 fix_applies (p_fixd)
1095 const char *pz_fname = pz_curr_file;
1096 const char *pz_scan = p_fixd->file_list;
1102 * There is only one fix that uses a shell script as of this writing.
1103 * I hope to nuke it anyway, it does not apply to DOS and it would
1104 * be painful to implement. Therefore, no "shell" fixes for DOS.
1106 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
1109 if (p_fixd->fd_flags & FD_SKIP_TEST)
1113 /* IF there is a file name restriction,
1114 THEN ensure the current file name matches one in the pattern */
1116 if (pz_scan != (char *) NULL)
1120 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1122 name_len = strlen (pz_fname);
1126 pz_scan = strstr (pz_scan + 1, pz_fname);
1127 /* IF we can't match the string at all,
1129 if (pz_scan == (char *) NULL)
1132 /* IF the match is surrounded by the '|' markers,
1133 THEN we found a full match -- time to run the tests */
1135 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1140 /* FOR each test, see if it fails.
1141 IF it does fail, then we go on to the next test */
1143 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1147 switch (p_test->type)
1150 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1152 if (VLEVEL( VERB_EVERYTHING ))
1153 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1154 pz_fname, p_fixd->test_ct - test_ct);
1161 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1163 if (VLEVEL( VERB_EVERYTHING ))
1164 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1165 pz_fname, p_fixd->test_ct - test_ct);
1172 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1174 if (VLEVEL( VERB_EVERYTHING ))
1175 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1176 pz_fname, p_fixd->test_ct - test_ct);
1184 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1187 if (VLEVEL( VERB_EVERYTHING ))
1188 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1189 pz_fname, p_fixd->test_ct - test_ct);
1201 /* * * * * * * * * * * * *
1203 Write out a replacement file */
1206 write_replacement (p_fixd)
1209 const char* pz_text = p_fixd->patch_args[0];
1211 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1215 FILE* out_fp = create_file (pz_curr_file);
1216 fputs (pz_text, out_fp);
1222 /* * * * * * * * * * * * *
1224 We have work to do. Read back in the output
1225 of the filtering chain. Compare each byte as we read it with
1226 the contents of the original file. As soon as we find any
1227 difference, we will create the output file, write out all
1228 the matched text and then copy any remaining data from the
1229 output of the filter chain.
1232 test_for_changes (read_fd)
1235 FILE *in_fp = fdopen (read_fd, "r");
1236 FILE *out_fp = (FILE *) NULL;
1237 char *pz_cmp = pz_curr_data;
1250 /* IF we are emitting the output
1251 THEN emit this character, too.
1253 if (out_fp != (FILE *) NULL)
1256 /* ELSE if this character does not match the original,
1257 THEN now is the time to start the output.
1259 else if (ch != *pz_cmp)
1261 out_fp = create_file (pz_curr_file);
1266 /* IF there are matched data, write the matched part now. */
1267 if (pz_cmp != pz_curr_data)
1268 fwrite (pz_curr_data, (size_t)(pz_cmp - pz_curr_data), 1, out_fp);
1270 /* Emit the current unmatching character */
1274 /* ELSE the character matches. Advance the compare ptr */
1278 /* IF we created the output file, ... */
1279 if (out_fp != (FILE *) NULL)
1283 /* Close the file and see if we have to worry about
1284 `#include "file.h"' constructs. */
1286 if (regexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1287 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1291 close (read_fd); /* probably redundant, but I'm paranoid */
1295 /* * * * * * * * * * * * *
1297 Process the potential fixes for a particular include file.
1298 Input: the original text of the file and the file's name
1299 Result: none. A new file may or may not be created. */
1304 tFixDesc *p_fixd = fixDescList;
1305 int todo_ct = FIX_COUNT;
1308 int num_children = 0;
1309 # else /* is __MSDOS__ */
1310 char* pz_file_source = pz_curr_file;
1313 if (access (pz_curr_file, R_OK) != 0)
1316 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1317 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1318 erno, xstrerror (erno));
1322 pz_curr_data = load_file (pz_curr_file);
1323 if (pz_curr_data == (char *) NULL)
1329 if (VLEVEL( VERB_PROGRESS ) && have_tty)
1330 fprintf (stderr, "%6d %-50s \r", data_map_size, pz_curr_file );
1333 process_chain_head = NOPROCESS;
1335 /* For every fix in our fix list, ... */
1336 for (; todo_ct > 0; p_fixd++, todo_ct--)
1338 if (! fix_applies (p_fixd))
1341 if (VLEVEL( VERB_APPLIES ))
1342 fprintf (stderr, "Applying %-24s to %s\n",
1343 p_fixd->fix_name, pz_curr_file);
1345 if (p_fixd->fd_flags & FD_REPLACEMENT)
1347 write_replacement (p_fixd);
1352 /* IF we do not have a read pointer,
1353 THEN this is the first fix for the current file.
1354 Open the source file. That will be used as stdin for
1355 the first fix. Any subsequent fixes will use the
1356 stdout descriptor of the previous fix for its stdin. */
1360 read_fd = open (pz_curr_file, O_RDONLY);
1363 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1364 xstrerror (errno), pz_curr_file);
1365 exit (EXIT_FAILURE);
1368 /* Ensure we do not get duplicate output */
1373 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1377 /* IF we have a read-back file descriptor,
1378 THEN check for changes and write output if changed. */
1382 test_for_changes (read_fd);
1384 apply_ct += num_children;
1386 /* Wait for child processes created by chain_open()
1387 to avoid leaving zombies. */
1389 wait ((int *) NULL);
1390 } while (--num_children > 0);
1393 # else /* is __MSDOS__ */
1395 for (; todo_ct > 0; p_fixd++, todo_ct--)
1397 if (! fix_applies (p_fixd))
1400 if (VLEVEL( VERB_APPLIES ))
1401 fprintf (stderr, "Applying %-24s to %s\n",
1402 p_fixd->fix_name, pz_curr_file);
1404 if (p_fixd->fd_flags & FD_REPLACEMENT)
1406 write_replacement (p_fixd);
1410 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
1411 pz_file_source = pz_temp_file;
1414 read_fd = open( pz_temp_file, O_RDONLY );
1415 test_for_changes( read_fd );
1416 /* Unlinking a file while it is still open is a Bad Idea on
1419 unlink( pz_temp_file );