xref: /openbsd/gnu/usr.bin/gcc/gcc/fixinc/fixfixes.c (revision c87b03e5)
1*c87b03e5Sespie 
2*c87b03e5Sespie /*
3*c87b03e5Sespie 
4*c87b03e5Sespie    Test to see if a particular fix should be applied to a header file.
5*c87b03e5Sespie 
6*c87b03e5Sespie    Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
7*c87b03e5Sespie 
8*c87b03e5Sespie = = = = = = = = = = = = = = = = = = = = = = = = =
9*c87b03e5Sespie 
10*c87b03e5Sespie NOTE TO DEVELOPERS
11*c87b03e5Sespie 
12*c87b03e5Sespie The routines you write here must work closely with fixincl.c.
13*c87b03e5Sespie 
14*c87b03e5Sespie Here are the rules:
15*c87b03e5Sespie 
16*c87b03e5Sespie 1.  Every test procedure name must be suffixed with "_fix".
17*c87b03e5Sespie     These routines will be referenced from inclhack.def, sans the suffix.
18*c87b03e5Sespie 
19*c87b03e5Sespie 2.  Use the "FIX_PROC_HEAD()" macro _with_ the "_fix" suffix
20*c87b03e5Sespie     (I cannot use the ## magic from ANSI C) for defining your entry point.
21*c87b03e5Sespie 
22*c87b03e5Sespie 3.  Put your test name into the FIXUP_TABLE.
23*c87b03e5Sespie 
24*c87b03e5Sespie 4.  Do not read anything from stdin.  It is closed.
25*c87b03e5Sespie 
26*c87b03e5Sespie 5.  Write to stderr only in the event of a reportable error
27*c87b03e5Sespie     In such an event, call "exit (EXIT_FAILURE)".
28*c87b03e5Sespie 
29*c87b03e5Sespie 6.  You have access to the fixDescList entry for the fix in question.
30*c87b03e5Sespie     This may be useful, for example, if there are interesting strings
31*c87b03e5Sespie     or pre-compiled regular expressions stored there.
32*c87b03e5Sespie 
33*c87b03e5Sespie = = = = = = = = = = = = = = = = = = = = = = = = =
34*c87b03e5Sespie 
35*c87b03e5Sespie This file is part of GNU CC.
36*c87b03e5Sespie 
37*c87b03e5Sespie GNU CC is free software; you can redistribute it and/or modify
38*c87b03e5Sespie it under the terms of the GNU General Public License as published by
39*c87b03e5Sespie the Free Software Foundation; either version 2, or (at your option)
40*c87b03e5Sespie any later version.
41*c87b03e5Sespie 
42*c87b03e5Sespie GNU CC is distributed in the hope that it will be useful,
43*c87b03e5Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
44*c87b03e5Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
45*c87b03e5Sespie GNU General Public License for more details.
46*c87b03e5Sespie 
47*c87b03e5Sespie You should have received a copy of the GNU General Public License
48*c87b03e5Sespie along with GNU CC; see the file COPYING.  If not, write to
49*c87b03e5Sespie the Free Software Foundation, 59 Temple Place - Suite 330,
50*c87b03e5Sespie Boston, MA 02111-1307, USA.  */
51*c87b03e5Sespie 
52*c87b03e5Sespie #include "fixlib.h"
53*c87b03e5Sespie #define    GTYPE_SE_CT 1
54*c87b03e5Sespie 
55*c87b03e5Sespie #ifdef SEPARATE_FIX_PROC
56*c87b03e5Sespie #include "fixincl.x"
57*c87b03e5Sespie #endif
58*c87b03e5Sespie 
59*c87b03e5Sespie tSCC zNeedsArg[] = "fixincl error:  `%s' needs %s argument (c_fix_arg[%d])\n";
60*c87b03e5Sespie 
61*c87b03e5Sespie typedef void t_fix_proc PARAMS ((const char *, const char *, tFixDesc *));
62*c87b03e5Sespie typedef struct {
63*c87b03e5Sespie     const char*  fix_name;
64*c87b03e5Sespie     t_fix_proc*  fix_proc;
65*c87b03e5Sespie } fix_entry_t;
66*c87b03e5Sespie 
67*c87b03e5Sespie #define FIXUP_TABLE \
68*c87b03e5Sespie   _FT_( "char_macro_def",   char_macro_def_fix ) \
69*c87b03e5Sespie   _FT_( "char_macro_use",   char_macro_use_fix ) \
70*c87b03e5Sespie   _FT_( "format",           format_fix )         \
71*c87b03e5Sespie   _FT_( "machine_name",     machine_name_fix )   \
72*c87b03e5Sespie   _FT_( "wrap",             wrap_fix )           \
73*c87b03e5Sespie   _FT_( "gnu_type",         gnu_type_fix )
74*c87b03e5Sespie 
75*c87b03e5Sespie 
76*c87b03e5Sespie #define FIX_PROC_HEAD( fix )                    \
77*c87b03e5Sespie static void fix PARAMS ((const char *, const char *, tFixDesc *)); /* avoid warning */      \
78*c87b03e5Sespie static void fix ( filname, text, p_fixd )       \
79*c87b03e5Sespie     const char* filname;                        \
80*c87b03e5Sespie     const char* text;                           \
81*c87b03e5Sespie     tFixDesc* p_fixd;
82*c87b03e5Sespie 
83*c87b03e5Sespie #ifdef NEED_PRINT_QUOTE
84*c87b03e5Sespie /*
85*c87b03e5Sespie  *  Skip over a quoted string.  Single quote strings may
86*c87b03e5Sespie  *  contain multiple characters if the first character is
87*c87b03e5Sespie  *  a backslash.  Especially a backslash followed by octal digits.
88*c87b03e5Sespie  *  We are not doing a correctness syntax check here.
89*c87b03e5Sespie  */
90*c87b03e5Sespie static char*
print_quote(q,text)91*c87b03e5Sespie print_quote( q, text )
92*c87b03e5Sespie   char  q;
93*c87b03e5Sespie   char* text;
94*c87b03e5Sespie {
95*c87b03e5Sespie   fputc( q, stdout );
96*c87b03e5Sespie 
97*c87b03e5Sespie   for (;;)
98*c87b03e5Sespie     {
99*c87b03e5Sespie       char ch = *(text++);
100*c87b03e5Sespie       fputc( ch, stdout );
101*c87b03e5Sespie 
102*c87b03e5Sespie       switch (ch)
103*c87b03e5Sespie         {
104*c87b03e5Sespie         case '\\':
105*c87b03e5Sespie           if (*text == NUL)
106*c87b03e5Sespie             goto quote_done;
107*c87b03e5Sespie 
108*c87b03e5Sespie           fputc( *(text++), stdout );
109*c87b03e5Sespie           break;
110*c87b03e5Sespie 
111*c87b03e5Sespie         case '"':
112*c87b03e5Sespie         case '\'':
113*c87b03e5Sespie           if (ch != q)
114*c87b03e5Sespie             break;
115*c87b03e5Sespie           /*FALLTHROUGH*/
116*c87b03e5Sespie 
117*c87b03e5Sespie         case '\n':
118*c87b03e5Sespie         case NUL:
119*c87b03e5Sespie           goto quote_done;
120*c87b03e5Sespie         }
121*c87b03e5Sespie     } quote_done:;
122*c87b03e5Sespie 
123*c87b03e5Sespie   return text;
124*c87b03e5Sespie }
125*c87b03e5Sespie #endif /* NEED_PRINT_QUOTE */
126*c87b03e5Sespie 
127*c87b03e5Sespie 
128*c87b03e5Sespie /*
129*c87b03e5Sespie  *  Emit the GNU standard type wrapped up in such a way that
130*c87b03e5Sespie  *  this thing can be encountered countless times during a compile
131*c87b03e5Sespie  *  and not cause even a warning.
132*c87b03e5Sespie  */
133*c87b03e5Sespie static const char *emit_gnu_type PARAMS ((const char *, regmatch_t *));
134*c87b03e5Sespie static const char*
emit_gnu_type(text,rm)135*c87b03e5Sespie emit_gnu_type ( text, rm )
136*c87b03e5Sespie   const char* text;
137*c87b03e5Sespie   regmatch_t* rm;
138*c87b03e5Sespie {
139*c87b03e5Sespie   char z_TYPE[ 64 ];
140*c87b03e5Sespie   char z_type[ 64 ];
141*c87b03e5Sespie 
142*c87b03e5Sespie   fwrite (text, rm[0].rm_so, 1, stdout);
143*c87b03e5Sespie 
144*c87b03e5Sespie   {
145*c87b03e5Sespie     const char* ps = text   + rm[1].rm_so;
146*c87b03e5Sespie     const char* pe = text   + rm[1].rm_eo;
147*c87b03e5Sespie     char* pd = z_type;
148*c87b03e5Sespie     char* pD = z_TYPE;
149*c87b03e5Sespie 
150*c87b03e5Sespie     while (ps < pe)
151*c87b03e5Sespie       *(pD++) = TOUPPER( *(pd++) = *(ps++) );
152*c87b03e5Sespie 
153*c87b03e5Sespie     *pD = *pd = NUL;
154*c87b03e5Sespie   }
155*c87b03e5Sespie 
156*c87b03e5Sespie   /*
157*c87b03e5Sespie    *  Now print out the reformed typedef,
158*c87b03e5Sespie    *  with a C++ guard for WCHAR
159*c87b03e5Sespie    */
160*c87b03e5Sespie   {
161*c87b03e5Sespie     tSCC z_fmt[] = "\
162*c87b03e5Sespie #if !defined(_GCC_%s_T)%s\n\
163*c87b03e5Sespie #define _GCC_%s_T\n\
164*c87b03e5Sespie typedef __%s_TYPE__ %s_t;\n\
165*c87b03e5Sespie #endif\n";
166*c87b03e5Sespie 
167*c87b03e5Sespie     const char *const pz_guard = (strcmp (z_type, "wchar") == 0)
168*c87b03e5Sespie                            ? " && ! defined(__cplusplus)" : "";
169*c87b03e5Sespie 
170*c87b03e5Sespie     printf (z_fmt, z_TYPE, pz_guard, z_TYPE, z_TYPE, z_type);
171*c87b03e5Sespie   }
172*c87b03e5Sespie 
173*c87b03e5Sespie   return text += rm[0].rm_eo;
174*c87b03e5Sespie }
175*c87b03e5Sespie 
176*c87b03e5Sespie 
177*c87b03e5Sespie /*
178*c87b03e5Sespie  *  Copy the `format' string to std out, replacing `%n' expressions
179*c87b03e5Sespie  *  with the matched text from a regular expression evaluation.
180*c87b03e5Sespie  *  Doubled '%' characters will be replaced with a single copy.
181*c87b03e5Sespie  *  '%' characters in other contexts and all other characters are
182*c87b03e5Sespie  *  copied out verbatim.
183*c87b03e5Sespie  */
184*c87b03e5Sespie static void format_write PARAMS ((tCC *, tCC *, regmatch_t[]));
185*c87b03e5Sespie static void
format_write(format,text,av)186*c87b03e5Sespie format_write (format, text, av)
187*c87b03e5Sespie      tCC* format;
188*c87b03e5Sespie      tCC* text;
189*c87b03e5Sespie      regmatch_t av[];
190*c87b03e5Sespie {
191*c87b03e5Sespie   int c;
192*c87b03e5Sespie 
193*c87b03e5Sespie   while ((c = (unsigned)*(format++)) != NUL) {
194*c87b03e5Sespie 
195*c87b03e5Sespie     if (c != '%')
196*c87b03e5Sespie       {
197*c87b03e5Sespie         putchar(c);
198*c87b03e5Sespie         continue;
199*c87b03e5Sespie       }
200*c87b03e5Sespie 
201*c87b03e5Sespie     c = (unsigned)*(format++);
202*c87b03e5Sespie 
203*c87b03e5Sespie     /*
204*c87b03e5Sespie      *  IF the character following a '%' is not a digit,
205*c87b03e5Sespie      *  THEN we will always emit a '%' and we may or may
206*c87b03e5Sespie      *  not emit the following character.  We will end on
207*c87b03e5Sespie      *  a NUL and we will emit only one of a pair of '%'.
208*c87b03e5Sespie      */
209*c87b03e5Sespie     if (! ISDIGIT ( c ))
210*c87b03e5Sespie       {
211*c87b03e5Sespie         putchar( '%' );
212*c87b03e5Sespie         switch (c) {
213*c87b03e5Sespie         case NUL:
214*c87b03e5Sespie           return;
215*c87b03e5Sespie         case '%':
216*c87b03e5Sespie           break;
217*c87b03e5Sespie         default:
218*c87b03e5Sespie           putchar(c);
219*c87b03e5Sespie         }
220*c87b03e5Sespie       }
221*c87b03e5Sespie 
222*c87b03e5Sespie     /*
223*c87b03e5Sespie      *  Emit the matched subexpression numbered 'c'.
224*c87b03e5Sespie      *  IF, of course, there was such a match...
225*c87b03e5Sespie      */
226*c87b03e5Sespie     else {
227*c87b03e5Sespie       regmatch_t*  pRM = av + (c - (unsigned)'0');
228*c87b03e5Sespie       size_t len;
229*c87b03e5Sespie 
230*c87b03e5Sespie       if (pRM->rm_so < 0)
231*c87b03e5Sespie         continue;
232*c87b03e5Sespie 
233*c87b03e5Sespie       len = pRM->rm_eo - pRM->rm_so;
234*c87b03e5Sespie       if (len > 0)
235*c87b03e5Sespie         fwrite(text + pRM->rm_so, len, 1, stdout);
236*c87b03e5Sespie     }
237*c87b03e5Sespie   }
238*c87b03e5Sespie }
239*c87b03e5Sespie 
240*c87b03e5Sespie 
241*c87b03e5Sespie /*
242*c87b03e5Sespie  *  Search for multiple copies of a regular expression.  Each block
243*c87b03e5Sespie  *  of matched text is replaced with the format string, as described
244*c87b03e5Sespie  *  above in `format_write'.
245*c87b03e5Sespie  */
FIX_PROC_HEAD(format_fix)246*c87b03e5Sespie FIX_PROC_HEAD( format_fix )
247*c87b03e5Sespie {
248*c87b03e5Sespie   tCC*  pz_pat = p_fixd->patch_args[2];
249*c87b03e5Sespie   tCC*  pz_fmt = p_fixd->patch_args[1];
250*c87b03e5Sespie   regex_t re;
251*c87b03e5Sespie   regmatch_t rm[10];
252*c87b03e5Sespie   IGNORE_ARG(filname);
253*c87b03e5Sespie 
254*c87b03e5Sespie   /*
255*c87b03e5Sespie    *  We must have a format
256*c87b03e5Sespie    */
257*c87b03e5Sespie   if (pz_fmt == (tCC*)NULL)
258*c87b03e5Sespie     {
259*c87b03e5Sespie       fprintf( stderr, zNeedsArg, p_fixd->fix_name, "replacement format", 0 );
260*c87b03e5Sespie       exit (EXIT_BROKEN);
261*c87b03e5Sespie     }
262*c87b03e5Sespie 
263*c87b03e5Sespie   /*
264*c87b03e5Sespie    *  IF we don't have a search text, then go find the first
265*c87b03e5Sespie    *  regular expression among the tests.
266*c87b03e5Sespie    */
267*c87b03e5Sespie   if (pz_pat == (tCC*)NULL)
268*c87b03e5Sespie     {
269*c87b03e5Sespie       tTestDesc* pTD = p_fixd->p_test_desc;
270*c87b03e5Sespie       int        ct  = p_fixd->test_ct;
271*c87b03e5Sespie       for (;;)
272*c87b03e5Sespie         {
273*c87b03e5Sespie           if (ct-- <= 0)
274*c87b03e5Sespie             {
275*c87b03e5Sespie               fprintf( stderr, zNeedsArg, p_fixd->fix_name, "search text", 1 );
276*c87b03e5Sespie               exit (EXIT_BROKEN);
277*c87b03e5Sespie             }
278*c87b03e5Sespie 
279*c87b03e5Sespie           if (pTD->type == TT_EGREP)
280*c87b03e5Sespie             {
281*c87b03e5Sespie               pz_pat = pTD->pz_test_text;
282*c87b03e5Sespie               break;
283*c87b03e5Sespie             }
284*c87b03e5Sespie 
285*c87b03e5Sespie           pTD++;
286*c87b03e5Sespie         }
287*c87b03e5Sespie     }
288*c87b03e5Sespie 
289*c87b03e5Sespie   /*
290*c87b03e5Sespie    *  Replace every copy of the text we find
291*c87b03e5Sespie    */
292*c87b03e5Sespie   compile_re (pz_pat, &re, 1, "format search-text", "format_fix" );
293*c87b03e5Sespie   while (regexec (&re, text, 10, rm, 0) == 0)
294*c87b03e5Sespie     {
295*c87b03e5Sespie       fwrite( text, rm[0].rm_so, 1, stdout );
296*c87b03e5Sespie       format_write( pz_fmt, text, rm );
297*c87b03e5Sespie       text += rm[0].rm_eo;
298*c87b03e5Sespie     }
299*c87b03e5Sespie 
300*c87b03e5Sespie   /*
301*c87b03e5Sespie    *  Dump out the rest of the file
302*c87b03e5Sespie    */
303*c87b03e5Sespie   fputs (text, stdout);
304*c87b03e5Sespie }
305*c87b03e5Sespie 
306*c87b03e5Sespie 
307*c87b03e5Sespie /* Scan the input file for all occurrences of text like this:
308*c87b03e5Sespie 
309*c87b03e5Sespie    #define TIOCCONS _IO(T, 12)
310*c87b03e5Sespie 
311*c87b03e5Sespie    and change them to read like this:
312*c87b03e5Sespie 
313*c87b03e5Sespie    #define TIOCCONS _IO('T', 12)
314*c87b03e5Sespie 
315*c87b03e5Sespie    which is the required syntax per the C standard.  (The definition of
316*c87b03e5Sespie    _IO also has to be tweaked - see below.)  'IO' is actually whatever you
317*c87b03e5Sespie    provide as the `c_fix_arg' argument.  */
318*c87b03e5Sespie 
FIX_PROC_HEAD(char_macro_use_fix)319*c87b03e5Sespie FIX_PROC_HEAD( char_macro_use_fix )
320*c87b03e5Sespie {
321*c87b03e5Sespie   /* This regexp looks for a traditional-syntax #define (# in column 1)
322*c87b03e5Sespie      of an object-like macro.  */
323*c87b03e5Sespie   static const char pat[] =
324*c87b03e5Sespie     "^#[ \t]*define[ \t]+[_A-Za-z][_A-Za-z0-9]*[ \t]+";
325*c87b03e5Sespie   static regex_t re;
326*c87b03e5Sespie 
327*c87b03e5Sespie   const char* str = p_fixd->patch_args[1];
328*c87b03e5Sespie   regmatch_t rm[1];
329*c87b03e5Sespie   const char *p, *limit;
330*c87b03e5Sespie   size_t len;
331*c87b03e5Sespie   IGNORE_ARG(filname);
332*c87b03e5Sespie 
333*c87b03e5Sespie   if (str == NULL)
334*c87b03e5Sespie     {
335*c87b03e5Sespie       fprintf (stderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0);
336*c87b03e5Sespie       exit (EXIT_BROKEN);
337*c87b03e5Sespie     }
338*c87b03e5Sespie 
339*c87b03e5Sespie   len = strlen (str);
340*c87b03e5Sespie   compile_re (pat, &re, 1, "macro pattern", "char_macro_use_fix");
341*c87b03e5Sespie 
342*c87b03e5Sespie   for (p = text;
343*c87b03e5Sespie        regexec (&re, p, 1, rm, 0) == 0;
344*c87b03e5Sespie        p = limit + 1)
345*c87b03e5Sespie     {
346*c87b03e5Sespie       /* p + rm[0].rm_eo is the first character of the macro replacement.
347*c87b03e5Sespie 	 Find the end of the macro replacement, and the STR we were
348*c87b03e5Sespie 	 sent to look for within the replacement.  */
349*c87b03e5Sespie       p += rm[0].rm_eo;
350*c87b03e5Sespie       limit = p - 1;
351*c87b03e5Sespie       do
352*c87b03e5Sespie 	{
353*c87b03e5Sespie 	  limit = strchr (limit + 1, '\n');
354*c87b03e5Sespie 	  if (!limit)
355*c87b03e5Sespie 	    goto done;
356*c87b03e5Sespie 	}
357*c87b03e5Sespie       while (limit[-1] == '\\');
358*c87b03e5Sespie 
359*c87b03e5Sespie       do
360*c87b03e5Sespie 	{
361*c87b03e5Sespie 	  if (*p == str[0] && !strncmp (p+1, str+1, len-1))
362*c87b03e5Sespie 	    goto found;
363*c87b03e5Sespie 	}
364*c87b03e5Sespie       while (++p < limit - len);
365*c87b03e5Sespie       /* Hit end of line.  */
366*c87b03e5Sespie       continue;
367*c87b03e5Sespie 
368*c87b03e5Sespie     found:
369*c87b03e5Sespie       /* Found STR on this line.  If the macro needs fixing,
370*c87b03e5Sespie 	 the next few chars will be whitespace or uppercase,
371*c87b03e5Sespie 	 then an open paren, then a single letter.  */
372*c87b03e5Sespie       while ((ISSPACE (*p) || ISUPPER (*p)) && p < limit) p++;
373*c87b03e5Sespie       if (*p++ != '(')
374*c87b03e5Sespie 	continue;
375*c87b03e5Sespie       if (!ISALPHA (*p))
376*c87b03e5Sespie 	continue;
377*c87b03e5Sespie       if (ISIDNUM (p[1]))
378*c87b03e5Sespie 	continue;
379*c87b03e5Sespie 
380*c87b03e5Sespie       /* Splat all preceding text into the output buffer,
381*c87b03e5Sespie 	 quote the character at p, then proceed.  */
382*c87b03e5Sespie       fwrite (text, 1, p - text, stdout);
383*c87b03e5Sespie       putchar ('\'');
384*c87b03e5Sespie       putchar (*p);
385*c87b03e5Sespie       putchar ('\'');
386*c87b03e5Sespie       text = p + 1;
387*c87b03e5Sespie     }
388*c87b03e5Sespie  done:
389*c87b03e5Sespie   fputs (text, stdout);
390*c87b03e5Sespie }
391*c87b03e5Sespie 
392*c87b03e5Sespie 
393*c87b03e5Sespie /* Scan the input file for all occurrences of text like this:
394*c87b03e5Sespie 
395*c87b03e5Sespie    #define xxxIOxx(x, y) (....'x'<<16....)
396*c87b03e5Sespie 
397*c87b03e5Sespie    and change them to read like this:
398*c87b03e5Sespie 
399*c87b03e5Sespie    #define xxxIOxx(x, y) (....x<<16....)
400*c87b03e5Sespie 
401*c87b03e5Sespie    which is the required syntax per the C standard.  (The uses of _IO
402*c87b03e5Sespie    also has to be tweaked - see above.)  'IO' is actually whatever
403*c87b03e5Sespie    you provide as the `c_fix_arg' argument.  */
FIX_PROC_HEAD(char_macro_def_fix)404*c87b03e5Sespie FIX_PROC_HEAD( char_macro_def_fix )
405*c87b03e5Sespie {
406*c87b03e5Sespie   /* This regexp looks for any traditional-syntax #define (# in column 1).  */
407*c87b03e5Sespie   static const char pat[] =
408*c87b03e5Sespie     "^#[ \t]*define[ \t]+";
409*c87b03e5Sespie   static regex_t re;
410*c87b03e5Sespie 
411*c87b03e5Sespie   const char* str = p_fixd->patch_args[1];
412*c87b03e5Sespie   regmatch_t rm[1];
413*c87b03e5Sespie   const char *p, *limit;
414*c87b03e5Sespie   char arg;
415*c87b03e5Sespie   size_t len;
416*c87b03e5Sespie   IGNORE_ARG(filname);
417*c87b03e5Sespie 
418*c87b03e5Sespie   if (str == NULL)
419*c87b03e5Sespie     {
420*c87b03e5Sespie       fprintf (stderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0);
421*c87b03e5Sespie       exit (EXIT_BROKEN);
422*c87b03e5Sespie     }
423*c87b03e5Sespie 
424*c87b03e5Sespie   len = strlen (str);
425*c87b03e5Sespie   compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_defines");
426*c87b03e5Sespie 
427*c87b03e5Sespie   for (p = text;
428*c87b03e5Sespie        regexec (&re, p, 1, rm, 0) == 0;
429*c87b03e5Sespie        p = limit + 1)
430*c87b03e5Sespie     {
431*c87b03e5Sespie       /* p + rm[0].rm_eo is the first character of the macro name.
432*c87b03e5Sespie 	 Find the end of the macro replacement, and the STR we were
433*c87b03e5Sespie 	 sent to look for within the name.  */
434*c87b03e5Sespie       p += rm[0].rm_eo;
435*c87b03e5Sespie       limit = p - 1;
436*c87b03e5Sespie       do
437*c87b03e5Sespie 	{
438*c87b03e5Sespie 	  limit = strchr (limit + 1, '\n');
439*c87b03e5Sespie 	  if (!limit)
440*c87b03e5Sespie 	    goto done;
441*c87b03e5Sespie 	}
442*c87b03e5Sespie       while (limit[-1] == '\\');
443*c87b03e5Sespie 
444*c87b03e5Sespie       do
445*c87b03e5Sespie 	{
446*c87b03e5Sespie 	  if (*p == str[0] && !strncmp (p+1, str+1, len-1))
447*c87b03e5Sespie 	    goto found;
448*c87b03e5Sespie 	  p++;
449*c87b03e5Sespie 	}
450*c87b03e5Sespie       while (ISIDNUM (*p));
451*c87b03e5Sespie       /* Hit end of macro name without finding the string.  */
452*c87b03e5Sespie       continue;
453*c87b03e5Sespie 
454*c87b03e5Sespie     found:
455*c87b03e5Sespie       /* Found STR in this macro name.  If the macro needs fixing,
456*c87b03e5Sespie 	 there may be a few uppercase letters, then there will be an
457*c87b03e5Sespie 	 open paren with _no_ intervening whitespace, and then a
458*c87b03e5Sespie 	 single letter.  */
459*c87b03e5Sespie       while (ISUPPER (*p) && p < limit) p++;
460*c87b03e5Sespie       if (*p++ != '(')
461*c87b03e5Sespie 	continue;
462*c87b03e5Sespie       if (!ISALPHA (*p))
463*c87b03e5Sespie 	continue;
464*c87b03e5Sespie       if (ISIDNUM (p[1]))
465*c87b03e5Sespie 	continue;
466*c87b03e5Sespie 
467*c87b03e5Sespie       /* The character at P is the one to look for in the following
468*c87b03e5Sespie 	 text.  */
469*c87b03e5Sespie       arg = *p;
470*c87b03e5Sespie       p += 2;
471*c87b03e5Sespie 
472*c87b03e5Sespie       while (p < limit)
473*c87b03e5Sespie 	{
474*c87b03e5Sespie 	  if (p[-1] == '\'' && p[0] == arg && p[1] == '\'')
475*c87b03e5Sespie 	    {
476*c87b03e5Sespie 	      /* Remove the quotes from this use of ARG.  */
477*c87b03e5Sespie 	      p--;
478*c87b03e5Sespie 	      fwrite (text, 1, p - text, stdout);
479*c87b03e5Sespie 	      putchar (arg);
480*c87b03e5Sespie 	      p += 3;
481*c87b03e5Sespie 	      text = p;
482*c87b03e5Sespie 	    }
483*c87b03e5Sespie 	  else
484*c87b03e5Sespie 	    p++;
485*c87b03e5Sespie 	}
486*c87b03e5Sespie     }
487*c87b03e5Sespie  done:
488*c87b03e5Sespie   fputs (text, stdout);
489*c87b03e5Sespie }
490*c87b03e5Sespie 
491*c87b03e5Sespie /* Fix for machine name #ifdefs that are not in the namespace reserved
492*c87b03e5Sespie    by the C standard.  They won't be defined if compiling with -ansi,
493*c87b03e5Sespie    and the headers will break.  We go to some trouble to only change
494*c87b03e5Sespie    #ifdefs where the macro is defined by GCC in non-ansi mode; this
495*c87b03e5Sespie    minimizes the number of headers touched.  */
496*c87b03e5Sespie 
497*c87b03e5Sespie #define SCRATCHSZ 64   /* hopefully long enough */
498*c87b03e5Sespie 
FIX_PROC_HEAD(machine_name_fix)499*c87b03e5Sespie FIX_PROC_HEAD( machine_name_fix )
500*c87b03e5Sespie {
501*c87b03e5Sespie #ifndef MN_NAME_PAT
502*c87b03e5Sespie   fputs( "The target machine has no needed machine name fixes\n", stderr );
503*c87b03e5Sespie #else
504*c87b03e5Sespie   regmatch_t match[2];
505*c87b03e5Sespie   const char *line, *base, *limit, *p, *q;
506*c87b03e5Sespie   regex_t *label_re, *name_re;
507*c87b03e5Sespie   char scratch[SCRATCHSZ];
508*c87b03e5Sespie   size_t len;
509*c87b03e5Sespie   IGNORE_ARG(filname);
510*c87b03e5Sespie   IGNORE_ARG(p_fixd);
511*c87b03e5Sespie 
512*c87b03e5Sespie   mn_get_regexps (&label_re, &name_re, "machine_name_fix");
513*c87b03e5Sespie 
514*c87b03e5Sespie   scratch[0] = '_';
515*c87b03e5Sespie   scratch[1] = '_';
516*c87b03e5Sespie 
517*c87b03e5Sespie   for (base = text;
518*c87b03e5Sespie        regexec (label_re, base, 2, match, 0) == 0;
519*c87b03e5Sespie        base = limit)
520*c87b03e5Sespie     {
521*c87b03e5Sespie       base += match[0].rm_eo;
522*c87b03e5Sespie       /* We're looking at an #if or #ifdef.  Scan forward for the
523*c87b03e5Sespie          next non-escaped newline.  */
524*c87b03e5Sespie       line = limit = base;
525*c87b03e5Sespie       do
526*c87b03e5Sespie         {
527*c87b03e5Sespie           limit++;
528*c87b03e5Sespie           limit = strchr (limit, '\n');
529*c87b03e5Sespie           if (!limit)
530*c87b03e5Sespie             goto done;
531*c87b03e5Sespie         }
532*c87b03e5Sespie       while (limit[-1] == '\\');
533*c87b03e5Sespie 
534*c87b03e5Sespie       /* If the 'name_pat' matches in between base and limit, we have
535*c87b03e5Sespie          a bogon.  It is not worth the hassle of excluding comments
536*c87b03e5Sespie          because comments on #if/#ifdef lines are rare, and strings on
537*c87b03e5Sespie          such lines are illegal.
538*c87b03e5Sespie 
539*c87b03e5Sespie          REG_NOTBOL means 'base' is not at the beginning of a line, which
540*c87b03e5Sespie          shouldn't matter since the name_re has no ^ anchor, but let's
541*c87b03e5Sespie          be accurate anyway.  */
542*c87b03e5Sespie 
543*c87b03e5Sespie       for (;;)
544*c87b03e5Sespie         {
545*c87b03e5Sespie         again:
546*c87b03e5Sespie           if (base == limit)
547*c87b03e5Sespie             break;
548*c87b03e5Sespie 
549*c87b03e5Sespie           if (regexec (name_re, base, 1, match, REG_NOTBOL))
550*c87b03e5Sespie             goto done;  /* No remaining match in this file */
551*c87b03e5Sespie 
552*c87b03e5Sespie           /* Match; is it on the line?  */
553*c87b03e5Sespie           if (match[0].rm_eo > limit - base)
554*c87b03e5Sespie             break;
555*c87b03e5Sespie 
556*c87b03e5Sespie           p = base + match[0].rm_so;
557*c87b03e5Sespie           base += match[0].rm_eo;
558*c87b03e5Sespie 
559*c87b03e5Sespie           /* One more test: if on the same line we have the same string
560*c87b03e5Sespie              with the appropriate underscores, then leave it alone.
561*c87b03e5Sespie              We want exactly two leading and trailing underscores.  */
562*c87b03e5Sespie           if (*p == '_')
563*c87b03e5Sespie             {
564*c87b03e5Sespie               len = base - p - ((*base == '_') ? 2 : 1);
565*c87b03e5Sespie               q = p + 1;
566*c87b03e5Sespie             }
567*c87b03e5Sespie           else
568*c87b03e5Sespie             {
569*c87b03e5Sespie               len = base - p - ((*base == '_') ? 1 : 0);
570*c87b03e5Sespie               q = p;
571*c87b03e5Sespie             }
572*c87b03e5Sespie           if (len + 4 > SCRATCHSZ)
573*c87b03e5Sespie             abort ();
574*c87b03e5Sespie           memcpy (&scratch[2], q, len);
575*c87b03e5Sespie           len += 2;
576*c87b03e5Sespie           scratch[len++] = '_';
577*c87b03e5Sespie           scratch[len++] = '_';
578*c87b03e5Sespie 
579*c87b03e5Sespie           for (q = line; q <= limit - len; q++)
580*c87b03e5Sespie             if (*q == '_' && !strncmp (q, scratch, len))
581*c87b03e5Sespie               goto again;
582*c87b03e5Sespie 
583*c87b03e5Sespie           fwrite (text, 1, p - text, stdout);
584*c87b03e5Sespie           fwrite (scratch, 1, len, stdout);
585*c87b03e5Sespie 
586*c87b03e5Sespie           text = base;
587*c87b03e5Sespie         }
588*c87b03e5Sespie     }
589*c87b03e5Sespie  done:
590*c87b03e5Sespie #endif
591*c87b03e5Sespie   fputs (text, stdout);
592*c87b03e5Sespie }
593*c87b03e5Sespie 
594*c87b03e5Sespie 
FIX_PROC_HEAD(wrap_fix)595*c87b03e5Sespie FIX_PROC_HEAD( wrap_fix )
596*c87b03e5Sespie {
597*c87b03e5Sespie   tSCC   z_no_wrap_pat[] = "^#if.*__need_";
598*c87b03e5Sespie   static regex_t no_wrapping_re; /* assume zeroed data */
599*c87b03e5Sespie 
600*c87b03e5Sespie   tCC*   pz_name = NULL;
601*c87b03e5Sespie 
602*c87b03e5Sespie   if (no_wrapping_re.allocated == 0)
603*c87b03e5Sespie     compile_re( z_no_wrap_pat, &no_wrapping_re, 0, "no-wrap pattern",
604*c87b03e5Sespie                 "wrap-fix" );
605*c87b03e5Sespie 
606*c87b03e5Sespie   /*
607*c87b03e5Sespie    *  IF we do *not* match the no-wrap re, then we have a double negative.
608*c87b03e5Sespie    *  A double negative means YES.
609*c87b03e5Sespie    */
610*c87b03e5Sespie   if (regexec( &no_wrapping_re, text, 0, NULL, 0 ) != 0)
611*c87b03e5Sespie     {
612*c87b03e5Sespie       /*
613*c87b03e5Sespie        *  A single file can get wrapped more than once by different fixes.
614*c87b03e5Sespie        *  A single fix can wrap multiple files.  Therefore, guard with
615*c87b03e5Sespie        *  *both* the fix name and the file name.
616*c87b03e5Sespie        */
617*c87b03e5Sespie       size_t ln = strlen( filname ) + strlen( p_fixd->fix_name ) + 14;
618*c87b03e5Sespie       char*  pz = xmalloc( ln );
619*c87b03e5Sespie       pz_name = pz;
620*c87b03e5Sespie       sprintf( pz, "FIXINC_WRAP_%s-%s", filname, p_fixd->fix_name );
621*c87b03e5Sespie 
622*c87b03e5Sespie       for (pz += 12; 1; pz++) {
623*c87b03e5Sespie         char ch = *pz;
624*c87b03e5Sespie 
625*c87b03e5Sespie         if (ch == NUL)
626*c87b03e5Sespie           break;
627*c87b03e5Sespie 
628*c87b03e5Sespie         if (! ISALNUM( ch )) {
629*c87b03e5Sespie           *pz = '_';
630*c87b03e5Sespie         }
631*c87b03e5Sespie         else {
632*c87b03e5Sespie           *pz = TOUPPER( ch );
633*c87b03e5Sespie         }
634*c87b03e5Sespie       }
635*c87b03e5Sespie 
636*c87b03e5Sespie       printf( "#ifndef %s\n", pz_name );
637*c87b03e5Sespie       printf( "#define %s 1\n\n", pz_name );
638*c87b03e5Sespie     }
639*c87b03e5Sespie 
640*c87b03e5Sespie   if (p_fixd->patch_args[1] == (tCC*)NULL)
641*c87b03e5Sespie     fputs( text, stdout );
642*c87b03e5Sespie 
643*c87b03e5Sespie   else {
644*c87b03e5Sespie     fputs( p_fixd->patch_args[1], stdout );
645*c87b03e5Sespie     fputs( text, stdout );
646*c87b03e5Sespie     if (p_fixd->patch_args[2] != (tCC*)NULL)
647*c87b03e5Sespie       fputs( p_fixd->patch_args[2], stdout );
648*c87b03e5Sespie   }
649*c87b03e5Sespie 
650*c87b03e5Sespie   if (pz_name != NULL) {
651*c87b03e5Sespie     printf( "\n#endif  /* %s */\n", pz_name );
652*c87b03e5Sespie     free( (void*)pz_name );
653*c87b03e5Sespie   }
654*c87b03e5Sespie }
655*c87b03e5Sespie 
656*c87b03e5Sespie 
657*c87b03e5Sespie /*
658*c87b03e5Sespie  *  Search for multiple copies of a regular expression.  Each block
659*c87b03e5Sespie  *  of matched text is replaced with the format string, as described
660*c87b03e5Sespie  *  above in `format_write'.
661*c87b03e5Sespie  */
FIX_PROC_HEAD(gnu_type_fix)662*c87b03e5Sespie FIX_PROC_HEAD( gnu_type_fix )
663*c87b03e5Sespie {
664*c87b03e5Sespie   const char* pz_pat;
665*c87b03e5Sespie   regex_t    re;
666*c87b03e5Sespie   regmatch_t rm[GTYPE_SE_CT+1];
667*c87b03e5Sespie   IGNORE_ARG(filname);
668*c87b03e5Sespie 
669*c87b03e5Sespie   {
670*c87b03e5Sespie     tTestDesc* pTD = p_fixd->p_test_desc;
671*c87b03e5Sespie     int        ct  = p_fixd->test_ct;
672*c87b03e5Sespie     for (;;)
673*c87b03e5Sespie       {
674*c87b03e5Sespie         if (ct-- <= 0)
675*c87b03e5Sespie           {
676*c87b03e5Sespie             fprintf (stderr, zNeedsArg, p_fixd->fix_name, "search text", 1);
677*c87b03e5Sespie             exit (EXIT_BROKEN);
678*c87b03e5Sespie           }
679*c87b03e5Sespie 
680*c87b03e5Sespie         if (pTD->type == TT_EGREP)
681*c87b03e5Sespie           {
682*c87b03e5Sespie             pz_pat = pTD->pz_test_text;
683*c87b03e5Sespie             break;
684*c87b03e5Sespie           }
685*c87b03e5Sespie 
686*c87b03e5Sespie         pTD++;
687*c87b03e5Sespie       }
688*c87b03e5Sespie   }
689*c87b03e5Sespie 
690*c87b03e5Sespie   compile_re (pz_pat, &re, 1, "gnu type typedef", "gnu_type_fix");
691*c87b03e5Sespie 
692*c87b03e5Sespie   while (regexec (&re, text, GTYPE_SE_CT+1, rm, 0) == 0)
693*c87b03e5Sespie     {
694*c87b03e5Sespie       text = emit_gnu_type (text, rm);
695*c87b03e5Sespie     }
696*c87b03e5Sespie 
697*c87b03e5Sespie   /*
698*c87b03e5Sespie    *  Dump out the rest of the file
699*c87b03e5Sespie    */
700*c87b03e5Sespie   fputs (text, stdout);
701*c87b03e5Sespie }
702*c87b03e5Sespie 
703*c87b03e5Sespie 
704*c87b03e5Sespie /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
705*c87b03e5Sespie 
706*c87b03e5Sespie      test for fix selector
707*c87b03e5Sespie 
708*c87b03e5Sespie      THIS IS THE ONLY EXPORTED ROUTINE
709*c87b03e5Sespie 
710*c87b03e5Sespie */
711*c87b03e5Sespie void
apply_fix(p_fixd,filname)712*c87b03e5Sespie apply_fix( p_fixd, filname )
713*c87b03e5Sespie   tFixDesc* p_fixd;
714*c87b03e5Sespie   tCC* filname;
715*c87b03e5Sespie {
716*c87b03e5Sespie #define _FT_(n,p) { n, p },
717*c87b03e5Sespie   static fix_entry_t fix_table[] = { FIXUP_TABLE { NULL, NULL }};
718*c87b03e5Sespie #undef _FT_
719*c87b03e5Sespie #define FIX_TABLE_CT (ARRAY_SIZE (fix_table)-1)
720*c87b03e5Sespie 
721*c87b03e5Sespie   tCC* fixname = p_fixd->patch_args[0];
722*c87b03e5Sespie   char* buf;
723*c87b03e5Sespie   int ct = FIX_TABLE_CT;
724*c87b03e5Sespie   fix_entry_t* pfe = fix_table;
725*c87b03e5Sespie 
726*c87b03e5Sespie   for (;;)
727*c87b03e5Sespie     {
728*c87b03e5Sespie       if (strcmp (pfe->fix_name, fixname) == 0)
729*c87b03e5Sespie         break;
730*c87b03e5Sespie       if (--ct <= 0)
731*c87b03e5Sespie         {
732*c87b03e5Sespie           fprintf (stderr, "fixincl error:  the `%s' fix is unknown\n",
733*c87b03e5Sespie                    fixname );
734*c87b03e5Sespie           exit (EXIT_BROKEN);
735*c87b03e5Sespie         }
736*c87b03e5Sespie       pfe++;
737*c87b03e5Sespie     }
738*c87b03e5Sespie 
739*c87b03e5Sespie   buf = load_file_data (stdin);
740*c87b03e5Sespie   (*pfe->fix_proc)( filname, buf, p_fixd );
741*c87b03e5Sespie }
742*c87b03e5Sespie 
743*c87b03e5Sespie #ifdef SEPARATE_FIX_PROC
744*c87b03e5Sespie tSCC z_usage[] =
745*c87b03e5Sespie "USAGE: applyfix <fix-name> <file-to-fix> <file-source> <file-destination>\n";
746*c87b03e5Sespie tSCC z_reopen[] =
747*c87b03e5Sespie "FS error %d (%s) reopening %s as std%s\n";
748*c87b03e5Sespie 
749*c87b03e5Sespie int
main(argc,argv)750*c87b03e5Sespie main( argc, argv )
751*c87b03e5Sespie   int     argc;
752*c87b03e5Sespie   char**  argv;
753*c87b03e5Sespie {
754*c87b03e5Sespie   tFixDesc* pFix;
755*c87b03e5Sespie   char* pz_tmptmp;
756*c87b03e5Sespie   char* pz_tmp_base;
757*c87b03e5Sespie   char* pz_tmp_dot;
758*c87b03e5Sespie 
759*c87b03e5Sespie   if (argc != 5)
760*c87b03e5Sespie     {
761*c87b03e5Sespie     usage_failure:
762*c87b03e5Sespie       fputs (z_usage, stderr);
763*c87b03e5Sespie       return EXIT_FAILURE;
764*c87b03e5Sespie     }
765*c87b03e5Sespie 
766*c87b03e5Sespie   {
767*c87b03e5Sespie     char* pz = argv[1];
768*c87b03e5Sespie     long  idx;
769*c87b03e5Sespie 
770*c87b03e5Sespie     if (! ISDIGIT ( *pz ))
771*c87b03e5Sespie       goto usage_failure;
772*c87b03e5Sespie 
773*c87b03e5Sespie     idx = strtol (pz, &pz, 10);
774*c87b03e5Sespie     if ((*pz != NUL) || ((unsigned)idx >= FIX_COUNT))
775*c87b03e5Sespie       goto usage_failure;
776*c87b03e5Sespie     pFix = fixDescList + idx;
777*c87b03e5Sespie   }
778*c87b03e5Sespie 
779*c87b03e5Sespie   if (freopen (argv[3], "r", stdin) != stdin)
780*c87b03e5Sespie     {
781*c87b03e5Sespie       fprintf (stderr, z_reopen, errno, strerror( errno ), argv[3], "in");
782*c87b03e5Sespie       return EXIT_FAILURE;
783*c87b03e5Sespie     }
784*c87b03e5Sespie 
785*c87b03e5Sespie   pz_tmptmp = (char*)xmalloc( strlen( argv[4] ) + 5 );
786*c87b03e5Sespie   strcpy( pz_tmptmp, argv[4] );
787*c87b03e5Sespie 
788*c87b03e5Sespie   /* Don't lose because "12345678" and "12345678X" map to the same
789*c87b03e5Sespie      file under DOS restricted 8+3 file namespace.  Note that DOS
790*c87b03e5Sespie      doesn't allow more than one dot in the trunk of a file name.  */
791*c87b03e5Sespie   pz_tmp_base = basename( pz_tmptmp );
792*c87b03e5Sespie   pz_tmp_dot = strchr( pz_tmp_base, '.' );
793*c87b03e5Sespie   if (pathconf( pz_tmptmp, _PC_NAME_MAX ) <= 12	/* is this DOS or Windows9X? */
794*c87b03e5Sespie       && pz_tmp_dot != (char*)NULL)
795*c87b03e5Sespie     strcpy (pz_tmp_dot+1, "X"); /* nuke the original extension */
796*c87b03e5Sespie   else
797*c87b03e5Sespie     strcat (pz_tmptmp, ".X");
798*c87b03e5Sespie   if (freopen (pz_tmptmp, "w", stdout) != stdout)
799*c87b03e5Sespie     {
800*c87b03e5Sespie       fprintf (stderr, z_reopen, errno, strerror( errno ), pz_tmptmp, "out");
801*c87b03e5Sespie       return EXIT_FAILURE;
802*c87b03e5Sespie     }
803*c87b03e5Sespie 
804*c87b03e5Sespie   apply_fix (pFix, argv[1]);
805*c87b03e5Sespie   fclose (stdout);
806*c87b03e5Sespie   fclose (stdin);
807*c87b03e5Sespie   unlink (argv[4]);
808*c87b03e5Sespie   if (rename (pz_tmptmp, argv[4]) != 0)
809*c87b03e5Sespie     {
810*c87b03e5Sespie       fprintf (stderr, "error %d (%s) renaming %s to %s\n", errno,
811*c87b03e5Sespie                strerror( errno ), pz_tmptmp, argv[4]);
812*c87b03e5Sespie       return EXIT_FAILURE;
813*c87b03e5Sespie     }
814*c87b03e5Sespie 
815*c87b03e5Sespie   return EXIT_SUCCESS;
816*c87b03e5Sespie }
817*c87b03e5Sespie #endif
818