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