4 Test to see if a particular fix should be applied to a header file.
6 Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
8 = = = = = = = = = = = = = = = = = = = = = = = = =
12 The routines you write here must work closely with fixincl.c.
16 1. Every test procedure name must be suffixed with "_fix".
17 These routines will be referenced from inclhack.def, sans the suffix.
19 2. Use the "FIX_PROC_HEAD()" macro _with_ the "_fix" suffix
20 (I cannot use the ## magic from ANSI C) for defining your entry point.
22 3. Put your test name into the FIXUP_TABLE.
24 4. Do not read anything from stdin. It is closed.
26 5. Write to stderr only in the event of a reportable error
27 In such an event, call "exit (EXIT_FAILURE)".
29 6. You have access to the fixDescList entry for the fix in question.
30 This may be useful, for example, if there are interesting strings
31 or pre-compiled regular expressions stored there.
33 It is also possible to access fix descriptions by using the
34 index of a known fix, "my_fix_name" for example:
36 tFixDesc* p_desc = fixDescList + MY_FIX_NAME_FIXIDX;
37 tTestDesc* p_tlist = p_desc->p_test_desc;
39 regexec (p_tlist->p_test_regex, ...)
41 = = = = = = = = = = = = = = = = = = = = = = = = =
43 This file is part of GNU CC.
45 GNU CC is free software; you can redistribute it and/or modify
46 it under the terms of the GNU General Public License as published by
47 the Free Software Foundation; either version 2, or (at your option)
50 GNU CC is distributed in the hope that it will be useful,
51 but WITHOUT ANY WARRANTY; without even the implied warranty of
52 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53 GNU General Public License for more details.
55 You should have received a copy of the GNU General Public License
56 along with GNU CC; see the file COPYING. If not, write to
57 the Free Software Foundation, 59 Temple Place - Suite 330,
58 Boston, MA 02111-1307, USA. */
63 #ifdef SEPARATE_FIX_PROC
67 tSCC zNeedsArg
[] = "fixincl error: `%s' needs %s argument (c_fix_arg[%d])\n";
69 typedef void t_fix_proc
PARAMS ((const char *, const char *, tFixDesc
*));
76 _FT_( "char_macro_def", char_macro_def_fix ) \
77 _FT_( "char_macro_use", char_macro_use_fix ) \
78 _FT_( "format", format_fix ) \
79 _FT_( "machine_name", machine_name_fix ) \
80 _FT_( "wrap", wrap_fix ) \
81 _FT_( "gnu_type", gnu_type_fix )
84 #define FIX_PROC_HEAD( fix ) \
85 static void fix PARAMS ((const char *, const char *, tFixDesc *)); /* avoid warning */ \
86 static void fix ( filname, text, p_fixd ) \
87 const char* filname; \
91 #ifdef NEED_PRINT_QUOTE
93 * Skip over a quoted string. Single quote strings may
94 * contain multiple characters if the first character is
95 * a backslash. Especially a backslash followed by octal digits.
96 * We are not doing a correctness syntax check here.
99 print_quote( q
, text
)
116 fputc( *(text
++), stdout
);
133 #endif /* NEED_PRINT_QUOTE */
137 * Emit the GNU standard type wrapped up in such a way that
138 * this thing can be encountered countless times during a compile
139 * and not cause even a warning.
141 static const char *emit_gnu_type
PARAMS ((const char *, regmatch_t
*));
143 emit_gnu_type ( text
, rm
)
150 fwrite (text
, rm
[0].rm_so
, 1, stdout
);
153 const char* ps
= text
+ rm
[1].rm_so
;
154 const char* pe
= text
+ rm
[1].rm_eo
;
159 *(pD
++) = TOUPPER( *(pd
++) = *(ps
++) );
165 * Now print out the reformed typedef,
166 * with a C++ guard for WCHAR
170 #if !defined(_GCC_%s_T)%s\n\
172 typedef __%s_TYPE__ %s_t;\n\
175 const char* pz_guard
= (strcmp (z_type
, "wchar") == 0)
176 ? " && ! defined(__cplusplus)" : "";
178 printf (z_fmt
, z_TYPE
, pz_guard
, z_TYPE
, z_TYPE
, z_type
);
181 return text
+= rm
[0].rm_eo
;
186 * Copy the `format' string to std out, replacing `%n' expressions
187 * with the matched text from a regular expression evaluation.
188 * Doubled '%' characters will be replaced with a single copy.
189 * '%' characters in other contexts and all other characters are
190 * copied out verbatim.
192 static void format_write
PARAMS ((tCC
*, tCC
*, regmatch_t
[]));
194 format_write (format
, text
, av
)
201 while ((c
= (unsigned)*(format
++)) != NUL
) {
209 c
= (unsigned)*(format
++);
212 * IF the character following a '%' is not a digit,
213 * THEN we will always emit a '%' and we may or may
214 * not emit the following character. We will end on
215 * a NUL and we will emit only one of a pair of '%'.
231 * Emit the matched subexpression numbered 'c'.
232 * IF, of course, there was such a match...
235 regmatch_t
* pRM
= av
+ (c
- (unsigned)'0');
241 len
= pRM
->rm_eo
- pRM
->rm_so
;
243 fwrite(text
+ pRM
->rm_so
, len
, 1, stdout
);
250 * Search for multiple copies of a regular expression. Each block
251 * of matched text is replaced with the format string, as described
252 * above in `format_write'.
254 FIX_PROC_HEAD( format_fix
)
256 tCC
* pz_pat
= p_fixd
->patch_args
[2];
257 tCC
* pz_fmt
= p_fixd
->patch_args
[1];
263 * We must have a format
265 if (pz_fmt
== (tCC
*)NULL
)
267 fprintf( stderr
, zNeedsArg
, p_fixd
->fix_name
, "replacement format", 0 );
272 * IF we don't have a search text, then go find the first
273 * regular expression among the tests.
275 if (pz_pat
== (tCC
*)NULL
)
277 tTestDesc
* pTD
= p_fixd
->p_test_desc
;
278 int ct
= p_fixd
->test_ct
;
283 fprintf( stderr
, zNeedsArg
, p_fixd
->fix_name
, "search text", 1 );
287 if (pTD
->type
== TT_EGREP
)
289 pz_pat
= pTD
->pz_test_text
;
298 * Replace every copy of the text we find
300 compile_re (pz_pat
, &re
, 1, "format search-text", "format_fix" );
301 while (regexec (&re
, text
, 10, rm
, 0) == 0)
303 fwrite( text
, rm
[0].rm_so
, 1, stdout
);
304 format_write( pz_fmt
, text
, rm
);
309 * Dump out the rest of the file
311 fputs (text
, stdout
);
315 /* Scan the input file for all occurrences of text like this:
317 #define TIOCCONS _IO(T, 12)
319 and change them to read like this:
321 #define TIOCCONS _IO('T', 12)
323 which is the required syntax per the C standard. (The definition of
324 _IO also has to be tweaked - see below.) 'IO' is actually whatever you
325 provide as the `c_fix_arg' argument. */
327 FIX_PROC_HEAD( char_macro_use_fix
)
329 /* This regexp looks for a traditional-syntax #define (# in column 1)
330 of an object-like macro. */
331 static const char pat
[] =
332 "^#[ \t]*define[ \t]+[_A-Za-z][_A-Za-z0-9]*[ \t]+";
335 const char* str
= p_fixd
->patch_args
[1];
337 const char *p
, *limit
;
343 fprintf (stderr
, zNeedsArg
, p_fixd
->fix_name
, "ioctl type", 0);
348 compile_re (pat
, &re
, 1, "macro pattern", "char_macro_use_fix");
351 regexec (&re
, p
, 1, rm
, 0) == 0;
354 /* p + rm[0].rm_eo is the first character of the macro replacement.
355 Find the end of the macro replacement, and the STR we were
356 sent to look for within the replacement. */
361 limit
= strchr (limit
+ 1, '\n');
365 while (limit
[-1] == '\\');
369 if (*p
== str
[0] && !strncmp (p
+1, str
+1, len
-1))
372 while (++p
< limit
- len
);
373 /* Hit end of line. */
377 /* Found STR on this line. If the macro needs fixing,
378 the next few chars will be whitespace or uppercase,
379 then an open paren, then a single letter. */
380 while ((ISSPACE (*p
) || ISUPPER (*p
)) && p
< limit
) p
++;
385 if (ISALNUM (p
[1]) || p
[1] == '_')
388 /* Splat all preceding text into the output buffer,
389 quote the character at p, then proceed. */
390 fwrite (text
, 1, p
- text
, stdout
);
397 fputs (text
, stdout
);
401 /* Scan the input file for all occurrences of text like this:
403 #define xxxIOxx(x, y) (....'x'<<16....)
405 and change them to read like this:
407 #define xxxIOxx(x, y) (....x<<16....)
409 which is the required syntax per the C standard. (The uses of _IO
410 also has to be tweaked - see above.) 'IO' is actually whatever
411 you provide as the `c_fix_arg' argument. */
412 FIX_PROC_HEAD( char_macro_def_fix
)
414 /* This regexp looks for any traditional-syntax #define (# in column 1). */
415 static const char pat
[] =
416 "^#[ \t]*define[ \t]+";
419 const char* str
= p_fixd
->patch_args
[1];
421 const char *p
, *limit
;
428 fprintf (stderr
, zNeedsArg
, p_fixd
->fix_name
, "ioctl type", 0);
433 compile_re (pat
, &re
, 1, "macro pattern", "fix_char_macro_defines");
436 regexec (&re
, p
, 1, rm
, 0) == 0;
439 /* p + rm[0].rm_eo is the first character of the macro name.
440 Find the end of the macro replacement, and the STR we were
441 sent to look for within the name. */
446 limit
= strchr (limit
+ 1, '\n');
450 while (limit
[-1] == '\\');
454 if (*p
== str
[0] && !strncmp (p
+1, str
+1, len
-1))
458 while (ISALPHA (*p
) || ISALNUM (*p
) || *p
== '_');
459 /* Hit end of macro name without finding the string. */
463 /* Found STR in this macro name. If the macro needs fixing,
464 there may be a few uppercase letters, then there will be an
465 open paren with _no_ intervening whitespace, and then a
467 while (ISUPPER (*p
) && p
< limit
) p
++;
472 if (ISALNUM (p
[1]) || p
[1] == '_')
475 /* The character at P is the one to look for in the following
482 if (p
[-1] == '\'' && p
[0] == arg
&& p
[1] == '\'')
484 /* Remove the quotes from this use of ARG. */
486 fwrite (text
, 1, p
- text
, stdout
);
496 fputs (text
, stdout
);
499 /* Fix for machine name #ifdefs that are not in the namespace reserved
500 by the C standard. They won't be defined if compiling with -ansi,
501 and the headers will break. We go to some trouble to only change
502 #ifdefs where the macro is defined by GCC in non-ansi mode; this
503 minimizes the number of headers touched. */
505 #define SCRATCHSZ 64 /* hopefully long enough */
507 FIX_PROC_HEAD( machine_name_fix
)
510 fputs( "The target machine has no needed machine name fixes\n", stderr
);
513 const char *line
, *base
, *limit
, *p
, *q
;
514 regex_t
*label_re
, *name_re
;
515 char scratch
[SCRATCHSZ
];
520 mn_get_regexps (&label_re
, &name_re
, "machine_name_fix");
526 regexec (label_re
, base
, 2, match
, 0) == 0;
529 base
+= match
[0].rm_eo
;
530 /* We're looking at an #if or #ifdef. Scan forward for the
531 next non-escaped newline. */
536 limit
= strchr (limit
, '\n');
540 while (limit
[-1] == '\\');
542 /* If the 'name_pat' matches in between base and limit, we have
543 a bogon. It is not worth the hassle of excluding comments
544 because comments on #if/#ifdef lines are rare, and strings on
545 such lines are illegal.
547 REG_NOTBOL means 'base' is not at the beginning of a line, which
548 shouldn't matter since the name_re has no ^ anchor, but let's
549 be accurate anyway. */
557 if (regexec (name_re
, base
, 1, match
, REG_NOTBOL
))
558 goto done
; /* No remaining match in this file */
560 /* Match; is it on the line? */
561 if (match
[0].rm_eo
> limit
- base
)
564 p
= base
+ match
[0].rm_so
;
565 base
+= match
[0].rm_eo
;
567 /* One more test: if on the same line we have the same string
568 with the appropriate underscores, then leave it alone.
569 We want exactly two leading and trailing underscores. */
572 len
= base
- p
- ((*base
== '_') ? 2 : 1);
577 len
= base
- p
- ((*base
== '_') ? 1 : 0);
580 if (len
+ 4 > SCRATCHSZ
)
582 memcpy (&scratch
[2], q
, len
);
584 scratch
[len
++] = '_';
585 scratch
[len
++] = '_';
587 for (q
= line
; q
<= limit
- len
; q
++)
588 if (*q
== '_' && !strncmp (q
, scratch
, len
))
591 fwrite (text
, 1, p
- text
, stdout
);
592 fwrite (scratch
, 1, len
, stdout
);
599 fputs (text
, stdout
);
603 FIX_PROC_HEAD( wrap_fix
)
605 tSCC z_no_wrap_pat
[] = "^#if.*__need_";
606 static regex_t no_wrapping_re
; /* assume zeroed data */
608 char z_fixname
[ 64 ];
609 tCC
* pz_src
= p_fixd
->fix_name
;
610 tCC
* pz_name
= z_fixname
;
611 char* pz_dst
= z_fixname
;
616 if (no_wrapping_re
.allocated
== 0)
617 compile_re( z_no_wrap_pat
, &no_wrapping_re
, 0, "no-wrap pattern",
626 } else if (! ISALNUM (ch
)) {
629 *pz_dst
++ = TOUPPER (ch
);
632 if (++len
>= sizeof( z_fixname
)) {
633 void* p
= xmalloc( len
+ strlen( pz_src
) + 1 );
634 memcpy( p
, (void*)z_fixname
, len
);
636 pz_dst
= (char*)pz_name
+ len
;
641 * IF we do *not* match the no-wrap re, then we have a double negative.
642 * A double negative means YES.
644 if (regexec (&no_wrapping_re
, text
, 0, NULL
, 0) != 0)
646 printf( "#ifndef FIXINC_%s_CHECK\n", pz_name
);
647 printf( "#define FIXINC_%s_CHECK 1\n\n", pz_name
);
651 if (p_fixd
->patch_args
[1] == (tCC
*)NULL
)
652 fputs( text
, stdout
);
655 fputs( p_fixd
->patch_args
[1], stdout
);
656 fputs( text
, stdout
);
657 if (p_fixd
->patch_args
[2] != (tCC
*)NULL
)
658 fputs( p_fixd
->patch_args
[2], stdout
);
662 printf( "\n#endif /* FIXINC_%s_CHECK */\n", pz_name
);
664 if (pz_name
!= z_fixname
)
665 free( (void*)pz_name
);
670 * Search for multiple copies of a regular expression. Each block
671 * of matched text is replaced with the format string, as described
672 * above in `format_write'.
674 FIX_PROC_HEAD( gnu_type_fix
)
678 regmatch_t rm
[GTYPE_SE_CT
+1];
682 tTestDesc
* pTD
= p_fixd
->p_test_desc
;
683 int ct
= p_fixd
->test_ct
;
688 fprintf (stderr
, zNeedsArg
, p_fixd
->fix_name
, "search text", 1);
692 if (pTD
->type
== TT_EGREP
)
694 pz_pat
= pTD
->pz_test_text
;
702 compile_re (pz_pat
, &re
, 1, "gnu type typedef", "gnu_type_fix");
704 while (regexec (&re
, text
, GTYPE_SE_CT
+1, rm
, 0) == 0)
706 text
= emit_gnu_type (text
, rm
);
710 * Dump out the rest of the file
712 fputs (text
, stdout
);
716 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
718 test for fix selector
720 THIS IS THE ONLY EXPORTED ROUTINE
724 apply_fix( p_fixd
, filname
)
728 #define _FT_(n,p) { n, p },
729 static fix_entry_t fix_table
[] = { FIXUP_TABLE
{ NULL
, NULL
}};
731 #define FIX_TABLE_CT (ARRAY_SIZE (fix_table)-1)
733 tCC
* fixname
= p_fixd
->patch_args
[0];
735 int ct
= FIX_TABLE_CT
;
736 fix_entry_t
* pfe
= fix_table
;
740 if (strcmp (pfe
->fix_name
, fixname
) == 0)
744 fprintf (stderr
, "fixincl error: the `%s' fix is unknown\n",
751 buf
= load_file_data (stdin
);
752 (*pfe
->fix_proc
)( filname
, buf
, p_fixd
);
755 #ifdef SEPARATE_FIX_PROC
757 "USAGE: applyfix <fix-name> <file-to-fix> <file-source> <file-destination>\n";
759 "FS error %d (%s) reopening %s as std%s\n";
774 fputs (z_usage
, stderr
);
782 if (! ISDIGIT ( *pz
))
785 idx
= strtol (pz
, &pz
, 10);
786 if ((*pz
!= NUL
) || ((unsigned)idx
>= FIX_COUNT
))
788 pFix
= fixDescList
+ idx
;
791 if (freopen (argv
[3], "r", stdin
) != stdin
)
793 fprintf (stderr
, z_reopen
, errno
, strerror( errno
), argv
[3], "in");
797 pz_tmptmp
= (char*)xmalloc( strlen( argv
[4] ) + 5 );
798 strcpy( pz_tmptmp
, argv
[4] );
800 /* Don't lose because "12345678" and "12345678X" map to the same
801 file under DOS restricted 8+3 file namespace. Note that DOS
802 doesn't allow more than one dot in the trunk of a file name. */
803 pz_tmp_base
= basename( pz_tmptmp
);
804 pz_tmp_dot
= strchr( pz_tmp_base
, '.' );
805 if (pathconf( pz_tmptmp
, _PC_NAME_MAX
) <= 12 /* is this DOS or Windows9X? */
806 && pz_tmp_dot
!= (char*)NULL
)
807 strcpy (pz_tmp_dot
+1, "X"); /* nuke the original extension */
809 strcat (pz_tmptmp
, ".X");
810 if (freopen (pz_tmptmp
, "w", stdout
) != stdout
)
812 fprintf (stderr
, z_reopen
, errno
, strerror( errno
), pz_tmptmp
, "out");
816 apply_fix (pFix
, argv
[1]);
820 if (rename (pz_tmptmp
, argv
[4]) != 0)
822 fprintf (stderr
, "error %d (%s) renaming %s to %s\n", errno
,
823 strerror( errno
), pz_tmptmp
, argv
[4]);