]>
Commit | Line | Data |
---|---|---|
5abc1f74 BK |
1 | |
2 | /* | |
3 | ||
4 | Test to see if a particular fix should be applied to a header file. | |
5 | ||
b51207a4 | 6 | Copyright (C) 1997-1999, 2000 Free Software Foundation, Inc. |
5abc1f74 BK |
7 | |
8 | = = = = = = = = = = = = = = = = = = = = = = = = = | |
9 | ||
10 | NOTE TO DEVELOPERS | |
11 | ||
12 | The routines you write here must work closely with both the fixincl.c | |
13 | and the test_need.c program. | |
14 | ||
15 | Here are the rules: | |
16 | ||
17 | 1. Every test procedure name must be suffixed with "_test". | |
18 | These routines will be referenced from inclhack.def, sans the suffix. | |
19 | ||
20 | 2. Use the "TEST_FOR_FIX_PROC_HEAD()" macro _with_ the "_test" suffix | |
21 | (I cannot use the ## magic from ANSI C) for defining your entry point. | |
22 | ||
23 | 3. Put your test name into the FIX_TEST_TABLE | |
24 | ||
25 | 4. Do not write anything to stdout. It may be closed. | |
26 | ||
27 | 5. Write to stderr only in the event of a reportable error | |
28 | In such an event, call "exit(1)". | |
29 | ||
30 | = = = = = = = = = = = = = = = = = = = = = = = = = | |
31 | ||
32 | This file is part of GNU CC. | |
33 | ||
34 | GNU CC is free software; you can redistribute it and/or modify | |
35 | it under the terms of the GNU General Public License as published by | |
36 | the Free Software Foundation; either version 2, or (at your option) | |
37 | any later version. | |
38 | ||
39 | GNU CC is distributed in the hope that it will be useful, | |
40 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
41 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
42 | GNU General Public License for more details. | |
43 | ||
44 | You should have received a copy of the GNU General Public License | |
45 | along with GNU CC; see the file COPYING. If not, write to | |
46 | the Free Software Foundation, 59 Temple Place - Suite 330, | |
47 | Boston, MA 02111-1307, USA. */ | |
48 | ||
49 | #include "fixlib.h" | |
50 | ||
5abc1f74 BK |
51 | #define SHOULD_APPLY(afp) ((afp) == APPLY_FIX) |
52 | apply_fix_p_t run_test(); | |
53 | ||
54 | typedef struct { | |
87ad679b | 55 | tCC* test_name; |
5abc1f74 BK |
56 | apply_fix_p_t (*test_proc)(); |
57 | } test_entry_t; | |
58 | ||
59 | #define FIX_TEST_TABLE \ | |
8f9ca912 BK |
60 | _FT_( "double_slash", double_slash_test ) \ |
61 | _FT_( "else_endif_label", else_endif_label_test ) | |
5abc1f74 BK |
62 | |
63 | ||
64 | #define TEST_FOR_FIX_PROC_HEAD( test ) \ | |
65 | static apply_fix_p_t test ( fname, text ) \ | |
87ad679b BK |
66 | tCC* fname; \ |
67 | tCC* text; | |
5abc1f74 BK |
68 | |
69 | /* | |
70 | * Skip over a quoted string. Single quote strings may | |
71 | * contain multiple characters if the first character is | |
72 | * a backslash. Especially a backslash followed by octal digits. | |
73 | * We are not doing a correctness syntax check here. | |
74 | */ | |
87ad679b | 75 | tSCC* |
5abc1f74 BK |
76 | skip_quote( q, text ) |
77 | char q; | |
78 | char* text; | |
79 | { | |
80 | for (;;) | |
81 | { | |
82 | char ch = *(text++); | |
83 | switch (ch) | |
84 | { | |
85 | case '\\': | |
86 | text++; /* skip over whatever character follows */ | |
87 | break; | |
88 | ||
89 | case '"': | |
90 | case '\'': | |
91 | if (ch != q) | |
92 | break; | |
93 | /*FALLTHROUGH*/ | |
94 | ||
95 | case '\n': | |
96 | case NUL: | |
97 | goto skip_done; | |
98 | } | |
99 | } skip_done:; | |
100 | ||
101 | return text; | |
102 | } | |
103 | ||
d7eb5a45 ZW |
104 | |
105 | TEST_FOR_FIX_PROC_HEAD( double_slash_test ) | |
106 | { | |
87ad679b | 107 | if (is_cxx_header (fname, text)) |
d7eb5a45 ZW |
108 | return SKIP_FIX; |
109 | ||
5abc1f74 BK |
110 | /* Now look for the comment markers in the text */ |
111 | for (;;) | |
112 | { | |
113 | char ch = *(text++); | |
114 | switch (ch) | |
115 | { | |
116 | case '/': | |
117 | switch (*text) /* do not advance `text' here */ | |
118 | { | |
119 | case '/': | |
120 | /* | |
121 | We found a "//" pair in open text. | |
122 | The fix must be applied | |
123 | */ | |
124 | return APPLY_FIX; | |
125 | ||
126 | case '*': | |
127 | /* We found a C-style comment. Skip forward to the end */ | |
128 | text = strstr( text+1, "*/" ); | |
129 | if (text == (char*)NULL) | |
130 | goto test_done; | |
131 | text += 2; | |
132 | } | |
133 | break; | |
134 | ||
135 | case NUL: | |
136 | goto test_done; | |
137 | ||
138 | case '"': | |
139 | case '\'': | |
140 | text = skip_quote( ch, text ); | |
141 | } | |
142 | ||
143 | } test_done:; | |
144 | ||
145 | return SKIP_FIX; | |
146 | } | |
147 | ||
8f9ca912 BK |
148 | |
149 | TEST_FOR_FIX_PROC_HEAD( else_endif_label_test ) | |
150 | { | |
151 | static int compiled = 0; | |
87ad679b | 152 | tSCC label_pat[] = "^[ \t]*#[ \t]*(else|endif)"; |
8f9ca912 BK |
153 | static regex_t label_re; |
154 | ||
155 | char ch; | |
87ad679b | 156 | tCC* pz_next = (char*)NULL; |
8f9ca912 | 157 | regmatch_t match[2]; |
87ad679b | 158 | t_bool file_is_cxx = is_cxx_header( fname, text ); |
8f9ca912 BK |
159 | |
160 | /* | |
161 | This routine may be run many times within a single execution. | |
162 | Do the compile once only in that case. In the standalone case, | |
163 | we waste 10 bytes of memory and a test, branch and increment delay. */ | |
164 | if (! compiled) | |
165 | { | |
166 | compiled++; | |
b51207a4 ZW |
167 | compile_re (label_pat, &label_re, 1, |
168 | "label pattern", "else_endif_label_test"); | |
8f9ca912 BK |
169 | } |
170 | ||
171 | for (;;) /* entire file */ | |
172 | { | |
173 | /* | |
174 | See if we need to advance to the next candidate directive | |
175 | If the scanning pointer passes over the end of the directive, | |
176 | then the directive is inside a comment */ | |
177 | if (pz_next < text) | |
178 | { | |
179 | if (regexec (&label_re, text, 2, match, 0) != 0) | |
180 | break; | |
181 | pz_next = text + match[0].rm_eo; | |
182 | } | |
183 | ||
184 | /* | |
185 | IF the scan pointer has not reached the directive end, ... */ | |
186 | if (pz_next > text) | |
187 | { | |
188 | /* | |
189 | Advance the scanning pointer. If we are at the start | |
190 | of a quoted string or a comment, then skip the entire unit */ | |
191 | ch = *(text++); | |
192 | ||
193 | switch (ch) | |
194 | { | |
195 | case '/': | |
196 | /* | |
197 | Skip comments */ | |
198 | if (*text == '*') | |
199 | { | |
200 | text = strstr( text+1, "*/" ); | |
201 | if (text == (char*)NULL) | |
202 | return SKIP_FIX; | |
203 | text += 2; | |
204 | continue; | |
205 | } | |
206 | break; | |
207 | ||
208 | case '"': | |
209 | case '\'': | |
210 | text = skip_quote( ch, text ); | |
211 | break; | |
212 | } /* switch (ch) */ | |
213 | continue; | |
214 | } /* if (still shy of directive end) */ | |
215 | ||
216 | /* | |
217 | The scanning pointer (text) has reached the end of the current | |
218 | directive under test, then check for bogons here */ | |
219 | for (;;) /* bogon check */ | |
220 | { | |
221 | char ch = *(pz_next++); | |
222 | if (isspace (ch)) | |
223 | { | |
224 | if (ch == '\n') | |
225 | { | |
226 | /* | |
227 | It is clean. No bogons on this directive */ | |
228 | text = pz_next; | |
229 | pz_next = (char*)NULL; /* force a new regex search */ | |
230 | break; | |
231 | } | |
232 | continue; | |
233 | } | |
234 | ||
235 | switch (ch) | |
236 | { | |
237 | case '\\': | |
238 | /* | |
239 | Skip escaped newlines. Otherwise, we have a bogon */ | |
240 | if (*pz_next != '\n') | |
241 | return APPLY_FIX; | |
242 | ||
243 | pz_next++; | |
244 | break; | |
245 | ||
246 | case '/': | |
247 | /* | |
248 | Skip comments. Otherwise, we have a bogon */ | |
87ad679b | 249 | switch (*pz_next) |
8f9ca912 | 250 | { |
87ad679b BK |
251 | case '/': |
252 | /* IF we found a "//" in a C header, THEN fix it. */ | |
253 | if (! file_is_cxx) | |
254 | return APPLY_FIX; | |
255 | ||
256 | /* C++ header. Skip to newline and continue. */ | |
257 | pz_next = strchr( pz_next+1, '\n' ); | |
258 | if (pz_next == (char*)NULL) | |
259 | return SKIP_FIX; | |
260 | pz_next++; | |
261 | break; | |
262 | ||
263 | case '*': | |
264 | /* A comment for either C++ or C. Skip over it. */ | |
8f9ca912 BK |
265 | pz_next = strstr( pz_next+1, "*/" ); |
266 | if (pz_next == (char*)NULL) | |
267 | return SKIP_FIX; | |
268 | pz_next += 2; | |
269 | break; | |
87ad679b BK |
270 | |
271 | default: | |
272 | /* a '/' followed by other junk. */ | |
273 | return APPLY_FIX; | |
8f9ca912 | 274 | } |
87ad679b | 275 | break; /* a C or C++ comment */ |
8f9ca912 BK |
276 | |
277 | default: | |
278 | /* | |
279 | GOTTA BE A BOGON */ | |
280 | return APPLY_FIX; | |
281 | } /* switch (ch) */ | |
282 | } /* for (bogon check loop) */ | |
283 | } /* for (entire file) loop */ | |
284 | ||
285 | return SKIP_FIX; | |
286 | } | |
287 | ||
5abc1f74 BK |
288 | /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = |
289 | ||
290 | test for fix selector | |
291 | ||
292 | THIS IS THE ONLY EXPORTED ROUTINE | |
293 | ||
294 | */ | |
295 | apply_fix_p_t | |
296 | run_test( tname, fname, text ) | |
87ad679b BK |
297 | tCC* tname; |
298 | tCC* fname; | |
299 | tCC* text; | |
5abc1f74 | 300 | { |
99d525c9 | 301 | #define _FT_(n,p) { n, p }, |
5abc1f74 | 302 | static test_entry_t test_table[] = { FIX_TEST_TABLE { NULL, NULL }}; |
99d525c9 PDM |
303 | #undef _FT_ |
304 | #define TEST_TABLE_CT ((sizeof(test_table)/sizeof(test_table[0]))-1) | |
5abc1f74 BK |
305 | |
306 | int ct = TEST_TABLE_CT; | |
307 | test_entry_t* pte = test_table; | |
308 | ||
309 | do | |
310 | { | |
311 | if (strcmp( pte->test_name, tname ) == 0) | |
312 | return (*pte->test_proc)( fname, text ); | |
8f9ca912 | 313 | pte++; |
5abc1f74 BK |
314 | } while (--ct > 0); |
315 | fprintf( stderr, "fixincludes error: the `%s' fix test is unknown\n", | |
316 | tname ); | |
317 | exit( 3 ); | |
318 | } | |
319 | ||
320 | /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = | |
321 | ||
322 | MAIN ROUTINE | |
323 | ||
324 | This file is both included in fixincl.c and compiled as a separate | |
325 | program for use by the inclhack.sh script. | |
326 | ||
327 | */ | |
328 | ||
329 | #ifdef MAIN | |
330 | ||
331 | int | |
332 | main( argc, argv ) | |
333 | int argc; | |
334 | char** argv; | |
335 | { | |
336 | char* fname = *++argv; | |
337 | char* tname = *++argv; | |
338 | char* buf; | |
5abc1f74 BK |
339 | |
340 | if (argc != 3) | |
341 | return run_test( "No test name provided", NULL, NULL, 0 ); | |
342 | ||
343 | fclose( stdin ); | |
344 | fclose( stdout ); | |
345 | ||
346 | buf = load_file_data (fopen (fname, "r")); | |
347 | ||
348 | return run_test( tname, fname, buf ); | |
349 | } | |
350 | ||
351 | #endif |