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-suse-linux -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name fixfixes.c -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 pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/buildworker/marxinbox-gcc-clang-static-analyzer/objdir/build-x86_64-pc-linux-gnu/fixincludes -resource-dir /usr/lib64/clang/15.0.7 -D HAVE_CONFIG_H -I . -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/fixincludes -I ../include -I /buildworker/marxinbox-gcc-clang-static-analyzer/build/fixincludes/../include -internal-isystem /usr/lib64/clang/15.0.7/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib64/gcc/x86_64-suse-linux/13/../../../../x86_64-suse-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-overlength-strings -Wno-long-long -fconst-strings -fdebug-compilation-dir=/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 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /buildworker/marxinbox-gcc-clang-static-analyzer/objdir/clang-static-analyzer/2023-03-27-141847-20772-1/report-JrkH13.plist -x c /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/* Check if the pattern at pos is actually in a "__has_include(...)"
481 directive. Return the pointer to the ')' of this
482 "__has_include(...)" if it is, NULL otherwise. */
483static const char *
484check_has_inc (const char *begin, const char *pos, const char *end)
485{
486 static const char has_inc[] = "__has_include";
487 const size_t has_inc_len = sizeof (has_inc) - 1;
488 const char *p;
489
490 for (p = memmem (begin, pos - begin, has_inc, has_inc_len);
491 p != NULL((void*)0);
492 p = memmem (p, pos - p, has_inc, has_inc_len))
493 {
494 p += has_inc_len;
495 while (p < end && ISSPACE (*p)(_sch_istable[(*p) & 0xff] & (unsigned short)(_sch_isspace
))
)
496 p++;
497
498 /* "__has_include" may appear as "defined(__has_include)",
499 search for the next appearance then. */
500 if (*p != '(')
501 continue;
502
503 /* To avoid too much complexity, just hope there is never a
504 ')' in a header name. */
505 p = memchr (p, ')', end - p);
506 if (p == NULL((void*)0) || p > pos)
507 return p;
508 }
509
510 return NULL((void*)0);
511}
512
513/* Fix for machine name #ifdefs that are not in the namespace reserved
514 by the C standard. They won't be defined if compiling with -ansi,
515 and the headers will break. We go to some trouble to only change
516 #ifdefs where the macro is defined by GCC in non-ansi mode; this
517 minimizes the number of headers touched. */
518
519#define SCRATCHSZ64 64 /* hopefully long enough */
520
521FIX_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__)) )
522{
523 regmatch_t match[2];
524 const char *line, *base, *limit, *p, *q;
525 regex_t *label_re, *name_re;
526 char scratch[SCRATCHSZ64];
527 size_t len;
528 IGNORE_ARG(filname)((void)(filname));
529 IGNORE_ARG(p_fixd)((void)(p_fixd));
530
531 if (!mn_get_regexps (&label_re, &name_re, "machine_name_fix"))
532 {
533 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)
;
534 goto done;
535 }
536
537 scratch[0] = '_';
538 scratch[1] = '_';
539
540 for (base = text;
541 xregexec (label_re, base, 2, match, 0) == 0;
542 base = limit)
543 {
544 base += match[0].rm_eo;
545 /* We're looking at an #if or #ifdef. Scan forward for the
546 next non-escaped newline. */
547 line = limit = base;
548 do
549 {
550 limit++;
551 limit = strchr (limit, '\n');
552 if (!limit)
553 goto done;
554 }
555 while (limit[-1] == '\\');
556
557 /* If the 'name_pat' matches in between base and limit, we have
558 a bogon. It is not worth the hassle of excluding comments
559 because comments on #if/#ifdef lines are rare, and strings on
560 such lines are only legal in a "__has_include" directive.
561
562 REG_NOTBOL means 'base' is not at the beginning of a line, which
563 shouldn't matter since the name_re has no ^ anchor, but let's
564 be accurate anyway. */
565
566 for (;;)
567 {
568 again:
569 if (base == limit)
570 break;
571
572 if (xregexec (name_re, base, 1, match, REG_NOTBOL1))
573 goto done; /* No remaining match in this file */
574
575 /* Match; is it on the line? */
576 if (match[0].rm_eo > limit - base)
577 break;
578
579 p = base + match[0].rm_so;
580
581 /* Check if the match is in __has_include(...) (PR 91085). */
582 q = check_has_inc (base, p, limit);
583 if (q)
584 {
585 base = q + 1;
586 goto again;
587 }
588
589 base += match[0].rm_eo;
590 /* One more test: if on the same line we have the same string
591 with the appropriate underscores, then leave it alone.
592 We want exactly two leading and trailing underscores. */
593 if (*p == '_')
594 {
595 len = base - p - ((*base == '_') ? 2 : 1);
596 q = p + 1;
597 }
598 else
599 {
600 len = base - p - ((*base == '_') ? 1 : 0);
601 q = p;
602 }
603 if (len + 4 > SCRATCHSZ64)
604 abort ();
605 memcpy (&scratch[2], q, len);
606 len += 2;
607 scratch[len++] = '_';
608 scratch[len++] = '_';
609
610 for (q = line; q <= limit - len; q++)
611 if (*q == '_' && !strncmp (q, scratch, len))
612 goto again;
613
614 fwrite (text, 1, p - text, stdout)fwrite_unlocked (text, 1, p - text, stdout);
615 fwrite (scratch, 1, len, stdout)fwrite_unlocked (scratch, 1, len, stdout);
616
617 text = base;
618 }
619 }
620 done:
621 fputs (text, stdout)fputs_unlocked (text, stdout);
622}
623
624
625FIX_PROC_HEAD( wrap_fix )static void wrap_fix (const char* filname __attribute__ ((__unused__
)) , const char* text __attribute__ ((__unused__)) , tFixDesc
* p_fixd __attribute__ ((__unused__)) )
626{
627 tSCCstatic const char z_no_wrap_pat[] = "^#if.*__need_";
628 static regex_t no_wrapping_re; /* assume zeroed data */
629
630 tCCconst char* pz_name = NULL((void*)0);
631
632 if (no_wrapping_re.allocated == 0)
633 compile_re( z_no_wrap_pat, &no_wrapping_re, 0, "no-wrap pattern",
634 "wrap-fix" );
635
636 /*
637 * IF we do *not* match the no-wrap re, then we have a double negative.
638 * A double negative means YES.
639 */
640 if (xregexec( &no_wrapping_re, text, 0, NULL((void*)0), 0 ) != 0)
641 {
642 /*
643 * A single file can get wrapped more than once by different fixes.
644 * A single fix can wrap multiple files. Therefore, guard with
645 * *both* the fix name and the file name.
646 */
647 size_t ln = strlen( filname ) + strlen( p_fixd->fix_name ) + 14;
648 char* pz = XNEWVEC (char, ln)((char *) xmalloc (sizeof (char) * (ln)));
649 pz_name = pz;
650 sprintf( pz, "FIXINC_WRAP_%s-%s", filname, p_fixd->fix_name );
651
652 for (pz += 12; 1; pz++) {
653 char ch = *pz;
654
655 if (ch == NUL'\0')
656 break;
657
658 if (! ISALNUM( ch )(_sch_istable[(ch) & 0xff] & (unsigned short)(_sch_isalnum
))
) {
659 *pz = '_';
660 }
661 else {
662 *pz = TOUPPER( ch )_sch_toupper[(ch) & 0xff];
663 }
664 }
665
666 printf( "#ifndef %s\n", pz_name );
667 printf( "#define %s 1\n\n", pz_name );
668 }
669
670 if (p_fixd->patch_args[1] == (tCCconst char*)NULL((void*)0))
671 fputs( text, stdout )fputs_unlocked (text, stdout);
672
673 else {
674 fputs( p_fixd->patch_args[1], stdout )fputs_unlocked (p_fixd->patch_args[1], stdout);
675 fputs( text, stdout )fputs_unlocked (text, stdout);
676 if (p_fixd->patch_args[2] != (tCCconst char*)NULL((void*)0))
677 fputs( p_fixd->patch_args[2], stdout )fputs_unlocked (p_fixd->patch_args[2], stdout);
678 }
679
680 if (pz_name != NULL((void*)0)) {
681 printf( "\n#endif /* %s */\n", pz_name );
682 free( (void*)pz_name );
683 }
684}
685
686
687/*
688 * Search for multiple copies of a regular expression. Each block
689 * of matched text is replaced with the format string, as described
690 * above in `format_write'.
691 */
692FIX_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__)) )
693{
694 const char* pz_pat;
695 regex_t re;
696 regmatch_t rm[GTYPE_SE_CT1+1];
697 IGNORE_ARG(filname)((void)(filname));
698
699 {
700 tTestDesc* pTD = p_fixd->p_test_desc;
701 int ct = p_fixd->test_ct;
702 for (;;)
703 {
704 if (ct-- <= 0)
705 {
706 fprintf (stderrstderr, zNeedsArg, p_fixd->fix_name, "search text", 1);
707 exit (EXIT_BROKEN3);
708 }
709
710 if (pTD->type == TT_EGREP)
711 {
712 pz_pat = pTD->pz_test_text;
713 break;
714 }
715
716 pTD++;
717 }
718 }
719
720 compile_re (pz_pat, &re, 1, "gnu type typedef", "gnu_type_fix");
721
722 while (xregexec (&re, text, GTYPE_SE_CT1+1, rm, 0) == 0)
723 {
724 text = emit_gnu_type (text, rm);
725 }
726
727 /*
728 * Dump out the rest of the file
729 */
730 fputs (text, stdout)fputs_unlocked (text, stdout);
731}
732
733
734/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
735
736 test for fix selector
737
738 THIS IS THE ONLY EXPORTED ROUTINE
739
740*/
741void
742apply_fix( tFixDesc* p_fixd, tCCconst char* filname )
743{
744#define _FT_(n,p) { n, p },
745 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) }};
746#undef _FT_
747#define FIX_TABLE_CT((sizeof (fix_table) / sizeof ((fix_table)[0]))-1) (ARRAY_SIZE (fix_table)(sizeof (fix_table) / sizeof ((fix_table)[0]))-1)
748
749 tCCconst char* fixname = p_fixd->patch_args[0];
750 char* buf;
751 int ct = FIX_TABLE_CT((sizeof (fix_table) / sizeof ((fix_table)[0]))-1);
752 fix_entry_t* pfe = fix_table;
753
754 for (;;)
755 {
756 if (strcmp (pfe->fix_name, fixname) == 0)
757 break;
758 if (--ct <= 0)
759 {
760 fprintf (stderrstderr, "fixincl error: the `%s' fix is unknown\n",
761 fixname );
762 exit (EXIT_BROKEN3);
763 }
764 pfe++;
765 }
766
767 buf = load_file_data (stdinstdin);
768 (*pfe->fix_proc)( filname, buf, p_fixd );
769}
770
771#ifdef SEPARATE_FIX_PROC
772tSCCstatic const char z_usage[] =
773"USAGE: applyfix <fix-name> <file-to-fix> <file-source> <file-destination>\n";
774tSCCstatic const char z_reopen[] =
775"FS error %d (%s) reopening %s as std%s\n";
776
777int
778main( int argc, char** argv )
779{
780 tFixDesc* pFix;
781 char* pz_tmptmp;
782#ifdef _PC_NAME_MAX_PC_NAME_MAX
783 char* pz_tmp_base;
784 char* pz_tmp_dot;
785#endif
786
787 if (argc != 5)
788 {
789 usage_failure:
790 fputs (z_usage, stderr)fputs_unlocked (z_usage, stderr);
791 return EXIT_FAILURE1;
792 }
793
794 initialize_opts ();
795
796 {
797 char* pz = argv[1];
798 long idx;
799
800 if (! ISDIGIT ( *pz )(_sch_istable[(*pz) & 0xff] & (unsigned short)(_sch_isdigit
))
)
801 goto usage_failure;
802
803 idx = strtol (pz, &pz, 10);
804 if ((*pz != NUL'\0') || ((unsigned)idx >= FIX_COUNT))
805 goto usage_failure;
806 pFix = fixDescList + idx;
807 }
808
809 if (freopen (argv[3], "r", stdin)freopen_unlocked(argv[3],"r",stdin) != stdinstdin)
810 {
811 fprintf (stderrstderr, z_reopen, errno(*__errno_location ()), strerror( errno(*__errno_location ()) ), argv[3], "in");
812 return EXIT_FAILURE1;
813 }
814
815 pz_tmptmp = XNEWVEC (char, strlen (argv[4]) + 5)((char *) xmalloc (sizeof (char) * (strlen (argv[4]) + 5)));
816 strcpy( pz_tmptmp, argv[4] );
817
818#ifdef _PC_NAME_MAX_PC_NAME_MAX
819 /* Don't lose because "12345678" and "12345678X" map to the same
820 file under DOS restricted 8+3 file namespace. Note that DOS
821 doesn't allow more than one dot in the trunk of a file name. */
822 pz_tmp_base = basename( pz_tmptmp );
823 pz_tmp_dot = strchr( pz_tmp_base, '.' );
824 if (pathconf( pz_tmptmp, _PC_NAME_MAX_PC_NAME_MAX ) <= 12 /* is this DOS or Windows9X? */
825 && pz_tmp_dot != (char*)NULL((void*)0))
826 strcpy (pz_tmp_dot+1, "X"); /* nuke the original extension */
827 else
828#endif /* _PC_NAME_MAX */
829 strcat (pz_tmptmp, ".X");
830 if (freopen (pz_tmptmp, "w", stdout)freopen_unlocked(pz_tmptmp,"w",stdout) != stdoutstdout)
831 {
832 fprintf (stderrstderr, z_reopen, errno(*__errno_location ()), strerror( errno(*__errno_location ()) ), pz_tmptmp, "out");
833 return EXIT_FAILURE1;
834 }
835
836 /* Second parameter of apply_fix is file name */
837 apply_fix (pFix, argv[2]);
838 fclose (stdoutstdout);
839 fclose (stdinstdin);
840 unlink (argv[4]);
841 if (rename (pz_tmptmp, argv[4]) != 0)
842 {
843 fprintf (stderrstderr, "error %d (%s) renaming %s to %s\n", errno(*__errno_location ()),
844 strerror( errno(*__errno_location ()) ), pz_tmptmp, argv[4]);
845 return EXIT_FAILURE1;
846 }
847
848 return EXIT_SUCCESS0;
849}
850#endif