]> gcc.gnu.org Git - gcc.git/blame - gcc/fixinc/fixfixes.c
toplev.c (rest_of_compilation): Remove dead code after combine.
[gcc.git] / gcc / fixinc / fixfixes.c
CommitLineData
5abc1f74
BK
1
2/*
3
4 Test to see if a particular fix should be applied to a header file.
5
3852e8af 6 Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
5abc1f74
BK
7
8= = = = = = = = = = = = = = = = = = = = = = = = =
9
10NOTE TO DEVELOPERS
11
12The routines you write here must work closely with both the fixincl.c
13and the test_need.c program.
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(1)".
29
306. If "MAIN" is _not_ defined, then you have access to the fixDescList
31 entry for the fix in question. This may be useful, for example,
32 if there are pre-compiled selection expressions stored there.
33
34 For example, you may do this if you know that the first
35 test contains a useful regex. This is okay because, remember,
36 this code perforce works closely with the inclhack.def fixes!!
37
38
39 tFixDesc* pMyDesc = fixDescList + MY_FIX_NAME_FIXIDX;
40 tTestDesc* pTestList = pMyDesc->p_test_desc;
41
42 regexec (pTestList->p_test_regex, ...)
43
44
45 If MAIN _is_ defined, then you will have to compile it on
46 your own.
47
48= = = = = = = = = = = = = = = = = = = = = = = = =
49
50This file is part of GNU CC.
51
52GNU CC is free software; you can redistribute it and/or modify
53it under the terms of the GNU General Public License as published by
54the Free Software Foundation; either version 2, or (at your option)
55any later version.
56
57GNU CC is distributed in the hope that it will be useful,
58but WITHOUT ANY WARRANTY; without even the implied warranty of
59MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60GNU General Public License for more details.
61
62You should have received a copy of the GNU General Public License
63along with GNU CC; see the file COPYING. If not, write to
64the Free Software Foundation, 59 Temple Place - Suite 330,
65Boston, MA 02111-1307, USA. */
66
67#include "fixlib.h"
68
69typedef struct {
70 const char* fix_name;
71 void (*fix_proc)();
72} fix_entry_t;
73
74#define FIXUP_TABLE \
8f9ca912 75 _FT_( "no_double_slash", double_slash_fix ) \
5c0d5b94
ZW
76 _FT_( "else_endif_label", else_endif_label_fix ) \
77 _FT_( "IO_use", IO_use_fix ) \
78 _FT_( "CTRL_use", CTRL_use_fix) \
79 _FT_( "IO_defn", IO_defn_fix ) \
52c207e2
ZW
80 _FT_( "CTRL_defn", CTRL_defn_fix ) \
81 _FT_( "machine_name", machine_name_fix )
5abc1f74
BK
82
83
84#define FIX_PROC_HEAD( fix ) \
85static void fix ( filname, text ) \
86 const char* filname; \
87 char* text;
88
89
90/*
91 * Skip over a quoted string. Single quote strings may
92 * contain multiple characters if the first character is
93 * a backslash. Especially a backslash followed by octal digits.
94 * We are not doing a correctness syntax check here.
95 */
96static char*
97print_quote( q, text )
98 char q;
99 char* text;
100{
101 fputc( q, stdout );
102
103 for (;;)
104 {
105 char ch = *(text++);
106 fputc( ch, stdout );
107
108 switch (ch)
109 {
110 case '\\':
111 if (*text == NUL)
112 goto quote_done;
113
114 fputc( *(text++), stdout );
115 break;
116
117 case '"':
118 case '\'':
119 if (ch != q)
120 break;
121 /*FALLTHROUGH*/
122
123 case '\n':
124 case NUL:
125 goto quote_done;
126 }
127 } quote_done:;
128
129 return text;
130}
131
132
133FIX_PROC_HEAD( double_slash_fix )
134{
135 /* Now look for the comment markers in the text */
136 for (;;)
137 {
138 char ch = *(text++);
139 switch (ch)
140 {
141 case '/':
142 switch (*text) /* do not advance `text' here */
143 {
144 case '/':
145 /*
146 We found a "//" pair in open text.
147 Delete text to New-Line
148 */
149 while ((*text != '\n') && (*text != '\0')) text++;
150 break;
151
152 case '*':
153 {
154 /* We found a C-style comment. Skip forward to the end */
155 char* pz = strstr( (--text)+2, "*/" );
156 if (pz == (char*)NULL)
157 {
158 fputs( text, stdout );
159 goto fix_done;
160 }
161 pz += 2;
162 fwrite (text, (pz - text), 1, stdout );
163 text = pz;
164 }
165 break;
166
167 default:
168 fputc (ch, stdout );
169 }
170 break;
171
172 case NUL:
173 goto fix_done;
174
175 case '"':
176 case '\'':
177 text = print_quote (ch, text );
178 break;
179
180 default:
181 fputc (ch, stdout );
182 }
183
184 } fix_done:;
185
186 fclose (stdout);;
187}
188
8f9ca912
BK
189
190FIX_PROC_HEAD( else_endif_label_fix )
191{
192 static const char label_pat[] = "^[ \t]*#[ \t]*(else|endif)";
193 static regex_t label_re;
194
195 char ch;
196 char* pz_next = (char*)NULL;
197 regmatch_t match[2];
198
b51207a4
ZW
199 compile_re (label_pat, &label_re, 1,
200 "label pattern", "else_endif_label_fix");
8f9ca912
BK
201
202 for (;;) /* entire file */
203 {
204 /*
205 See if we need to advance to the next candidate directive
206 If the scanning pointer passes over the end of the directive,
207 then the directive is inside a comment */
208 if (pz_next < text)
209 {
210 if (regexec (&label_re, text, 2, match, 0) != 0)
211 {
212 fputs( text, stdout );
213 break;
214 }
215
216 pz_next = text + match[0].rm_eo;
217 }
218
219 /*
220 IF the scan pointer has not reached the directive end, ... */
221 if (pz_next > text)
222 {
223 /*
224 Advance the scanning pointer. If we are at the start
225 of a quoted string or a comment, then skip the entire unit */
226 ch = *text;
227
228 switch (ch)
229 {
230 case '/':
231 /*
232 Skip comments */
233 if (text[1] == '*')
234 {
235 char* pz = strstr( text+2, "*/" );
236 if (pz == (char*)NULL)
237 {
238 fputs( text, stdout );
239 return;
240 }
241 pz += 2;
242 fwrite( text, 1, (pz - text), stdout );
243 text = pz;
244 continue;
245 }
246 putc( ch, stdout );
247 text++;
248 break;
249
250 case '"':
251 case '\'':
252 text = print_quote( ch, text+1 );
253 break;
254
255 default:
256 putc( ch, stdout );
257 text++;
258 } /* switch (ch) */
259 continue;
260 } /* if (still shy of directive end) */
261
262 /*
263 The scanning pointer (text) has reached the end of the current
264 directive under test. Check for bogons here. */
265 for (;;) /* bogon check */
266 {
267 char ch = *(text++);
268 if (isspace (ch))
269 {
270 putc( ch, stdout );
271 if (ch == '\n')
272 {
273 /*
274 It is clean. No bogons on this directive */
275 pz_next = (char*)NULL; /* force a new regex search */
276 goto dont_fix_bogon;
277 }
278 continue;
279 }
280
281 switch (ch)
282 {
283 case NUL:
284 return;
285
286 case '\\':
287 /*
288 Skip escaped newlines. Otherwise, we have a bogon */
289 if (*text != '\n') {
290 text--;
291 goto fix_the_bogon;
292 }
293
294 /*
295 Emit the escaped newline and keep scanning for possible junk */
296 putc( '\\', stdout );
297 putc( '\n', stdout );
298 text++;
299 break;
300
301 case '/':
302 /*
303 Skip comments. Otherwise, we have a bogon */
304 if (*text == '*')
305 {
306 text--;
307 pz_next = strstr( text+2, "*/" );
308 if (pz_next == (char*)NULL)
309 {
310 putc( '\n', stdout );
311 return;
312 }
313 pz_next += 2;
314 fwrite( text, 1, (pz_next - text), stdout );
315 text = pz_next;
316 break;
317 }
318
8f9ca912
BK
319 /* FALLTHROUGH */
320
321 default:
322 /*
323 GOTTA BE A BOGON */
324 text--;
325 goto fix_the_bogon;
326 } /* switch (ch) */
327 } /* for (bogon check loop) */
328
329 fix_the_bogon:
330 /*
331 `text' points to the start of the bogus data */
332 for (;;)
333 {
334 /*
335 NOT an escaped newline. Find the end of line that
336 is not preceeded by an escape character: */
337 pz_next = strchr( text, '\n' );
338 if (pz_next == (char*)NULL)
339 {
340 putc( '\n', stdout );
341 return;
342 }
343
344 if (pz_next[-1] != '\\')
345 {
346 text = pz_next;
347 pz_next = (char*)NULL; /* force a new regex search */
348 break;
349 }
350
351 /*
352 The newline was escaped. We gotta keep going. */
353 text = pz_next + 1;
354 }
355
356 dont_fix_bogon:;
357 } /* for (entire file) loop */
358
359 return;
360}
361
5c0d5b94
ZW
362/* Scan the input file for all occurrences of text like this:
363
364 #define TIOCCONS _IO(T, 12)
365
366 and change them to read like this:
367
368 #define TIOCCONS _IO('T', 12)
369
370 which is the required syntax per the C standard. (The definition of
371 _IO also has to be tweaked - see below.) 'IO' is actually whatever you
372 provide in the STR argument. */
373void
374fix_char_macro_uses (text, str)
375 const char *text;
376 const char *str;
377{
378 /* This regexp looks for a traditional-syntax #define (# in column 1)
379 of an object-like macro. */
380 static const char pat[] =
3a2e9dd2 381 "^#[ \t]*define[ \t]+[_A-Za-z][_A-Za-z0-9]*[ \t]+";
5c0d5b94
ZW
382 static regex_t re;
383
384 regmatch_t rm[1];
385 const char *p, *limit;
386 size_t len = strlen (str);
387
388 compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_uses");
389
390 for (p = text;
391 regexec (&re, p, 1, rm, 0) == 0;
392 p = limit + 1)
393 {
394 /* p + rm[0].rm_eo is the first character of the macro replacement.
395 Find the end of the macro replacement, and the STR we were
396 sent to look for within the replacement. */
397 p += rm[0].rm_eo;
398 limit = p - 1;
399 do
400 {
401 limit = strchr (limit + 1, '\n');
402 if (!limit)
403 goto done;
404 }
405 while (limit[-1] == '\\');
406
407 do
408 {
409 if (*p == str[0] && !strncmp (p+1, str+1, len-1))
410 goto found;
411 }
412 while (++p < limit - len);
413 /* Hit end of line. */
414 continue;
415
416 found:
417 /* Found STR on this line. If the macro needs fixing,
418 the next few chars will be whitespace or uppercase,
419 then an open paren, then a single letter. */
420 while ((isspace (*p) || isupper (*p)) && p < limit) p++;
421 if (*p++ != '(')
422 continue;
423 if (!isalpha (*p))
424 continue;
425 if (isalnum (p[1]) || p[1] == '_')
426 continue;
427
428 /* Splat all preceding text into the output buffer,
429 quote the character at p, then proceed. */
430 fwrite (text, 1, p - text, stdout);
431 putchar ('\'');
432 putchar (*p);
433 putchar ('\'');
434 text = p + 1;
435 }
436 done:
437 fputs (text, stdout);
438}
439
440/* Scan the input file for all occurrences of text like this:
441
442 #define _IO(x, y) ('x'<<16+y)
443
444 and change them to read like this:
445
446 #define _IO(x, y) (x<<16+y)
447
448 which is the required syntax per the C standard. (The uses of _IO
449 also have to be tweaked - see above.) 'IO' is actually whatever
450 you provide in the STR argument. */
451void
452fix_char_macro_defines (text, str)
453 const char *text;
454 const char *str;
455{
456 /* This regexp looks for any traditional-syntax #define (# in column 1). */
457 static const char pat[] =
458 "^#[ \t]*define[ \t]+";
459 static regex_t re;
460
461 regmatch_t rm[1];
462 const char *p, *limit;
463 size_t len = strlen (str);
464 char arg;
465
466 compile_re (pat, &re, 1, "macro pattern", "fix_char_macro_defines");
467
468 for (p = text;
469 regexec (&re, p, 1, rm, 0) == 0;
470 p = limit + 1)
471 {
472 /* p + rm[0].rm_eo is the first character of the macro name.
473 Find the end of the macro replacement, and the STR we were
474 sent to look for within the name. */
475 p += rm[0].rm_eo;
476 limit = p - 1;
477 do
478 {
479 limit = strchr (limit + 1, '\n');
480 if (!limit)
481 goto done;
482 }
483 while (limit[-1] == '\\');
484
485 do
486 {
487 if (*p == str[0] && !strncmp (p+1, str+1, len-1))
488 goto found;
3a2e9dd2 489 p++;
5c0d5b94
ZW
490 }
491 while (isalpha (*p) || isalnum (*p) || *p == '_');
492 /* Hit end of macro name without finding the string. */
493 continue;
494
495 found:
496 /* Found STR in this macro name. If the macro needs fixing,
497 there may be a few uppercase letters, then there will be an
498 open paren with _no_ intervening whitespace, and then a
499 single letter. */
500 while (isupper (*p) && p < limit) p++;
501 if (*p++ != '(')
502 continue;
503 if (!isalpha (*p))
504 continue;
505 if (isalnum (p[1]) || p[1] == '_')
506 continue;
507
508 /* The character at P is the one to look for in the following
509 text. */
510 arg = *p;
511 p += 2;
512
513 while (p < limit)
514 {
515 if (p[-1] == '\'' && p[0] == arg && p[1] == '\'')
516 {
517 /* Remove the quotes from this use of ARG. */
518 p--;
519 fwrite (text, 1, p - text, stdout);
520 putchar (arg);
521 p += 3;
522 text = p;
523 }
524 else
525 p++;
526 }
527 }
528 done:
529 fputs (text, stdout);
530}
531
532/* The various prefixes on these macros are handled automatically
533 because the fixers don't care where they start matching. */
534FIX_PROC_HEAD( IO_use_fix )
535{
536 fix_char_macro_uses (text, "IO");
537}
538FIX_PROC_HEAD( CTRL_use_fix )
539{
540 fix_char_macro_uses (text, "CTRL");
541}
542
543FIX_PROC_HEAD( IO_defn_fix )
544{
545 fix_char_macro_defines (text, "IO");
546}
547FIX_PROC_HEAD( CTRL_defn_fix )
548{
549 fix_char_macro_defines (text, "CTRL");
550}
551
552
52c207e2
ZW
553/* Fix for machine name #ifdefs that are not in the namespace reserved
554 by the C standard. They won't be defined if compiling with -ansi,
555 and the headers will break. We go to some trouble to only change
556 #ifdefs where the macro is defined by GCC in non-ansi mode; this
557 minimizes the number of headers touched. */
558
559#define SCRATCHSZ 64 /* hopefully long enough */
560
561FIX_PROC_HEAD( machine_name_fix )
562{
bff0dc38
BK
563#ifndef MN_NAME_PAT
564 fputs( "The target machine has no needed machine name fixes\n", stderr );
565#else
52c207e2
ZW
566 regmatch_t match[2];
567 char *line, *base, *limit, *p, *q;
568 regex_t *label_re, *name_re;
569 char scratch[SCRATCHSZ];
570 size_t len;
571
bff0dc38 572 mn_get_regexps (&label_re, &name_re, "machine_name_fix");
78a0d70c 573
52c207e2
ZW
574 scratch[0] = '_';
575 scratch[1] = '_';
576
577 for (base = text;
578 regexec (label_re, base, 2, match, 0) == 0;
579 base = limit)
580 {
581 base += match[0].rm_eo;
582 /* We're looking at an #if or #ifdef. Scan forward for the
583 next non-escaped newline. */
584 line = limit = base;
585 do
586 {
587 limit++;
588 limit = strchr (limit, '\n');
589 if (!limit)
590 goto done;
591 }
592 while (limit[-1] == '\\');
593
594 /* If the 'name_pat' matches in between base and limit, we have
595 a bogon. It is not worth the hassle of excluding comments
596 because comments on #if/#ifdef lines are rare, and strings on
597 such lines are illegal.
598
599 REG_NOTBOL means 'base' is not at the beginning of a line, which
600 shouldn't matter since the name_re has no ^ anchor, but let's
601 be accurate anyway. */
602
603 for (;;)
604 {
605 again:
606 if (base == limit)
607 break;
608
609 if (regexec (name_re, base, 1, match, REG_NOTBOL))
610 goto done; /* No remaining match in this file */
611
612 /* Match; is it on the line? */
613 if (match[0].rm_eo > limit - base)
614 break;
615
616 p = base + match[0].rm_so;
617 base += match[0].rm_eo;
618
619 /* One more test: if on the same line we have the same string
620 with the appropriate underscores, then leave it alone.
621 We want exactly two leading and trailing underscores. */
622 if (*p == '_')
623 {
624 len = base - p - ((*base == '_') ? 2 : 1);
625 q = p + 1;
626 }
627 else
628 {
629 len = base - p - ((*base == '_') ? 1 : 0);
630 q = p;
631 }
632 if (len + 4 > SCRATCHSZ)
633 abort ();
634 memcpy (&scratch[2], q, len);
635 len += 2;
636 scratch[len++] = '_';
637 scratch[len++] = '_';
638
639 for (q = line; q <= limit - len; q++)
640 if (*q == '_' && !strncmp (q, scratch, len))
641 goto again;
642
643 fwrite (text, 1, p - text, stdout);
644 fwrite (scratch, 1, len, stdout);
645
646 text = base;
647 }
648 }
649 done:
bff0dc38 650#endif
52c207e2 651 fputs (text, stdout);
52c207e2
ZW
652}
653
654
5abc1f74
BK
655/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
656
657 test for fix selector
658
659 THIS IS THE ONLY EXPORTED ROUTINE
660
661*/
662void
663apply_fix( fixname, filname )
664 const char* fixname;
665 const char* filname;
666{
99d525c9 667#define _FT_(n,p) { n, p },
5abc1f74 668 static fix_entry_t fix_table[] = { FIXUP_TABLE { NULL, NULL }};
99d525c9
PDM
669#undef _FT_
670#define FIX_TABLE_CT ((sizeof(fix_table)/sizeof(fix_table[0]))-1)
5abc1f74
BK
671
672 char* buf;
673 int ct = FIX_TABLE_CT;
674 fix_entry_t* pfe = fix_table;
675
676 for (;;)
677 {
678 if (strcmp (pfe->fix_name, fixname) == 0)
679 break;
680 if (--ct <= 0)
8f9ca912
BK
681 {
682 fprintf (stderr, "fixincludes error: the `%s' fix is unknown\n",
683 fixname );
684 exit (3);
685 }
686 pfe++;
5abc1f74
BK
687 }
688
689 buf = load_file_data (stdin);
690 (*pfe->fix_proc)( filname, buf );
691}
692
693#ifdef MAIN
694
695/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
696
697 MAIN ROUTINE
698
699 This file is both included in fixincl.c and compiled as a separate
700 program for use by the inclhack.sh script.
701
702*/
703
704int
705main( argc, argv )
706 int argc;
707 char** argv;
708{
709 if (argc != 3)
710 apply_fix ("No test name provided", NULL, NULL, 0 );
711
712 apply_fix (argv[2], argv[1]);
713 return 0;
714}
715
716#endif
This page took 0.231647 seconds and 5 git commands to generate.