* gcc.dg/c90-const-expr-3.c: xfail all the ASSERT_NOT_NPC tests.
[official-gcc.git] / fixincludes / fixincl.c
blob243f9bbfd1017be9c021f9c9743d5d2292fddc2a
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)
12 any later version.
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. */
24 #include "fixlib.h"
26 #include <sys/stat.h>
28 #if defined( HAVE_MMAP_FILE )
29 #include <sys/mman.h>
30 #define BAD_ADDR ((void*)-1)
31 #endif
33 #ifndef SEPARATE_FIX_PROC
34 #include "server.h"
35 #endif
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\
47 \t\"%s/%s\"\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;
53 typedef enum {
54 VERB_SILENT = 0,
55 VERB_FIXES,
56 VERB_APPLIES,
57 VERB_PROGRESS,
58 VERB_TESTS,
59 VERB_EVERYTHING
60 } te_verbose;
62 te_verbose verbose_level = VERB_PROGRESS;
63 int have_tty = 0;
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;
75 int data_map_fd;
76 size_t data_map_size;
77 size_t ttl_data_size = 0;
79 #ifdef DO_STATS
80 int process_ct = 0;
81 int apply_ct = 0;
82 int fixed_ct = 0;
83 int altered_ct = 0;
84 #endif /* DO_STATS */
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);
94 void process (void);
96 /* External Source Code */
98 #include "fixincl.x"
100 /* * * * * * * * * * * * * * * * * * *
102 * MAIN ROUTINE
104 extern int main (int, char **);
106 main (int argc, char** argv)
108 char *file_name_buf;
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
119 by accident */
121 freopen ("/dev/null", "r", stdin);
123 if (file_name_buf == (char *) NULL)
125 fputs ("No file names listed for fixing\n", stderr);
126 exit (EXIT_FAILURE);
129 for (;;)
131 char* pz_end;
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] == '/'))
137 file_name_buf += 2;
139 /* Check for end of list */
141 if (*file_name_buf == NUL)
142 break;
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);
150 else
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 == '#'))
158 continue;
159 *pz_end = NUL;
161 process ();
162 } /* for (;;) */
164 #ifdef DO_STATS
165 if (VLEVEL( VERB_PROGRESS )) {
166 tSCC zFmt[] =
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 );
179 # endif
180 exit (EXIT_SUCCESS);
184 static void
185 do_version (void)
187 static const char zFmt[] = "echo '%s'";
188 char zBuf[ 1024 ];
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
195 run_compiles ();
196 sprintf (zBuf, zFmt, program_id);
197 #ifndef SEPARATE_FIX_PROC
198 puts (zBuf + 5);
199 exit (strcmp (run_shell (zBuf), program_id));
200 #else
201 exit (system (zBuf));
202 #endif
205 /* * * * * * * * * * * * */
207 void
208 initialize ( int argc, char** argv )
210 xmalloc_set_program_name (argv[0]);
212 switch (argc)
214 case 1:
215 break;
217 case 2:
218 if (strcmp (argv[1], "-v") == 0)
219 do_version ();
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] );
224 exit (EXIT_FAILURE);
226 break;
228 default:
229 fputs ("fixincl ERROR: too many command line arguments\n", stderr);
230 exit (EXIT_FAILURE);
233 #ifdef SIGCHLD
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);
237 #endif
239 initialize_opts ();
241 if (ISDIGIT ( *pz_verbose ))
242 verbose_level = (te_verbose)atoi( pz_verbose );
243 else
244 switch (*pz_verbose) {
245 case 's':
246 case 'S':
247 verbose_level = VERB_SILENT; break;
249 case 'f':
250 case 'F':
251 verbose_level = VERB_FIXES; break;
253 case 'a':
254 case 'A':
255 verbose_level = VERB_APPLIES; break;
257 default:
258 case 'p':
259 case 'P':
260 verbose_level = VERB_PROGRESS; break;
262 case 't':
263 case 'T':
264 verbose_level = VERB_TESTS; break;
266 case 'e':
267 case 'E':
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] == '/'))
275 pz_find_base += 2;
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.
282 run_compiles ();
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" );
288 # endif
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. */
303 char *
304 load_file ( const char* fname )
306 struct stat stbf;
307 char* res;
309 if (stat (fname, &stbf) != 0)
311 if (NOT_SILENT)
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)
317 return (char*)NULL;
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;
327 if (data_map_fd < 0)
329 if (NOT_SILENT)
330 fprintf (stderr, "error %d (%s) opening %s for read\n",
331 errno, xstrerror (errno), fname);
332 return (char*)NULL;
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;
342 else
343 res = (char*)mmap ((void*)NULL, data_map_size, PROT_READ,
344 MAP_PRIVATE, data_map_fd, 0);
345 if (res == (char*)BAD_ADDR)
346 #endif
348 FILE* fp = fdopen (data_map_fd, "r");
349 curr_data_mapped = BOOL_FALSE;
350 res = load_file_data (fp);
351 fclose (fp);
354 return res;
357 static int
358 machine_matches( tFixDesc* p_fixd )
360 # ifndef SEPARATE_FIX_PROC
361 tSCC case_fmt[] = "case %s in\n"; /* 9 bytes, plus string */
362 tSCC esac_fmt[] =
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;
369 char *pz;
370 const char *pz_sep = "";
371 tCC *pz_if_true;
372 tCC *pz_if_false;
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)
384 pz_if_true = skip;
385 pz_if_false = run;
387 else
389 pz_if_true = run;
390 pz_if_false = skip;
393 /* Emit all the machine names. If there are more than one,
394 then we will insert " | \\\n" between the names */
396 for (;;)
398 const char* pz_mach = *(papz_machs++);
400 if (pz_mach == (const char*) NULL)
401 break;
402 sprintf (pz, "%s%s", pz_sep, pz_mach);
403 pz += strlen (pz);
404 pz_sep = " | \\\n";
407 /* Now emit the match and not-match actions and the esac */
409 sprintf (pz, esac_fmt, pz_if_true, pz_if_false);
411 /* Run the script.
412 The result will start either with 's' or 'r'. */
415 int skip;
416 pz = run_shell (cmd_buf);
417 skip = (*pz == 's');
418 free ( (void*)pz );
419 if (skip)
421 p_fixd->fd_flags |= FD_SKIP_TEST;
422 return BOOL_FALSE;
426 return BOOL_TRUE;
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;
430 for (;;)
432 const char* pz_mach = *(papz_machs++);
434 if (pz_mach == (const char*) NULL)
435 break;
436 if (strstr (pz_mach, "dos") != NULL && !invert)
437 return BOOL_TRUE;
440 p_fixd->fd_flags |= FD_SKIP_TEST;
441 return BOOL_FALSE;
442 # endif
445 /* * * * * * * * * * * * *
447 run_compiles run all the regexp compiles for all the fixes once.
449 void
450 run_compiles (void)
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
476 THEN ... */
478 if ( (pz_machine != NULL)
479 && (p_fixd->papz_machs != (const char**) NULL)
480 && ! machine_matches (p_fixd) )
481 continue;
483 /* FOR every test for the fixup, ... */
485 while (--test_ct >= 0)
487 switch (p_test->type)
489 case TT_EGREP:
490 case TT_NEGREP:
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);
494 default: break;
496 p_test++;
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)
513 #else
514 # define S_IRALL 0644
515 #endif
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)
521 #else
522 # define S_DIRALL 0755
523 #endif
526 static FILE *
527 create_file (void)
529 int fd;
530 FILE *pf;
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, '/');
541 struct stat stbf;
543 while (pz_dir != (char *) NULL)
545 *pz_dir = NUL;
546 if (stat (fname, &stbf) < 0)
548 #ifdef _WIN32
549 mkdir (fname);
550 #else
551 mkdir (fname, S_IFDIR | S_DIRALL);
552 #endif
555 *pz_dir = '/';
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);
562 if (fd < 0)
564 fprintf (stderr, "Error %d (%s) creating %s\n",
565 errno, xstrerror (errno), fname);
566 exit (EXIT_FAILURE);
568 if (NOT_SILENT)
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,
577 (pz_machine == NULL)
578 ? "fixinc/tests/inc"
579 : pz_input_dir,
580 pz_curr_file);
582 return pf;
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
594 static int
595 test_test (tTestDesc* p_test, char* pz_test_file)
597 tSCC cmd_fmt[] =
598 "file=%s\n\
599 if ( test %s ) > /dev/null 2>&1\n\
600 then echo TRUE\n\
601 else echo FALSE\n\
602 fi";
604 char *pz_res;
605 int res;
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);
612 switch (*pz_res) {
613 case 'T':
614 res = APPLY_FIX;
615 break;
617 case 'F':
618 res = SKIP_FIX;
619 break;
621 default:
622 fprintf (stderr, "Script yielded bogus result of `%s':\n%s\n\n",
623 pz_res, cmd_buf );
624 res = SKIP_FIX;
627 free ((void *) pz_res);
628 return res;
630 #else
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
636 #endif
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
646 is inverted. */
648 static int
649 egrep_test (char* pz_data, tTestDesc* p_test)
651 #ifdef DEBUG
652 if (p_test->p_test_regex == 0)
653 fprintf (stderr, "fixincl ERROR RE not compiled: `%s'\n",
654 p_test->pz_test_text);
655 #endif
656 if (xregexec (p_test->p_test_regex, pz_data, 0, 0, 0) == 0)
657 return APPLY_FIX;
658 return SKIP_FIX;
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. */
668 static int
669 quoted_file_exists (const char* pz_src_path,
670 const char* pz_file_path,
671 const char* pz_file)
673 char z[ MAXPATHLEN ];
674 char* pz;
675 sprintf (z, "%s/%s/", pz_src_path, pz_file_path);
676 pz = z + strlen ( z );
678 for (;;) {
679 char ch = *pz_file++;
680 if (! ISGRAPH( ch ))
681 return 0;
682 if (ch == '"')
683 break;
684 *pz++ = ch;
686 *pz = '\0';
688 struct stat s;
689 if (stat (z, &s) != 0)
690 return 0;
691 return S_ISREG( s.st_mode );
696 /* * * * * * * * * * * * *
698 extract_quoted_files
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
706 emits a triple of:
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 */
718 static void
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)
733 pz_fixed_file = ".";
734 else
735 *pz_dir_end = '\0';
737 for (;;)
739 pz_incl_quot += p_re_match->rm_so;
741 /* Skip forward to the included file name */
742 while (*pz_incl_quot != '"')
743 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);
762 /* End of entry */
763 putc ('\n', stdout);
766 /* Find the next entry */
767 if (xregexec (&incl_quote_re, pz_incl_quot, 1, p_re_match, 0) != 0)
768 break;
773 /* * * * * * * * * * * * *
775 Somebody wrote a *_fix subroutine that we must call.
777 #ifndef SEPARATE_FIX_PROC
778 static int
779 internal_fix (int read_fd, tFixDesc* p_fixd)
781 int fd[2];
783 if (pipe( fd ) != 0)
785 fprintf (stderr, "Error %d on pipe(2) call\n", errno );
786 exit (EXIT_FAILURE);
789 for (;;)
791 pid_t childid = fork();
793 switch (childid)
795 case -1:
796 break;
798 case 0:
799 close (fd[0]);
800 goto do_child_task;
802 default:
804 * Parent process
806 close (read_fd);
807 close (fd[1]);
808 return fd[0];
812 * Parent in error
814 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
815 p_fixd->fix_name);
817 static int failCt = 0;
818 if ((errno != EAGAIN) || (++failCt > 10))
819 exit (EXIT_FAILURE);
820 sleep (1);
822 } do_child_task:;
825 * Close our current stdin and stdout
827 close (STDIN_FILENO);
828 close (STDOUT_FILENO);
829 UNLOAD_DATA();
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);
839 exit (0);
841 #endif /* !SEPARATE_FIX_PROC */
844 #ifdef SEPARATE_FIX_PROC
845 static void
846 fix_with_system (tFixDesc* p_fixd,
847 tCC* pz_fix_file,
848 tCC* pz_file_source,
849 tCC* pz_temp_file)
851 char* pz_cmd;
852 char* pz_scan;
853 size_t argsize;
854 int i;
855 tSCC z_applyfix_prog[2] = {
856 "/../fixincludes/applyfix" EXE_EXT,
857 "/../../fixincludes/applyfix" EXE_EXT };
859 if (p_fixd->fd_flags & FD_SUBROUTINE)
860 for (i = 0; i < 2; i++)
862 struct stat buf;
864 argsize = 32
865 + strlen( pz_orig_dir )
866 + sizeof( z_applyfix_prog )
867 + strlen( pz_fix_file )
868 + strlen( pz_file_source )
869 + strlen( pz_temp_file );
871 pz_cmd = xmalloc (argsize);
873 strcpy( pz_cmd, pz_orig_dir );
874 pz_scan = pz_cmd + strlen( pz_orig_dir );
875 strcpy( pz_scan, z_applyfix_prog );
876 pz_scan += sizeof( z_applyfix_prog ) - 1;
878 if (stat (pz_scan, &buf) != -1)
880 *(pz_scan++) = ' ';
882 * Now add the fix number and file names that may be needed
884 sprintf (pz_scan, "%ld \'%s\' \'%s\' \'%s\'", p_fixd - fixDescList,
885 pz_fix_file, pz_file_source, pz_temp_file);
886 break;
889 else /* NOT an "internal" fix: */
891 size_t parg_size;
892 #ifdef __MSDOS__
893 /* Don't use the "src > dstX; rm -f dst; mv -f dstX dst" trick:
894 dst is a temporary file anyway, so we know there's no other
895 file by that name; and DOS's system(3) doesn't mind to
896 clobber existing file in redirection. Besides, with DOS 8+3
897 limited file namespace, we can easily lose if dst already has
898 an extension that is 3 or more characters long.
900 I do not think the 8+3 issue is relevant because all the files
901 we operate on are named "*.h", making 8+2 adequate. Anyway,
902 the following bizarre use of 'cat' only works on DOS boxes.
903 It causes the file to be dropped into a temporary file for
904 'cat' to read (pipes do not work on DOS). */
905 tSCC z_cmd_fmt[] = " \'%s\' | cat > \'%s\'";
906 #else
907 /* Don't use positional formatting arguments because some lame-o
908 implementations cannot cope :-(. */
909 tSCC z_cmd_fmt[] = " %s > %sX ; rm -f %s; mv -f %sX %s";
910 #endif
911 tCC** ppArgs = p_fixd->patch_args;
913 argsize = sizeof( z_cmd_fmt ) + strlen( pz_temp_file )
914 + strlen( pz_file_source );
915 parg_size = argsize;
919 * Compute the size of the command line. Add lotsa extra space
920 * because some of the args to sed use lotsa single quotes.
921 * (This requires three extra bytes per quote. Here we allow
922 * for up to 8 single quotes for each argument, including the
923 * command name "sed" itself. Nobody will *ever* need more. :)
925 for (;;)
927 tCC* p_arg = *(ppArgs++);
928 if (p_arg == NULL)
929 break;
930 argsize += 24 + strlen( p_arg );
933 /* Estimated buffer size we will need. */
934 pz_scan = pz_cmd = xmalloc (argsize);
935 /* How much of it do we allot to the program name and its
936 arguments. */
937 parg_size = argsize - parg_size;
939 ppArgs = p_fixd->patch_args;
942 * Copy the program name, unquoted
945 tCC* pArg = *(ppArgs++);
946 for (;;)
948 char ch = *(pArg++);
949 if (ch == NUL)
950 break;
951 *(pz_scan++) = ch;
956 * Copy the program arguments, quoted
958 for (;;)
960 tCC* pArg = *(ppArgs++);
961 char* pz_scan_save;
962 if (pArg == NULL)
963 break;
964 *(pz_scan++) = ' ';
965 pz_scan = make_raw_shell_str( pz_scan_save = pz_scan, pArg,
966 parg_size - (pz_scan - pz_cmd) );
968 * Make sure we don't overflow the buffer due to sloppy
969 * size estimation.
971 while (pz_scan == (char*)NULL)
973 size_t already_filled = pz_scan_save - pz_cmd;
974 pz_cmd = xrealloc (pz_cmd, argsize += 100);
975 pz_scan_save = pz_scan = pz_cmd + already_filled;
976 parg_size += 100;
977 pz_scan = make_raw_shell_str( pz_scan, pArg,
978 parg_size - (pz_scan - pz_cmd) );
983 * add the file machinations.
985 #ifdef __MSDOS__
986 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file );
987 #else
988 sprintf (pz_scan, z_cmd_fmt, pz_file_source, pz_temp_file,
989 pz_temp_file, pz_temp_file, pz_temp_file);
990 #endif
992 system( pz_cmd );
993 free( (void*)pz_cmd );
996 /* * * * * * * * * * * * *
998 This loop should only cycle for 1/2 of one loop.
999 "chain_open" starts a process that uses "read_fd" as
1000 its stdin and returns the new fd this process will use
1001 for stdout. */
1003 #else /* is *NOT* SEPARATE_FIX_PROC */
1004 static int
1005 start_fixer (int read_fd, tFixDesc* p_fixd, char* pz_fix_file)
1007 tCC* pz_cmd_save;
1008 char* pz_cmd;
1010 if ((p_fixd->fd_flags & FD_SUBROUTINE) != 0)
1011 return internal_fix (read_fd, p_fixd);
1013 if ((p_fixd->fd_flags & FD_SHELL_SCRIPT) == 0)
1015 pz_cmd = NULL;
1016 pz_cmd_save = NULL;
1018 else
1020 tSCC z_cmd_fmt[] = "file='%s'\n%s";
1021 pz_cmd = xmalloc (strlen (p_fixd->patch_args[2])
1022 + sizeof (z_cmd_fmt) + strlen (pz_fix_file));
1023 sprintf (pz_cmd, z_cmd_fmt, pz_fix_file, p_fixd->patch_args[2]);
1024 pz_cmd_save = p_fixd->patch_args[2];
1025 p_fixd->patch_args[2] = pz_cmd;
1028 /* Start a fix process, handing off the previous read fd for its
1029 stdin and getting a new fd that reads from the fix process' stdout.
1030 We normally will not loop, but we will up to 10 times if we keep
1031 getting "EAGAIN" errors.
1034 for (;;)
1036 static int failCt = 0;
1037 int fd;
1039 fd = chain_open (read_fd,
1040 (tCC **) p_fixd->patch_args,
1041 (process_chain_head == -1)
1042 ? &process_chain_head : (pid_t *) NULL);
1044 if (fd != -1)
1046 read_fd = fd;
1047 break;
1050 fprintf (stderr, z_fork_err, errno, xstrerror (errno),
1051 p_fixd->fix_name);
1053 if ((errno != EAGAIN) || (++failCt > 10))
1054 exit (EXIT_FAILURE);
1055 sleep (1);
1058 /* IF we allocated a shell script command,
1059 THEN free it and restore the command format to the fix description */
1060 if (pz_cmd != (char*)NULL)
1062 free ((void*)pz_cmd);
1063 p_fixd->patch_args[2] = pz_cmd_save;
1066 return read_fd;
1068 #endif
1071 /* * * * * * * * * * * * *
1073 Process the potential fixes for a particular include file.
1074 Input: the original text of the file and the file's name
1075 Result: none. A new file may or may not be created. */
1077 static t_bool
1078 fix_applies (tFixDesc* p_fixd)
1080 const char *pz_fname = pz_curr_file;
1081 const char *pz_scan = p_fixd->file_list;
1082 int test_ct;
1083 tTestDesc *p_test;
1085 # ifdef SEPARATE_FIX_PROC
1087 * There is only one fix that uses a shell script as of this writing.
1088 * I hope to nuke it anyway, it does not apply to DOS and it would
1089 * be painful to implement. Therefore, no "shell" fixes for DOS.
1091 if (p_fixd->fd_flags & (FD_SHELL_SCRIPT | FD_SKIP_TEST))
1092 return BOOL_FALSE;
1093 # else
1094 if (p_fixd->fd_flags & FD_SKIP_TEST)
1095 return BOOL_FALSE;
1096 # endif
1098 /* IF there is a file name restriction,
1099 THEN ensure the current file name matches one in the pattern */
1101 if (pz_scan != (char *) NULL)
1103 size_t name_len;
1105 while ((pz_fname[0] == '.') && (pz_fname[1] == '/'))
1106 pz_fname += 2;
1107 name_len = strlen (pz_fname);
1109 for (;;)
1111 pz_scan = strstr (pz_scan + 1, pz_fname);
1112 /* IF we can't match the string at all,
1113 THEN bail */
1114 if (pz_scan == (char *) NULL)
1115 return BOOL_FALSE;
1117 /* IF the match is surrounded by the '|' markers,
1118 THEN we found a full match -- time to run the tests */
1120 if ((pz_scan[-1] == '|') && (pz_scan[name_len] == '|'))
1121 break;
1125 /* FOR each test, see if it fails.
1126 IF it does fail, then we go on to the next test */
1128 for (p_test = p_fixd->p_test_desc, test_ct = p_fixd->test_ct;
1129 test_ct-- > 0;
1130 p_test++)
1132 switch (p_test->type)
1134 case TT_TEST:
1135 if (test_test (p_test, pz_curr_file) != APPLY_FIX) {
1136 #ifdef DEBUG
1137 if (VLEVEL( VERB_EVERYTHING ))
1138 fprintf (stderr, z_failed, "TEST", p_fixd->fix_name,
1139 pz_fname, p_fixd->test_ct - test_ct);
1140 #endif
1141 return BOOL_FALSE;
1143 break;
1145 case TT_EGREP:
1146 if (egrep_test (pz_curr_data, p_test) != APPLY_FIX) {
1147 #ifdef DEBUG
1148 if (VLEVEL( VERB_EVERYTHING ))
1149 fprintf (stderr, z_failed, "EGREP", p_fixd->fix_name,
1150 pz_fname, p_fixd->test_ct - test_ct);
1151 #endif
1152 return BOOL_FALSE;
1154 break;
1156 case TT_NEGREP:
1157 if (egrep_test (pz_curr_data, p_test) == APPLY_FIX) {
1158 #ifdef DEBUG
1159 if (VLEVEL( VERB_EVERYTHING ))
1160 fprintf (stderr, z_failed, "NEGREP", p_fixd->fix_name,
1161 pz_fname, p_fixd->test_ct - test_ct);
1162 #endif
1163 /* Negated sense */
1164 return BOOL_FALSE;
1166 break;
1168 case TT_FUNCTION:
1169 if (run_test (p_test->pz_test_text, pz_curr_file, pz_curr_data)
1170 != APPLY_FIX) {
1171 #ifdef DEBUG
1172 if (VLEVEL( VERB_EVERYTHING ))
1173 fprintf (stderr, z_failed, "FTEST", p_fixd->fix_name,
1174 pz_fname, p_fixd->test_ct - test_ct);
1175 #endif
1176 return BOOL_FALSE;
1178 break;
1182 return BOOL_TRUE;
1186 /* * * * * * * * * * * * *
1188 Write out a replacement file */
1190 static void
1191 write_replacement (tFixDesc* p_fixd)
1193 const char* pz_text = p_fixd->patch_args[0];
1195 if ((pz_text == (char*)NULL) || (*pz_text == NUL))
1196 return;
1199 FILE* out_fp = create_file ();
1200 fputs (pz_text, out_fp);
1201 fclose (out_fp);
1206 /* * * * * * * * * * * * *
1208 We have work to do. Read back in the output
1209 of the filtering chain. Compare each byte as we read it with
1210 the contents of the original file. As soon as we find any
1211 difference, we will create the output file, write out all
1212 the matched text and then copy any remaining data from the
1213 output of the filter chain.
1215 static void
1216 test_for_changes (int read_fd)
1218 FILE *in_fp = fdopen (read_fd, "r");
1219 FILE *out_fp = (FILE *) NULL;
1220 unsigned char *pz_cmp = (unsigned char*)pz_curr_data;
1222 #ifdef DO_STATS
1223 fixed_ct++;
1224 #endif
1225 for (;;)
1227 int ch;
1229 ch = getc (in_fp);
1230 if (ch == EOF)
1231 break;
1232 ch &= 0xFF; /* all bytes are 8 bits */
1234 /* IF we are emitting the output
1235 THEN emit this character, too.
1237 if (out_fp != (FILE *) NULL)
1238 putc (ch, out_fp);
1240 /* ELSE if this character does not match the original,
1241 THEN now is the time to start the output.
1243 else if (ch != *pz_cmp)
1245 out_fp = create_file ();
1247 #ifdef DO_STATS
1248 altered_ct++;
1249 #endif
1250 /* IF there are matched data, write the matched part now. */
1251 if ((char*)pz_cmp != pz_curr_data)
1252 fwrite (pz_curr_data, (size_t)((char*)pz_cmp - pz_curr_data),
1253 1, out_fp);
1255 /* Emit the current unmatching character */
1256 putc (ch, out_fp);
1258 else
1259 /* ELSE the character matches. Advance the compare ptr */
1260 pz_cmp++;
1263 /* IF we created the output file, ... */
1264 if (out_fp != (FILE *) NULL)
1266 regmatch_t match;
1268 /* Close the file and see if we have to worry about
1269 `#include "file.h"' constructs. */
1270 fclose (out_fp);
1271 if (xregexec (&incl_quote_re, pz_curr_data, 1, &match, 0) == 0)
1272 extract_quoted_files (pz_curr_data, pz_curr_file, &match);
1275 fclose (in_fp);
1276 close (read_fd); /* probably redundant, but I'm paranoid */
1280 /* * * * * * * * * * * * *
1282 Process the potential fixes for a particular include file.
1283 Input: the original text of the file and the file's name
1284 Result: none. A new file may or may not be created. */
1286 void
1287 process (void)
1289 tFixDesc *p_fixd = fixDescList;
1290 int todo_ct = FIX_COUNT;
1291 int read_fd = -1;
1292 # ifndef SEPARATE_FIX_PROC
1293 int num_children = 0;
1294 # else /* is SEPARATE_FIX_PROC */
1295 char* pz_file_source = pz_curr_file;
1296 # endif
1298 if (access (pz_curr_file, R_OK) != 0)
1300 int erno = errno;
1301 fprintf (stderr, "Cannot access %s from %s\n\terror %d (%s)\n",
1302 pz_curr_file, getcwd ((char *) NULL, MAXPATHLEN),
1303 erno, xstrerror (erno));
1304 return;
1307 pz_curr_data = load_file (pz_curr_file);
1308 if (pz_curr_data == (char *) NULL)
1309 return;
1311 #ifdef DO_STATS
1312 process_ct++;
1313 #endif
1314 if (VLEVEL( VERB_PROGRESS ) && have_tty)
1315 fprintf (stderr, "%6lu %-50s \r",
1316 (unsigned long) data_map_size, pz_curr_file);
1318 # ifndef SEPARATE_FIX_PROC
1319 process_chain_head = NOPROCESS;
1321 /* For every fix in our fix list, ... */
1322 for (; todo_ct > 0; p_fixd++, todo_ct--)
1324 if (! fix_applies (p_fixd))
1325 continue;
1327 if (VLEVEL( VERB_APPLIES ))
1328 fprintf (stderr, "Applying %-24s to %s\n",
1329 p_fixd->fix_name, pz_curr_file);
1331 if (p_fixd->fd_flags & FD_REPLACEMENT)
1333 write_replacement (p_fixd);
1334 UNLOAD_DATA();
1335 return;
1338 /* IF we do not have a read pointer,
1339 THEN this is the first fix for the current file.
1340 Open the source file. That will be used as stdin for
1341 the first fix. Any subsequent fixes will use the
1342 stdout descriptor of the previous fix for its stdin. */
1344 if (read_fd == -1)
1346 read_fd = open (pz_curr_file, O_RDONLY);
1347 if (read_fd < 0)
1349 fprintf (stderr, "Error %d (%s) opening %s\n", errno,
1350 xstrerror (errno), pz_curr_file);
1351 exit (EXIT_FAILURE);
1354 /* Ensure we do not get duplicate output */
1356 fflush (stdout);
1359 read_fd = start_fixer (read_fd, p_fixd, pz_curr_file);
1360 num_children++;
1363 /* IF we have a read-back file descriptor,
1364 THEN check for changes and write output if changed. */
1366 if (read_fd >= 0)
1368 test_for_changes (read_fd);
1369 #ifdef DO_STATS
1370 apply_ct += num_children;
1371 #endif
1372 /* Wait for child processes created by chain_open()
1373 to avoid leaving zombies. */
1374 do {
1375 wait ((int *) NULL);
1376 } while (--num_children > 0);
1379 # else /* is SEPARATE_FIX_PROC */
1381 for (; todo_ct > 0; p_fixd++, todo_ct--)
1383 if (! fix_applies (p_fixd))
1384 continue;
1386 if (VLEVEL( VERB_APPLIES ))
1387 fprintf (stderr, "Applying %-24s to %s\n",
1388 p_fixd->fix_name, pz_curr_file);
1390 if (p_fixd->fd_flags & FD_REPLACEMENT)
1392 write_replacement (p_fixd);
1393 UNLOAD_DATA();
1394 return;
1396 fix_with_system (p_fixd, pz_curr_file, pz_file_source, pz_temp_file);
1397 pz_file_source = pz_temp_file;
1400 read_fd = open (pz_temp_file, O_RDONLY);
1401 if (read_fd < 0)
1403 if (errno != ENOENT)
1404 fprintf (stderr, "error %d (%s) opening output (%s) for read\n",
1405 errno, xstrerror (errno), pz_temp_file);
1407 else
1409 test_for_changes (read_fd);
1410 /* Unlinking a file while it is still open is a Bad Idea on
1411 DOS/Windows. */
1412 close (read_fd);
1413 unlink (pz_temp_file);
1416 # endif
1417 UNLOAD_DATA();