Bug Summary

File:build/fixincludes/fixfixes.c
Warning:line 166, column 10
Although the value stored to 'text' is used in the enclosing expression, the value is never actually read from 'text'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name fixfixes.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model static -mframe-pointer=none -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D HAVE_CONFIG_H -I . -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/fixincludes -I ../include -I /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/fixincludes/../include -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-overlength-strings -Wno-long-long -fconst-strings -fdebug-compilation-dir /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/build-x86_64-pc-linux-gnu/fixincludes -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=plist-html -analyzer-config silence-checkers=core.NullDereference -faddrsig -o /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/clang-static-analyzer/2021-01-16-135054-17580-1/report-ha4FX5.plist -x c /home/marxin/BIG/buildbot/buildworker/marxinbox-gcc-clang-static-analyzer/build/fixincludes/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, 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_CT1 1
54
55#ifdef SEPARATE_FIX_PROC
56#include "fixincl.x"
57#endif
58
59tSCCstatic const char 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_FT_( "char_macro_def", char_macro_def_fix ) _FT_( "char_macro_use"
, char_macro_use_fix ) _FT_( "format", format_fix ) _FT_( "machine_name"
, machine_name_fix ) _FT_( "wrap", wrap_fix ) _FT_( "gnu_type"
, gnu_type_fix )
\
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 )static void fix (const char* filname __attribute__ ((__unused__
)) , const char* text __attribute__ ((__unused__)) , tFixDesc
* p_fixd __attribute__ ((__unused__)) )
\
77static void fix (const char* filname ATTRIBUTE_UNUSED__attribute__ ((__unused__)) , \
78 const char* text ATTRIBUTE_UNUSED__attribute__ ((__unused__)) , \
79 tFixDesc* p_fixd ATTRIBUTE_UNUSED__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 )fputc_unlocked (q, stdout);
92
93 for (;;)
94 {
95 char ch = *(text++);
96 fputc( ch, stdout )fputc_unlocked (ch, stdout);
97
98 switch (ch)
99 {
100 case '\\':
101 if (*text == NUL'\0')
102 goto quote_done;
103
104 fputc( *(text++), stdout )fputc_unlocked (*(text++), stdout);
105 break;
106
107 case '"':
108 case '\'':
109 if (ch != q)
110 break;
111 /*FALLTHROUGH*/
112
113 case '\n':
114 case NUL'\0':
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)fwrite_unlocked (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++) )_sch_toupper[(*(pd++) = *(ps++)) & 0xff];
145
146 *pD = *pd = NUL'\0';
147 }
148
149 /*
150 * Now print out the reformed typedef,
151 * with a C++ guard for WCHAR
152 */
153 {
154 tSCCstatic const char 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;
Although the value stored to 'text' is used in the enclosing expression, the value is never actually read from 'text'
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 (tCCconst char* format, tCCconst char* text, regmatch_t av[] )
179{
180 int c;
181
182 while ((c = (unsigned)*(format++)) != NUL'\0') {
183
184 if (c != '%')
185 {
186 putchar(c)putchar_unlocked (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 )(_sch_istable[(c) & 0xff] & (unsigned short)(_sch_isdigit
))
)
199 {
200 putchar( '%' )putchar_unlocked ('%');
201 switch (c) {
202 case NUL'\0':
203 return;
204 case '%':
205 break;
206 default:
207 putchar(c)putchar_unlocked (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)fwrite_unlocked (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 )static void format_fix (const char* filname __attribute__ ((__unused__
)) , const char* text __attribute__ ((__unused__)) , tFixDesc
* p_fixd __attribute__ ((__unused__)) )
236{
237 tCCconst char* pz_pat = p_fixd->patch_args[2];
238 tCCconst char* pz_fmt = p_fixd->patch_args[1];
239 regex_t re;
240 regmatch_t rm[10];
241 IGNORE_ARG(filname)((void)(filname));
242
243 /*
244 * We must have a format
245 */
246 if (pz_fmt == (tCCconst char*)NULL((void*)0))
247 {
248 fprintf( stderrstderr, zNeedsArg, p_fixd->fix_name, "replacement format", 0 );
249 exit (EXIT_BROKEN3);
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 == (tCCconst char*)NULL((void*)0))
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( stderrstderr, zNeedsArg, p_fixd->fix_name, "search text", 1 );
265 exit (EXIT_BROKEN3);
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 )fwrite_unlocked (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)fputs_unlocked (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 )static void char_macro_use_fix (const char* filname __attribute__
((__unused__)) , const char* text __attribute__ ((__unused__
)) , tFixDesc* p_fixd __attribute__ ((__unused__)) )
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)((void)(filname));
321
322 if (str == NULL((void*)0))
323 {
324 fprintf (stderrstderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0);
325 exit (EXIT_BROKEN3);
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)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isspace
))
|| ISUPPER (*p)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isupper
))
) && p < limit) p++;
362 if (*p++ != '(')
363 continue;
364 if (!ISALPHA (*p)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isalpha
))
)
365 continue;
366 if (ISIDNUM (p[1])(_sch_istable[(p[1]) & 0xff] & (unsigned short)(_sch_isidnum
))
)
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)fwrite_unlocked (text, 1, p - text, stdout);
372 putchar ('\'')putchar_unlocked ('\'');
373 putchar (*p)putchar_unlocked (*p);
374 putchar ('\'')putchar_unlocked ('\'');
375 text = p + 1;
376 }
377 done:
378 fputs (text, stdout)fputs_unlocked (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 )static void char_macro_def_fix (const char* filname __attribute__
((__unused__)) , const char* text __attribute__ ((__unused__
)) , tFixDesc* p_fixd __attribute__ ((__unused__)) )
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)((void)(filname));
406
407 if (str == NULL((void*)0))
408 {
409 fprintf (stderrstderr, zNeedsArg, p_fixd->fix_name, "ioctl type", 0);
410 exit (EXIT_BROKEN3);
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)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isidnum
))
);
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)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isupper
))
&& p < limit) p++;
449 if (*p++ != '(')
450 continue;
451 if (!ISALPHA (*p)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isalpha
))
)
452 continue;
453 if (ISIDNUM (p[1])(_sch_istable[(p[1]) & 0xff] & (unsigned short)(_sch_isidnum
))
)
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)fwrite_unlocked (text, 1, p - text, stdout);
468 putchar (arg)putchar_unlocked (arg);
469 p += 3;
470 text = p;
471 }
472 else
473 p++;
474 }
475 }
476 done:
477 fputs (text, stdout)fputs_unlocked (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 SCRATCHSZ64 64 /* hopefully long enough */
487
488FIX_PROC_HEAD( machine_name_fix )static void machine_name_fix (const char* filname __attribute__
((__unused__)) , const char* text __attribute__ ((__unused__
)) , tFixDesc* p_fixd __attribute__ ((__unused__)) )
489{
490 regmatch_t match[2];
491 const char *line, *base, *limit, *p, *q;
492 regex_t *label_re, *name_re;
493 char scratch[SCRATCHSZ64];
494 size_t len;
495 IGNORE_ARG(filname)((void)(filname));
496 IGNORE_ARG(p_fixd)((void)(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 )fputs_unlocked ("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_NOTBOL1))
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 > SCRATCHSZ64)
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)fwrite_unlocked (text, 1, p - text, stdout);
574 fwrite (scratch, 1, len, stdout)fwrite_unlocked (scratch, 1, len, stdout);
575
576 text = base;
577 }
578 }
579 done:
580 fputs (text, stdout)fputs_unlocked (text, stdout);
581}
582
583
584FIX_PROC_HEAD( wrap_fix )static void wrap_fix (const char* filname __attribute__ ((__unused__
)) , const char* text __attribute__ ((__unused__)) , tFixDesc
* p_fixd __attribute__ ((__unused__)) )
585{
586 tSCCstatic const char z_no_wrap_pat[] = "^#if.*__need_";
587 static regex_t no_wrapping_re; /* assume zeroed data */
588
589 tCCconst char* pz_name = NULL((void*)0);
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((void*)0), 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)((char *) xmalloc (sizeof (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'\0')
615 break;
616
617 if (! ISALNUM( ch )(_sch_istable[(ch) & 0xff] & (unsigned short)(_sch_isalnum
))
) {
618 *pz = '_';
619 }
620 else {
621 *pz = TOUPPER( ch )_sch_toupper[(ch) & 0xff];
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] == (tCCconst char*)NULL((void*)0))
630 fputs( text, stdout )fputs_unlocked (text, stdout);
631
632 else {
633 fputs( p_fixd->patch_args[1], stdout )fputs_unlocked (p_fixd->patch_args[1], stdout);
634 fputs( text, stdout )fputs_unlocked (text, stdout);
635 if (p_fixd->patch_args[2] != (tCCconst char*)NULL((void*)0))
636 fputs( p_fixd->patch_args[2], stdout )fputs_unlocked (p_fixd->patch_args[2], stdout);
637 }
638
639 if (pz_name != NULL((void*)0)) {
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 )static void gnu_type_fix (const char* filname __attribute__ (
(__unused__)) , const char* text __attribute__ ((__unused__))
, tFixDesc* p_fixd __attribute__ ((__unused__)) )
652{
653 const char* pz_pat;
654 regex_t re;
655 regmatch_t rm[GTYPE_SE_CT1+1];
656 IGNORE_ARG(filname)((void)(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 (stderrstderr, zNeedsArg, p_fixd->fix_name, "search text", 1);
666 exit (EXIT_BROKEN3);
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_CT1+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)fputs_unlocked (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, tCCconst char* filname )
702{
703#define _FT_(n,p) { n, p },
704 static fix_entry_t fix_table[] = { FIXUP_TABLE_FT_( "char_macro_def", char_macro_def_fix ) _FT_( "char_macro_use"
, char_macro_use_fix ) _FT_( "format", format_fix ) _FT_( "machine_name"
, machine_name_fix ) _FT_( "wrap", wrap_fix ) _FT_( "gnu_type"
, gnu_type_fix )
{ NULL((void*)0), NULL((void*)0) }};
705#undef _FT_
706#define FIX_TABLE_CT((sizeof (fix_table) / sizeof ((fix_table)[0]))-1) (ARRAY_SIZE (fix_table)(sizeof (fix_table) / sizeof ((fix_table)[0]))-1)
707
708 tCCconst char* fixname = p_fixd->patch_args[0];
709 char* buf;
710 int ct = FIX_TABLE_CT((sizeof (fix_table) / sizeof ((fix_table)[0]))-1);
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 (stderrstderr, "fixincl error: the `%s' fix is unknown\n",
720 fixname );
721 exit (EXIT_BROKEN3);
722 }
723 pfe++;
724 }
725
726 buf = load_file_data (stdinstdin);
727 (*pfe->fix_proc)( filname, buf, p_fixd );
728}
729
730#ifdef SEPARATE_FIX_PROC
731tSCCstatic const char z_usage[] =
732"USAGE: applyfix <fix-name> <file-to-fix> <file-source> <file-destination>\n";
733tSCCstatic const char 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#ifdef _PC_NAME_MAX_PC_NAME_MAX
742 char* pz_tmp_base;
743 char* pz_tmp_dot;
744#endif
745
746 if (argc != 5)
747 {
748 usage_failure:
749 fputs (z_usage, stderr)fputs_unlocked (z_usage, stderr);
750 return EXIT_FAILURE1;
751 }
752
753 initialize_opts ();
754
755 {
756 char* pz = argv[1];
757 long idx;
758
759 if (! ISDIGIT ( *pz )(_sch_istable[(*pz) & 0xff] & (unsigned short)(_sch_isdigit
))
)
760 goto usage_failure;
761
762 idx = strtol (pz, &pz, 10);
763 if ((*pz != NUL'\0') || ((unsigned)idx >= FIX_COUNT))
764 goto usage_failure;
765 pFix = fixDescList + idx;
766 }
767
768 if (freopen (argv[3], "r", stdin)freopen_unlocked(argv[3],"r",stdin) != stdinstdin)
769 {
770 fprintf (stderrstderr, z_reopen, errno(*__errno_location ()), strerror( errno(*__errno_location ()) ), argv[3], "in");
771 return EXIT_FAILURE1;
772 }
773
774 pz_tmptmp = XNEWVEC (char, strlen (argv[4]) + 5)((char *) xmalloc (sizeof (char) * (strlen (argv[4]) + 5)));
775 strcpy( pz_tmptmp, argv[4] );
776
777#ifdef _PC_NAME_MAX_PC_NAME_MAX
778 /* Don't lose because "12345678" and "12345678X" map to the same
779 file under DOS restricted 8+3 file namespace. Note that DOS
780 doesn't allow more than one dot in the trunk of a file name. */
781 pz_tmp_base = basename( pz_tmptmp );
782 pz_tmp_dot = strchr( pz_tmp_base, '.' );
783 if (pathconf( pz_tmptmp, _PC_NAME_MAX_PC_NAME_MAX ) <= 12 /* is this DOS or Windows9X? */
784 && pz_tmp_dot != (char*)NULL((void*)0))
785 strcpy (pz_tmp_dot+1, "X"); /* nuke the original extension */
786 else
787#endif /* _PC_NAME_MAX */
788 strcat (pz_tmptmp, ".X");
789 if (freopen (pz_tmptmp, "w", stdout)freopen_unlocked(pz_tmptmp,"w",stdout) != stdoutstdout)
790 {
791 fprintf (stderrstderr, z_reopen, errno(*__errno_location ()), strerror( errno(*__errno_location ()) ), pz_tmptmp, "out");
792 return EXIT_FAILURE1;
793 }
794
795 /* Second parameter of apply_fix is file name */
796 apply_fix (pFix, argv[2]);
797 fclose (stdoutstdout);
798 fclose (stdinstdin);
799 unlink (argv[4]);
800 if (rename (pz_tmptmp, argv[4]) != 0)
801 {
802 fprintf (stderrstderr, "error %d (%s) renaming %s to %s\n", errno(*__errno_location ()),
803 strerror( errno(*__errno_location ()) ), pz_tmptmp, argv[4]);
804 return EXIT_FAILURE1;
805 }
806
807 return EXIT_SUCCESS0;
808}
809#endif