OSDN Git Service

enhance the format style c_fix & remove unneeded wrapper funcs
[pf3gnuchains/gcc-fork.git] / gcc / fixinc / fixfixes.c
1
2 /*
3
4    Test to see if a particular fix should be applied to a header file.
5
6    Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
7
8 = = = = = = = = = = = = = = = = = = = = = = = = =
9
10 NOTE TO DEVELOPERS
11
12 The routines you write here must work closely with fixincl.c.
13
14 Here are the rules:
15
16 1.  Every test procedure name must be suffixed with "_fix".
17     These routines will be referenced from inclhack.def, sans the suffix.
18
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.
21
22 3.  Put your test name into the FIXUP_TABLE
23
24 4.  Do not read anything from stdin.  It is closed.
25
26 5.  Write to stderr only in the event of a reportable error
27     In such an event, call "exit(1)".
28
29 6.  You have access to the fixDescList entry for the fix in question.
30     This may be useful, for example, if there are pre-compiled
31     selection expressions stored there.
32
33     For example, you may do this if you know that the first 
34     test contains a useful regex.  This is okay because, remember,
35     this code perforce works closely with the inclhack.def fixes!!
36
37     tFixDesc*  pMyDesc = fixDescList + MY_FIX_NAME_FIXIDX;
38     tTestDesc* pTestList = pMyDesc->p_test_desc;
39
40     regexec (pTestList->p_test_regex, ...)
41
42 = = = = = = = = = = = = = = = = = = = = = = = = =
43
44 This file is part of GNU CC.
45
46 GNU CC is free software; you can redistribute it and/or modify
47 it under the terms of the GNU General Public License as published by
48 the Free Software Foundation; either version 2, or (at your option)
49 any later version.
50
51 GNU CC is distributed in the hope that it will be useful,
52 but WITHOUT ANY WARRANTY; without even the implied warranty of
53 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54 GNU General Public License for more details.
55
56 You should have received a copy of the GNU General Public License
57 along with GNU CC; see the file COPYING.  If not, write to
58 the Free Software Foundation, 59 Temple Place - Suite 330,
59 Boston, MA 02111-1307, USA.  */
60
61 #include "fixlib.h"
62
63 typedef struct {
64     const char*  fix_name;
65     void (*fix_proc)();
66 } fix_entry_t;
67
68 #define FIXUP_TABLE \
69   _FT_( "format",           format_fix ) \
70   _FT_( "char_macro_use",   char_macro_use_fix ) \
71   _FT_( "char_macro_def",   char_macro_def_fix ) \
72   _FT_( "machine_name",     machine_name_fix )
73
74
75 #define FIX_PROC_HEAD( fix ) \
76 static void fix ( filname, text, p_fixd ) \
77     const char* filname; \
78     static char* text; \
79     tFixDesc* p_fixd;
80
81
82 /*
83  *  Skip over a quoted string.  Single quote strings may
84  *  contain multiple characters if the first character is
85  *  a backslash.  Especially a backslash followed by octal digits.
86  *  We are not doing a correctness syntax check here.
87  */
88 static char*
89 print_quote( q, text )
90   char  q;
91   char* text;
92 {
93   fputc( q, stdout );
94
95   for (;;)
96     {
97       char ch = *(text++);
98       fputc( ch, stdout );
99
100       switch (ch)
101         {
102         case '\\':
103           if (*text == NUL)
104             goto quote_done;
105
106           fputc( *(text++), stdout );
107           break;
108
109         case '"':
110         case '\'':
111           if (ch != q)
112             break;
113           /*FALLTHROUGH*/
114
115         case '\n':
116         case NUL:
117           goto quote_done;
118         }
119     } quote_done:;
120
121   return text;
122 }
123
124 static void
125 format_write (format, text, av)
126      tCC* format;
127      tCC* text;
128      regmatch_t av[];
129 {
130     tCC *p, *str;
131     int c;
132     size_t len;
133
134     for (p = 0; *p; p++) {
135        c = *p;
136        if (c != '%') {
137            putchar(c);
138            continue;
139        }
140
141        c = *++p;
142        if (c == '%') {
143            putchar(c);
144            continue;
145        } else if (c < '0' || c > '9') {
146            abort();
147        }
148
149        c -= '0';
150        str = text + av[c].rm_so;
151        len = av[c].rm_eo - av[c].rm_so;
152        fwrite(str, len, 1, stdout);
153     }
154 }
155
156 FIX_PROC_HEAD( format_fix )
157 {
158     tSCC  zBad[] = "fixincl error:  `%s' needs %s c_fix_arg\n";
159     tCC*  pz_pat = p_fixd->patch_args[2];
160     tCC*  pz_fmt = p_fixd->patch_args[1];
161     const char *p;
162     regex_t re;
163     regmatch_t rm[10];
164
165     /*
166      *  We must have a format
167      */
168     if (pz_fmt == (tCC*)NULL) {
169         fprintf( stderr, zBad, p_fixd->fix_name, "replacement-format" );
170         exit( 3 );
171     }
172
173     /*
174      *  IF we don't have a search text, then go find the first
175      *  regular expression among the tests.
176      */
177     if (pz_pat == (tCC*)NULL) {
178         tTestDesc* pTD = p_fixd->p_test_desc;
179         int        ct  = p_fixd->test_ct;
180         for (;;) {
181             if (ct-- <= 0) {
182                 fprintf( stderr, zBad, p_fixd->fix_name, "search-text" );
183                 exit( 3 );
184             }
185
186             if (pTD->type == TT_EGREP) {
187                 pz_pat = pTD->pz_test_text;
188                 break;
189             }
190
191             pTD++;
192         }
193     }
194
195     /*
196      *  Replace every copy of the text we find
197      */
198     compile_re (pz_pat, &re, 1, "format search-text", "format_fix" );
199     while (regexec (&re, text, 10, rm, 0) == 0)
200     {
201         char* apz[10];
202         int   i;
203
204         fwrite( text, rm[0].rm_so, 1, stdout );
205        format_write( pz_fmt, text, rm );
206         text += rm[0].rm_eo;
207     }
208
209     /*
210      *  Dump out the rest of the file
211      */
212     fputs (text, stdout);
213 }
214
215 /* Scan the input file for all occurrences of text like this:
216
217    #define TIOCCONS _IO(T, 12)
218
219    and change them to read like this:
220
221    #define TIOCCONS _IO('T', 12)
222
223    which is the required syntax per the C standard.  (The definition of
224    _IO also has to be tweaked - see below.)  'IO' is actually whatever you
225    provide in the STR argument.  */
226
227 FIX_PROC_HEAD( char_macro_use_fix )
228 {
229   /* This regexp looks for a traditional-syntax #define (# in column 1)
230      of an object-like macro.  */
231   static const char pat[] =
232     "^#[ \t]*define[ \t]+[_A-Za-z][_A-Za-z0-9]*[ \t]+";
233   static regex_t re;
234
235   regmatch_t rm[1];
236   const char *p, *limit;
237   const char *str = p_fixd->patch_args[0];
238   size_t len;
239
240   if (str == NULL)
241     {
242       fprintf (stderr, "%s needs macro-name-string argument",
243               p_fixd->fix_name);
244       exit(3);
245     }
246
247   len = strlen (str);
248   compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_uses");
249
250   for (p = text;
251        regexec (&re, p, 1, rm, 0) == 0;
252        p = limit + 1)
253     {
254       /* p + rm[0].rm_eo is the first character of the macro replacement.
255          Find the end of the macro replacement, and the STR we were
256          sent to look for within the replacement.  */
257       p += rm[0].rm_eo;
258       limit = p - 1;
259       do
260         {
261           limit = strchr (limit + 1, '\n');
262           if (!limit)
263             goto done;
264         }
265       while (limit[-1] == '\\');
266
267       do
268         {
269           if (*p == str[0] && !strncmp (p+1, str+1, len-1))
270             goto found;
271         }
272       while (++p < limit - len);
273       /* Hit end of line.  */
274       continue;
275
276     found:
277       /* Found STR on this line.  If the macro needs fixing,
278          the next few chars will be whitespace or uppercase,
279          then an open paren, then a single letter.  */
280       while ((isspace (*p) || isupper (*p)) && p < limit) p++;
281       if (*p++ != '(')
282         continue;
283       if (!isalpha (*p))
284         continue;
285       if (isalnum (p[1]) || p[1] == '_')
286         continue;
287
288       /* Splat all preceding text into the output buffer,
289          quote the character at p, then proceed.  */
290       fwrite (text, 1, p - text, stdout);
291       putchar ('\'');
292       putchar (*p);
293       putchar ('\'');
294       text = p + 1;
295     }
296  done:
297   fputs (text, stdout);
298 }
299
300 /* Scan the input file for all occurrences of text like this:
301
302    #define _IO(x, y) ('x'<<16+y)
303
304    and change them to read like this:
305
306    #define _IO(x, y) (x<<16+y)
307
308    which is the required syntax per the C standard.  (The uses of _IO
309    also have to be tweaked - see above.)  'IO' is actually whatever
310    you provide in the STR argument.  */
311 FIX_PROC_HEAD( char_macro_def_fix )
312 {
313   /* This regexp looks for any traditional-syntax #define (# in column 1).  */
314   static const char pat[] =
315     "^#[ \t]*define[ \t]+";
316   static regex_t re;
317
318   regmatch_t rm[1];
319   const char *p, *limit;
320   const char *str = p_fixd->patch_args[0];
321   size_t len;
322   char arg;
323
324   if (str == NULL)
325     {
326       fprintf (stderr, "%s needs macro-name-string argument",
327               p_fixd->fix_name);
328       exit(3);
329     }
330
331   compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_defines");
332
333   for (p = text;
334        regexec (&re, p, 1, rm, 0) == 0;
335        p = limit + 1)
336     {
337       /* p + rm[0].rm_eo is the first character of the macro name.
338          Find the end of the macro replacement, and the STR we were
339          sent to look for within the name.  */
340       p += rm[0].rm_eo;
341       limit = p - 1;
342       do
343         {
344           limit = strchr (limit + 1, '\n');
345           if (!limit)
346             goto done;
347         }
348       while (limit[-1] == '\\');
349
350       do
351         {
352           if (*p == str[0] && !strncmp (p+1, str+1, len-1))
353             goto found;
354           p++;
355         }
356       while (isalpha (*p) || isalnum (*p) || *p == '_');
357       /* Hit end of macro name without finding the string.  */
358       continue;
359
360     found:
361       /* Found STR in this macro name.  If the macro needs fixing,
362          there may be a few uppercase letters, then there will be an
363          open paren with _no_ intervening whitespace, and then a
364          single letter.  */
365       while (isupper (*p) && p < limit) p++;
366       if (*p++ != '(')
367         continue;
368       if (!isalpha (*p))
369         continue;
370       if (isalnum (p[1]) || p[1] == '_')
371         continue;
372
373       /* The character at P is the one to look for in the following
374          text.  */
375       arg = *p;
376       p += 2;
377
378       while (p < limit)
379         {
380           if (p[-1] == '\'' && p[0] == arg && p[1] == '\'')
381             {
382               /* Remove the quotes from this use of ARG.  */
383               p--;
384               fwrite (text, 1, p - text, stdout);
385               putchar (arg);
386               p += 3;
387               text = p;
388             }
389           else
390             p++;
391         }
392     }
393  done:
394   fputs (text, stdout);
395 }
396
397 /* Fix for machine name #ifdefs that are not in the namespace reserved
398    by the C standard.  They won't be defined if compiling with -ansi,
399    and the headers will break.  We go to some trouble to only change
400    #ifdefs where the macro is defined by GCC in non-ansi mode; this
401    minimizes the number of headers touched.  */
402
403 #define SCRATCHSZ 64   /* hopefully long enough */
404
405 FIX_PROC_HEAD( machine_name_fix )
406 {
407 #ifndef MN_NAME_PAT
408   fputs( "The target machine has no needed machine name fixes\n", stderr );
409 #else
410   regmatch_t match[2];
411   const char *line, *base, *limit, *p, *q;
412   regex_t *label_re, *name_re;
413   char scratch[SCRATCHSZ];
414   size_t len;
415
416   mn_get_regexps (&label_re, &name_re, "machine_name_fix");
417
418   scratch[0] = '_';
419   scratch[1] = '_';
420
421   for (base = text;
422        regexec (label_re, base, 2, match, 0) == 0;
423        base = limit)
424     {
425       base += match[0].rm_eo;
426       /* We're looking at an #if or #ifdef.  Scan forward for the
427          next non-escaped newline.  */
428       line = limit = base;
429       do
430         {
431           limit++;
432           limit = strchr (limit, '\n');
433           if (!limit)
434             goto done;
435         }
436       while (limit[-1] == '\\');
437
438       /* If the 'name_pat' matches in between base and limit, we have
439          a bogon.  It is not worth the hassle of excluding comments
440          because comments on #if/#ifdef lines are rare, and strings on
441          such lines are illegal.
442
443          REG_NOTBOL means 'base' is not at the beginning of a line, which
444          shouldn't matter since the name_re has no ^ anchor, but let's
445          be accurate anyway.  */
446
447       for (;;)
448         {
449         again:
450           if (base == limit)
451             break;
452
453           if (regexec (name_re, base, 1, match, REG_NOTBOL))
454             goto done;  /* No remaining match in this file */
455
456           /* Match; is it on the line?  */
457           if (match[0].rm_eo > limit - base)
458             break;
459
460           p = base + match[0].rm_so;
461           base += match[0].rm_eo;
462
463           /* One more test: if on the same line we have the same string
464              with the appropriate underscores, then leave it alone.
465              We want exactly two leading and trailing underscores.  */
466           if (*p == '_')
467             {
468               len = base - p - ((*base == '_') ? 2 : 1);
469               q = p + 1;
470             }
471           else
472             {
473               len = base - p - ((*base == '_') ? 1 : 0);
474               q = p;
475             }
476           if (len + 4 > SCRATCHSZ)
477             abort ();
478           memcpy (&scratch[2], q, len);
479           len += 2;
480           scratch[len++] = '_';
481           scratch[len++] = '_';
482
483           for (q = line; q <= limit - len; q++)
484             if (*q == '_' && !strncmp (q, scratch, len))
485               goto again;
486           
487           fwrite (text, 1, p - text, stdout);
488           fwrite (scratch, 1, len, stdout);
489
490           text = base;
491         }
492     }
493  done:
494 #endif
495   fputs (text, stdout);
496 }
497
498
499 /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
500
501      test for fix selector
502
503      THIS IS THE ONLY EXPORTED ROUTINE
504
505 */
506 void
507 apply_fix( p_fixd, filname )
508   tFixDesc* p_fixd;
509   tCC* filname;
510 {
511 #define _FT_(n,p) { n, p },
512   static fix_entry_t fix_table[] = { FIXUP_TABLE { NULL, NULL }};
513 #undef _FT_
514 #define FIX_TABLE_CT ((sizeof(fix_table)/sizeof(fix_table[0]))-1)
515
516   tCC* fixname = p_fixd->patch_args[0];
517   char* buf;
518   int ct = FIX_TABLE_CT;
519   fix_entry_t* pfe = fix_table;
520
521   for (;;)
522     {
523       if (strcmp (pfe->fix_name, fixname) == 0)
524         break;
525       if (--ct <= 0)
526         {
527           fprintf (stderr, "fixincludes error:  the `%s' fix is unknown\n",
528                    fixname );
529           exit (3);
530         }
531       pfe++;
532     }
533
534   buf = load_file_data (stdin);
535   (*pfe->fix_proc)( filname, buf, p_fixd );
536 }