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 tSCC zNeedsArg[] = "fixincl error: `%s' needs %s argument (c_fix_arg[%d])\n";
71 _FT_( "char_macro_def", char_macro_def_fix ) \
72 _FT_( "char_macro_use", char_macro_use_fix ) \
73 _FT_( "format", format_fix ) \
74 _FT_( "machine_name", machine_name_fix ) \
75 _FT_( "wrap", wrap_fix ) \
76 _FT_( "gnu_type", gnu_type_fix )
79 #define FIX_PROC_HEAD( fix ) \
80 static void fix ( filname, text, p_fixd ) \
81 const char* filname; \
87 * Skip over a quoted string. Single quote strings may
88 * contain multiple characters if the first character is
89 * a backslash. Especially a backslash followed by octal digits.
90 * We are not doing a correctness syntax check here.
93 print_quote( q, text )
110 fputc( *(text++), stdout );
130 * Emit the GNU standard type wrapped up in such a way that
131 * this thing can be encountered countless times during a compile
132 * and not cause even a warning.
135 emit_gnu_type ( text, rm )
139 extern t_gnu_type_map gnu_type_map[];
140 extern int gnu_type_map_ct;
142 const char* pzt = text + rm[GTYPE_SE_CT].rm_so;
143 t_gnu_type_map* p_tm = gnu_type_map;
144 int ct = gnu_type_map_ct;
146 fwrite (text, rm[0].rm_so, 1, stdout);
151 if (strncmp (pzt, p_tm->pz_type, p_tm->type_name_len) == 0)
156 return (const char*)NULL;
165 * Now print out the reformed typedef
167 printf ("#ifndef __%s_TYPE__\n"
168 "#define __%s_TYPE__ %s\n"
170 p_tm->pz_TYPE, p_tm->pz_TYPE, p_tm->pz_gtype );
172 printf ("#if !defined(_GCC_%s_T)%s\n"
173 "#define _GCC_%s_T\n"
174 "typedef __%s_TYPE__ %s_t;\n"
176 p_tm->pz_TYPE, p_tm->pz_cxx_guard,
177 p_tm->pz_TYPE, p_tm->pz_TYPE, p_tm->pz_type);
184 * Copy the `format' string to std out, replacing `%n' expressions
185 * with the matched text from a regular expression evaluation.
186 * Doubled '%' characters will be replaced with a single copy.
187 * '%' characters in other contexts and all other characters are
188 * copied out verbatim.
191 format_write (format, text, av)
198 while ((c = (unsigned)*(format++)) != NUL) {
206 c = (unsigned)*(format++);
209 * IF the character following a '%' is not a digit,
210 * THEN we will always emit a '%' and we may or may
211 * not emit the following character. We will end on
212 * a NUL and we will emit only one of a pair of '%'.
228 * Emit the matched subexpression numbered 'c'.
229 * IF, of course, there was such a match...
232 regmatch_t* pRM = av + (c - (unsigned)'0');
238 len = pRM->rm_eo - pRM->rm_so;
240 fwrite(text + pRM->rm_so, len, 1, stdout);
247 * Search for multiple copies of a regular expression. Each block
248 * of matched text is replaced with the format string, as described
249 * above in `format_write'.
251 FIX_PROC_HEAD( format_fix )
253 tCC* pz_pat = p_fixd->patch_args[2];
254 tCC* pz_fmt = p_fixd->patch_args[1];
260 * We must have a format
262 if (pz_fmt == (tCC*)NULL)
264 fprintf( stderr, zNeedsArg, p_fixd->fix_name, "replacement format", 0 );
269 * IF we don't have a search text, then go find the first
270 * regular expression among the tests.
272 if (pz_pat == (tCC*)NULL)
274 tTestDesc* pTD = p_fixd->p_test_desc;
275 int ct = p_fixd->test_ct;
280 fprintf( stderr, zNeedsArg, p_fixd->fix_name, "search text", 1 );
284 if (pTD->type == TT_EGREP)
286 pz_pat = pTD->pz_test_text;
295 * Replace every copy of the text we find
297 compile_re (pz_pat, &re, 1, "format search-text", "format_fix" );
298 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;
342 fprintf (stderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0);
347 compile_re (pat, &re, 1, "macro pattern", "char_macro_use_fix");
350 regexec (&re, p, 1, rm, 0) == 0;
353 /* p + rm[0].rm_eo is the first character of the macro replacement.
354 Find the end of the macro replacement, and the STR we were
355 sent to look for within the replacement. */
360 limit = strchr (limit + 1, '\n');
364 while (limit[-1] == '\\');
368 if (*p == str[0] && !strncmp (p+1, str+1, len-1))
371 while (++p < limit - len);
372 /* Hit end of line. */
376 /* Found STR on this line. If the macro needs fixing,
377 the next few chars will be whitespace or uppercase,
378 then an open paren, then a single letter. */
379 while ((isspace (*p) || isupper (*p)) && p < limit) p++;
384 if (isalnum (p[1]) || p[1] == '_')
387 /* Splat all preceding text into the output buffer,
388 quote the character at p, then proceed. */
389 fwrite (text, 1, p - text, stdout);
396 fputs (text, stdout);
400 /* Scan the input file for all occurrences of text like this:
402 #define xxxIOxx(x, y) (....'x'<<16....)
404 and change them to read like this:
406 #define xxxIOxx(x, y) (....x<<16....)
408 which is the required syntax per the C standard. (The uses of _IO
409 also has to be tweaked - see above.) 'IO' is actually whatever
410 you provide as the `c_fix_arg' argument. */
411 FIX_PROC_HEAD( char_macro_def_fix )
413 /* This regexp looks for any traditional-syntax #define (# in column 1). */
414 static const char pat[] =
415 "^#[ \t]*define[ \t]+";
418 const char* str = p_fixd->patch_args[1];
420 const char *p, *limit;
426 fprintf (stderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0);
431 compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_defines");
434 regexec (&re, p, 1, rm, 0) == 0;
437 /* p + rm[0].rm_eo is the first character of the macro name.
438 Find the end of the macro replacement, and the STR we were
439 sent to look for within the name. */
444 limit = strchr (limit + 1, '\n');
448 while (limit[-1] == '\\');
452 if (*p == str[0] && !strncmp (p+1, str+1, len-1))
456 while (isalpha (*p) || isalnum (*p) || *p == '_');
457 /* Hit end of macro name without finding the string. */
461 /* Found STR in this macro name. If the macro needs fixing,
462 there may be a few uppercase letters, then there will be an
463 open paren with _no_ intervening whitespace, and then a
465 while (isupper (*p) && p < limit) p++;
470 if (isalnum (p[1]) || p[1] == '_')
473 /* The character at P is the one to look for in the following
480 if (p[-1] == '\'' && p[0] == arg && p[1] == '\'')
482 /* Remove the quotes from this use of ARG. */
484 fwrite (text, 1, p - text, stdout);
494 fputs (text, stdout);
497 /* Fix for machine name #ifdefs that are not in the namespace reserved
498 by the C standard. They won't be defined if compiling with -ansi,
499 and the headers will break. We go to some trouble to only change
500 #ifdefs where the macro is defined by GCC in non-ansi mode; this
501 minimizes the number of headers touched. */
503 #define SCRATCHSZ 64 /* hopefully long enough */
505 FIX_PROC_HEAD( machine_name_fix )
508 fputs( "The target machine has no needed machine name fixes\n", stderr );
511 const char *line, *base, *limit, *p, *q;
512 regex_t *label_re, *name_re;
513 char scratch[SCRATCHSZ];
516 mn_get_regexps (&label_re, &name_re, "machine_name_fix");
522 regexec (label_re, base, 2, match, 0) == 0;
525 base += match[0].rm_eo;
526 /* We're looking at an #if or #ifdef. Scan forward for the
527 next non-escaped newline. */
532 limit = strchr (limit, '\n');
536 while (limit[-1] == '\\');
538 /* If the 'name_pat' matches in between base and limit, we have
539 a bogon. It is not worth the hassle of excluding comments
540 because comments on #if/#ifdef lines are rare, and strings on
541 such lines are illegal.
543 REG_NOTBOL means 'base' is not at the beginning of a line, which
544 shouldn't matter since the name_re has no ^ anchor, but let's
545 be accurate anyway. */
553 if (regexec (name_re, base, 1, match, REG_NOTBOL))
554 goto done; /* No remaining match in this file */
556 /* Match; is it on the line? */
557 if (match[0].rm_eo > limit - base)
560 p = base + match[0].rm_so;
561 base += match[0].rm_eo;
563 /* One more test: if on the same line we have the same string
564 with the appropriate underscores, then leave it alone.
565 We want exactly two leading and trailing underscores. */
568 len = base - p - ((*base == '_') ? 2 : 1);
573 len = base - p - ((*base == '_') ? 1 : 0);
576 if (len + 4 > SCRATCHSZ)
578 memcpy (&scratch[2], q, len);
580 scratch[len++] = '_';
581 scratch[len++] = '_';
583 for (q = line; q <= limit - len; q++)
584 if (*q == '_' && !strncmp (q, scratch, len))
587 fwrite (text, 1, p - text, stdout);
588 fwrite (scratch, 1, len, stdout);
595 fputs (text, stdout);
599 FIX_PROC_HEAD( wrap_fix )
601 char z_fixname[ 64 ];
602 tCC* pz_src = p_fixd->fix_name;
603 tCC* pz_name = z_fixname;
604 char* pz_dst = z_fixname;
608 char ch = *(pz_src++);
611 *(pz_dst++) = toupper( ch );
613 else if (isalnum( ch ))
616 else if (ch == NUL) {
623 if (++len >= sizeof( z_fixname )) {
624 void* p = xmalloc( len + strlen( pz_src ) + 1 );
625 memcpy( p, (void*)z_fixname, len );
627 pz_dst = (char*)pz_name + len;
631 printf( "#ifndef FIXINC_%s_CHECK\n", pz_name );
632 printf( "#define FIXINC_%s_CHECK 1\n\n", pz_name );
634 if (p_fixd->patch_args[1] == (tCC*)NULL)
635 fputs( text, stdout );
638 fputs( p_fixd->patch_args[1], stdout );
639 fputs( text, stdout );
640 if (p_fixd->patch_args[2] != (tCC*)NULL)
641 fputs( p_fixd->patch_args[2], stdout );
644 printf( "\n#endif /* FIXINC_%s_CHECK */\n", pz_name );
645 if (pz_name != z_fixname)
646 free( (void*)pz_name );
651 * Search for multiple copies of a regular expression. Each block
652 * of matched text is replaced with the format string, as described
653 * above in `format_write'.
655 FIX_PROC_HEAD( gnu_type_fix )
659 regmatch_t rm[GTYPE_SE_CT+1];
662 tTestDesc* pTD = p_fixd->p_test_desc;
663 int ct = p_fixd->test_ct;
668 fprintf (stderr, zNeedsArg, p_fixd->fix_name, "search text", 1);
672 if (pTD->type == TT_EGREP)
674 pz_pat = pTD->pz_test_text;
682 compile_re (pz_pat, &re, 1, "gnu type typedef", "gnu_type_fix");
684 while (regexec (&re, text, GTYPE_SE_CT+1, rm, 0) == 0)
687 text = emit_gnu_type (text, rm);
689 tSCC z_mismatch[] = "``%s'' mismatched:\n";
692 * Make sure we matched *all* subexpressions
694 if (rm[GTYPE_SE_CT].rm_so == -1)
698 fprintf (stderr, z_mismatch, pz_pat);
700 for (i=0; i <= GTYPE_SE_CT; i++)
702 if (rm[i].rm_so != -1)
704 fprintf( stderr, "%4d: ``", i );
705 fwrite( text + rm[i].rm_so, rm[i].rm_eo - rm[i].rm_so,
707 fputs( "''\n", stderr );
711 fprintf( stderr, "%4d: BROKEN\n", i );
717 text = emit_gnu_type (text, rm);
720 fprintf (stderr, z_mismatch, pz_pat);
727 * Dump out the rest of the file
729 fputs (text, stdout);
733 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
735 test for fix selector
737 THIS IS THE ONLY EXPORTED ROUTINE
741 apply_fix( p_fixd, filname )
745 #define _FT_(n,p) { n, p },
746 static fix_entry_t fix_table[] = { FIXUP_TABLE { NULL, NULL }};
748 #define FIX_TABLE_CT ((sizeof(fix_table)/sizeof(fix_table[0]))-1)
750 tCC* fixname = p_fixd->patch_args[0];
752 int ct = FIX_TABLE_CT;
753 fix_entry_t* pfe = fix_table;
757 if (strcmp (pfe->fix_name, fixname) == 0)
761 fprintf (stderr, "fixincl error: the `%s' fix is unknown\n",
768 buf = load_file_data (stdin);
769 (*pfe->fix_proc)( filname, buf, p_fixd );