Bug Summary

File:workdir/unxlngi6.pro/CustomTarget/ucpp/source/cpp.c
Location:line 1138, column 13
Description:Memory is never released; potential leak of memory pointed to by 'atl.t'

Annotated Source Code

1/*
2 * C and T preprocessor, and integrated lexer
3 * (c) Thomas Pornin 1999 - 2002
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. The name of the authors may not be used to endorse or promote
14 * products derived from this software without specific prior written
15 * permission.
16 *
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
23 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
27 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31#define VERS_MAJ1 1
32#define VERS_MIN3 3
33/* uncomment the following if you cannot set it with a compiler flag */
34/* #define STAND_ALONE */
35
36#include "tune.h"
37#include <stdio.h>
38#include <string.h>
39#include <stdarg.h>
40#include <setjmp.h>
41#include <stddef.h>
42#include <limits.h>
43#include <time.h>
44#include "ucppi.h"
45#include "mem.h"
46#include "nhash.h"
47#ifdef UCPP_MMAP
48#include <unistd.h>
49#include <sys/types.h>
50#include <sys/mman.h>
51#include <fcntl.h>
52#endif
53
54/*
55 * The standard path where includes are looked for.
56 */
57#ifdef STAND_ALONE1
58static char *include_path_std[] = { STD_INCLUDE_PATH"/usr/local/include", "/usr/include", 0 };
59#endif
60static char **include_path;
61static size_t include_path_nb = 0;
62
63int no_special_macros = 0;
64int emit_dependencies = 0, emit_defines = 0, emit_assertions = 0;
65FILE *emit_output;
66
67#ifdef STAND_ALONE1
68static char *system_macros_def[] = { STD_MACROS0, 0 };
69static char *system_assertions_def[] = { STD_ASSERT0, 0 };
70#endif
71
72char *current_filename = 0, *current_long_filename = 0;
73static int current_incdir = -1;
74
75#ifndef NO_UCPP_ERROR_FUNCTIONS
76/*
77 * "ouch" is the name for an internal ucpp error. If AUDIT is not defined,
78 * no code calling this function will be generated; a "ouch" may still be
79 * emitted by getmem() (in mem.c) if MEM_CHECK is defined, but this "ouch"
80 * does not use this function.
81 */
82void ucpp_ouch(char *fmt, ...)
83{
84 va_list ap;
85
86 va_start(ap, fmt)__builtin_va_start(ap, fmt);
87 fprintf(stderrstderr, "%s: ouch, ", current_filename);
88 vfprintf(stderrstderr, fmt, ap);
89 fprintf(stderrstderr, "\n");
90 va_end(ap)__builtin_va_end(ap);
91 die();
92}
93
94/*
95 * report an error, with current_filename, line, and printf-like syntax
96 */
97void ucpp_error(long line, char *fmt, ...)
98{
99 va_list ap;
100
101 va_start(ap, fmt)__builtin_va_start(ap, fmt);
102 if (line > 0)
103 fprintf(stderrstderr, "%s: line %ld: ", current_filename, line);
104 else if (line == 0) fprintf(stderrstderr, "%s: ", current_filename);
105 vfprintf(stderrstderr, fmt, ap);
106 fprintf(stderrstderr, "\n");
107 if (line >= 0) {
108 struct stack_context *sc = report_context();
109 size_t i;
110
111 for (i = 0; sc[i].line >= 0; i ++)
112 fprintf(stderrstderr, "\tincluded from %s:%ld\n",
113 sc[i].long_name ? sc[i].long_name : sc[i].name,
114 sc[i].line);
115 freememfree(sc);
116 }
117 va_end(ap)__builtin_va_end(ap);
118}
119
120/*
121 * like error(), with the mention "warning"
122 */
123void ucpp_warning(long line, char *fmt, ...)
124{
125 va_list ap;
126
127 va_start(ap, fmt)__builtin_va_start(ap, fmt);
128 if (line > 0)
129 fprintf(stderrstderr, "%s: warning: line %ld: ",
130 current_filename, line);
131 else if (line == 0)
132 fprintf(stderrstderr, "%s: warning: ", current_filename);
133 else fprintf(stderrstderr, "warning: ");
134 vfprintf(stderrstderr, fmt, ap);
135 fprintf(stderrstderr, "\n");
136 if (line >= 0) {
137 struct stack_context *sc = report_context();
138 size_t i;
139
140 for (i = 0; sc[i].line >= 0; i ++)
141 fprintf(stderrstderr, "\tincluded from %s:%ld\n",
142 sc[i].long_name ? sc[i].long_name : sc[i].name,
143 sc[i].line);
144 freememfree(sc);
145 }
146 va_end(ap)__builtin_va_end(ap);
147}
148#endif /* NO_UCPP_ERROR_FUNCTIONS */
149
150/*
151 * Some memory allocations are manually garbage-collected; essentially,
152 * strings duplicated in the process of macro replacement. Each such
153 * string is referenced in the garbage_fifo, which is cleared when all
154 * nested macros have been resolved.
155 */
156
157struct garbage_fifo {
158 char **garbage;
159 size_t ngarb, memgarb;
160};
161
162/*
163 * throw_away() marks a string to be collected later
164 */
165void throw_awayucpp_throw_away(struct garbage_fifo *gf, char *n)
166{
167 wan(gf->garbage, gf->ngarb, n, gf->memgarb)do { if ((gf->ngarb) == (gf->memgarb)) { (gf->memgarb
) += (gf->memgarb); (gf->garbage) = incmem((gf->garbage
), (gf->ngarb) * sizeof(n), (gf->memgarb) * sizeof(n));
} (gf->garbage)[(gf->ngarb) ++] = (n); } while (0)
;
9
Within the expansion of the macro 'wan':
168}
169
170/*
171 * free marked strings
172 */
173void garbage_collectucpp_garbage_collect(struct garbage_fifo *gf)
174{
175 size_t i;
176
177 for (i = 0; i < gf->ngarb; i ++) freememfree(gf->garbage[i]);
178 gf->ngarb = 0;
179}
180
181static void init_garbage_fifo(struct garbage_fifo *gf)
182{
183 gf->garbage = getmemmalloc((gf->memgarb = GARBAGE_LIST_MEMG32)
184 * sizeof(char *));
185 gf->ngarb = 0;
186}
187
188static void free_garbage_fifo(struct garbage_fifo *gf)
189{
190 garbage_collectucpp_garbage_collect(gf);
191 freememfree(gf->garbage);
192 freememfree(gf);
193}
194
195/*
196 * order is important: it must match the token-constants declared as an
197 * enum in the header file.
198 */
199char *operators_name[] = {
200 " ", "\n", " ",
201 "0000", "name", "bunch", "pragma", "context",
202 "\"dummy string\"", "'dummy char'",
203 "/", "/=", "-", "--", "-=", "->", "+", "++", "+=", "<", "<=", "<<",
204 "<<=", ">", ">=", ">>", ">>=", "=", "==",
205#ifdef CAST_OP
206 "=>",
207#endif
208 "~", "!=", "&", "&&", "&=", "|", "||", "|=", "%", "%=", "*", "*=",
209 "^", "^=", "!",
210 "{", "}", "[", "]", "(", ")", ",", "?", ";",
211 ":", ".", "...", "#", "##", " ", "ouch", "<:", ":>", "<%", "%>",
212 "%:", "%:%:"
213};
214
215/* the ascii representation of a token */
216#ifdef SEMPER_FIDELIS
217#define tname(x)((((x).type) >= NUMBER && ((x).type) <= CHAR) ?
(x).name : operators_name[(x).type])
(ttWHI((x).type)((((x).type) == NONE || ((x).type) == COMMENT || ((x).type) ==
OPT_NONE) || ((x).type) == NEWLINE)
? " " : S_TOKEN((x).type)(((x).type) >= NUMBER && ((x).type) <= CHAR) \
218 ? (x).name : operators_name[(x).type])
219#else
220#define tname(x)((((x).type) >= NUMBER && ((x).type) <= CHAR) ?
(x).name : operators_name[(x).type])
(S_TOKEN((x).type)(((x).type) >= NUMBER && ((x).type) <= CHAR) ? (x).name \
221 : operators_name[(x).type])
222#endif
223
224char *token_nameucpp_token_name(struct token *t)
225{
226 return tname(*t)((((*t).type) >= NUMBER && ((*t).type) <= CHAR)
? (*t).name : operators_name[(*t).type])
;
227}
228
229/*
230 * To speed up deeply nested and repeated inclusions, we:
231 * -- use a hash table to remember where we found each file
232 * -- remember when the file is protected by a #ifndef/#define/#endif
233 * construction; we can then avoid including several times a file
234 * when this is not necessary.
235 * -- remember in which directory, in the include path, the file was found.
236 */
237struct found_file {
238 hash_item_header head; /* first field */
239 char *name;
240 char *protect;
241};
242
243/*
244 * For files from system include path.
245 */
246struct found_file_sys {
247 hash_item_header head; /* first field */
248 struct found_file *rff;
249 int incdir;
250};
251
252static HTT found_files, found_files_sys;
253static int found_files_init_done = 0, found_files_sys_init_done = 0;
254
255static struct found_file *new_found_file(void)
256{
257 struct found_file *ff = getmemmalloc(sizeof(struct found_file));
258
259 ff->name = 0;
260 ff->protect = 0;
261 return ff;
262}
263
264static void del_found_file(void *m)
265{
266 struct found_file *ff = (struct found_file *)m;
267
268 if (ff->name) freememfree(ff->name);
269 if (ff->protect) freememfree(ff->protect);
270 freememfree(ff);
271}
272
273static struct found_file_sys *new_found_file_sys(void)
274{
275 struct found_file_sys *ffs = getmemmalloc(sizeof(struct found_file_sys));
276
277 ffs->rff = 0;
278 ffs->incdir = -1;
279 return ffs;
280}
281
282static void del_found_file_sys(void *m)
283{
284 struct found_file_sys *ffs = (struct found_file_sys *)m;
285
286 freememfree(ffs);
287}
288
289/*
290 * To keep up with the #ifndef/#define/#endif protection mechanism
291 * detection.
292 */
293struct protect protect_detect;
294static struct protect *protect_detect_stack = 0;
295
296void set_init_filename(char *x, int real_file)
297{
298 if (current_filename) freememfree(current_filename);
299 current_filename = sdup(x);
300 current_long_filename = 0;
301 current_incdir = -1;
302 if (real_file) {
303 protect_detect.macro = 0;
304 protect_detect.state = 1;
305 protect_detect.ff = new_found_file();
306 protect_detect.ff->name = sdup(x);
307 HTT_put(&found_files, protect_detect.ff, x);
308 } else {
309 protect_detect.state = 0;
310 }
311}
312
313static void init_found_files(void)
314{
315 if (found_files_init_done) HTT_kill(&found_files);
316 HTT_init(&found_files, del_found_file);
317 found_files_init_done = 1;
318 if (found_files_sys_init_done) HTT_kill(&found_files_sys);
319 HTT_init(&found_files_sys, del_found_file_sys);
320 found_files_sys_init_done = 1;
321}
322
323/*
324 * Set the lexer state at the beginning of a file.
325 */
326static void reinit_lexer_state(struct lexer_state *ls, int wb)
327{
328#ifndef NO_UCPP_BUF1
329 ls->input_buf = wb ? getmemmalloc(INPUT_BUF_MEMG8192) : 0;
330#ifdef UCPP_MMAP
331 ls->from_mmap = 0;
332#endif
333#endif
334 ls->input = 0;
335 ls->ebuf = ls->pbuf = 0;
336 ls->nlka = 0;
337 ls->macfile = 0;
338 ls->discard = 1;
339 ls->last = 0; /* we suppose '\n' is not 0 */
340 ls->line = 1;
341 ls->ltwnl = 1;
342 ls->oline = 1;
343 ls->pending_token = 0;
344 ls->cli = 0;
345 ls->copy_line[COPY_LINE_LENGTH80 - 1] = 0;
346 ls->ifnest = 0;
347 ls->condf[0] = ls->condf[1] = 0;
348}
349
350/*
351 * Initialize the struct lexer_state, with optional input and output buffers.
352 */
353void init_buf_lexer_stateucpp_init_buf_lexer_state(struct lexer_state *ls, int wb)
354{
355 reinit_lexer_state(ls, wb);
356#ifndef NO_UCPP_BUF1
357 ls->output_buf = wb ? getmemmalloc(OUTPUT_BUF_MEMG8192) : 0;
358#endif
359 ls->sbuf = 0;
360 ls->output_fifo = 0;
361
362 ls->ctok = getmemmalloc(sizeof(struct token));
363 ls->ctok->name = getmemmalloc(ls->tknl = TOKEN_NAME_MEMG64);
364 ls->pending_token = 0;
365
366 ls->flags = 0;
367 ls->count_trigraphs = 0;
368 ls->gf = getmemmalloc(sizeof(struct garbage_fifo));
369 init_garbage_fifo(ls->gf);
370 ls->condcomp = 1;
371 ls->condnest = 0;
372#ifdef INMACRO_FLAG
373 ls->inmacro = 0;
374 ls->macro_count = 0;
375#endif
376}
377
378/*
379 * Initialize the (complex) struct lexer_state.
380 */
381void init_lexer_state(struct lexer_state *ls)
382{
383 init_buf_lexer_stateucpp_init_buf_lexer_state(ls, 1);
384 ls->input = 0;
385}
386
387/*
388 * Restore what is needed from a lexer_state. This is used for #include.
389 */
390static void restore_lexer_state(struct lexer_state *ls,
391 struct lexer_state *lsbak)
392{
393#ifndef NO_UCPP_BUF1
394 freememfree(ls->input_buf);
395 ls->input_buf = lsbak->input_buf;
396#ifdef UCPP_MMAP
397 ls->from_mmap = lsbak->from_mmap;
398 ls->input_buf_sav = lsbak->input_buf_sav;
399#endif
400#endif
401 ls->input = lsbak->input;
402 ls->ebuf = lsbak->ebuf;
403 ls->pbuf = lsbak->pbuf;
404 ls->nlka = lsbak->nlka;
405 ls->discard = lsbak->discard;
406 ls->line = lsbak->line;
407 ls->oline = lsbak->oline;
408 ls->ifnest = lsbak->ifnest;
409 ls->condf[0] = lsbak->condf[0];
410 ls->condf[1] = lsbak->condf[1];
411}
412
413/*
414 * close input file operations on a struct lexer_state
415 */
416static void close_input(struct lexer_state *ls)
417{
418#ifdef UCPP_MMAP
419 if (ls->from_mmap) {
420 munmap((void *)ls->input_buf, ls->ebuf);
421 ls->from_mmap = 0;
422 ls->input_buf = ls->input_buf_sav;
423 }
424#endif
425 if (ls->input) {
426 fclose(ls->input);
427 ls->input = 0;
428 }
429}
430
431/*
432 * file_context (and the two functions push_ and pop_) are used to save
433 * all that is needed when including a file.
434 */
435static struct file_context {
436 struct lexer_state ls;
437 char *name, *long_name;
438 int incdir;
439} *ls_stack;
440static size_t ls_depth = 0;
441
442static void push_file_context(struct lexer_state *ls)
443{
444 struct file_context fc;
445
446 fc.name = current_filename;
447 fc.long_name = current_long_filename;
448 fc.incdir = current_incdir;
449 mmvmemcpy(&(fc.ls), ls, sizeof(struct lexer_state));
450 aol(ls_stack, ls_depth, fc, LS_STACK_MEMG)do { if (((ls_depth) % (4)) == 0) { if ((ls_depth) != 0) { (ls_stack
) = incmem((ls_stack), (ls_depth) * sizeof(fc), ((ls_depth) +
(4)) * sizeof(fc)); } else { (ls_stack) = malloc((4) * sizeof
(fc)); } } (ls_stack)[(ls_depth) ++] = (fc); } while (0)
;
451 ls_depth --;
452 aol(protect_detect_stack, ls_depth, protect_detect, LS_STACK_MEMG)do { if (((ls_depth) % (4)) == 0) { if ((ls_depth) != 0) { (protect_detect_stack
) = incmem((protect_detect_stack), (ls_depth) * sizeof(protect_detect
), ((ls_depth) + (4)) * sizeof(protect_detect)); } else { (protect_detect_stack
) = malloc((4) * sizeof(protect_detect)); } } (protect_detect_stack
)[(ls_depth) ++] = (protect_detect); } while (0)
;
453 protect_detect.macro = 0;
454}
455
456static void pop_file_context(struct lexer_state *ls)
457{
458#ifdef AUDIT
459 if (ls_depth <= 0) ouchucpp_ouch("prepare to meet thy creator");
460#endif
461 close_input(ls);
462 restore_lexer_state(ls, &(ls_stack[-- ls_depth].ls));
463 if (protect_detect.macro) freememfree(protect_detect.macro);
464 protect_detect = protect_detect_stack[ls_depth];
465 if (current_filename) freememfree(current_filename);
466 current_filename = ls_stack[ls_depth].name;
467 current_long_filename = ls_stack[ls_depth].long_name;
468 current_incdir = ls_stack[ls_depth].incdir;
469 if (ls_depth == 0) {
470 freememfree(ls_stack);
471 freememfree(protect_detect_stack);
472 }
473}
474
475/*
476 * report_context() returns the list of successive includers of the
477 * current file, ending with a dummy entry with a negative line number.
478 * The caller is responsible for freeing the returned pointer.
479 */
480struct stack_context *report_context(void)
481{
482 struct stack_context *sc;
483 size_t i;
484
485 sc = getmemmalloc((ls_depth + 1) * sizeof(struct stack_context));
486 for (i = 0; i < ls_depth; i ++) {
487 sc[i].name = ls_stack[ls_depth - i - 1].name;
488 sc[i].long_name = ls_stack[ls_depth - i - 1].long_name;
489 sc[i].line = ls_stack[ls_depth - i - 1].ls.line - 1;
490 }
491 sc[ls_depth].line = -1;
492 return sc;
493}
494
495/*
496 * init_lexer_mode() is used to end initialization of a struct lexer_state
497 * if it must be used for a lexer
498 */
499void init_lexer_mode(struct lexer_state *ls)
500{
501 ls->flags = DEFAULT_LEXER_FLAGS(0x000080UL | 0x000001UL | 0x000020UL | 0x002000UL | 0x000100UL
| 0x010000UL | 0x008000UL | 0x000800UL)
;
502 ls->output_fifo = getmemmalloc(sizeof(struct token_fifo));
503 ls->output_fifo->art = ls->output_fifo->nt = 0;
504 ls->toplevel_of = ls->output_fifo;
505 ls->save_ctok = ls->ctok;
506}
507
508/*
509 * release memory used by a struct lexer_state; this implies closing
510 * any input stream held by this structure.
511 */
512void free_lexer_state(struct lexer_state *ls)
513{
514 close_input(ls);
515#ifndef NO_UCPP_BUF1
516 if (ls->input_buf) {
517 freememfree(ls->input_buf);
518 ls->input_buf = 0;
519 }
520 if (ls->output_buf) {
521 freememfree(ls->output_buf);
522 ls->output_buf = 0;
523 }
524#endif
525 if (ls->ctok && (!ls->output_fifo || ls->output_fifo->nt == 0)) {
526 freememfree(ls->ctok->name);
527 freememfree(ls->ctok);
528 ls->ctok = 0;
529 }
530 if (ls->gf) {
531 free_garbage_fifo(ls->gf);
532 ls->gf = 0;
533 }
534 if (ls->output_fifo) {
535 freememfree(ls->output_fifo);
536 ls->output_fifo = 0;
537 }
538}
539
540/*
541 * Print line information.
542 */
543static void print_line_info(struct lexer_state *ls, unsigned long flags)
544{
545 char *fn = current_long_filename ?
546 current_long_filename : current_filename;
547 char *b, *d;
548
549 b = getmemmalloc(50 + strlen(fn));
550 if (flags & GCC_LINE_NUM0x000400UL) {
551 sprintf(b, "# %ld \"%s\"\n", ls->line, fn);
552 } else {
553 sprintf(b, "#line %ld \"%s\"\n", ls->line, fn);
554 }
555 for (d = b; *d; d ++) put_charucpp_put_char(ls, (unsigned char)(*d));
556 freememfree(b);
557}
558
559/*
560 * Enter a file; this implies the possible emission of a #line directive.
561 * The flags used are passed as second parameter instead of being
562 * extracted from the struct lexer_state.
563 *
564 * As a command-line option, gcc-like directives (with only a '#',
565 * without 'line') may be produced.
566 *
567 * enter_file() returns 1 if a (CONTEXT) token was produced, 0 otherwise.
568 */
569int enter_file(struct lexer_state *ls, unsigned long flags)
570{
571 char *fn = current_long_filename ?
572 current_long_filename : current_filename;
573
574 if (!(flags & LINE_NUM0x000200UL)) return 0;
575 if ((flags & LEXER0x010000UL) && !(flags & TEXT_OUTPUT0x100000UL)) {
576 struct token t;
577
578 t.type = CONTEXT;
579 t.line = ls->line;
580 t.name = fn;
581 print_tokenucpp_print_token(ls, &t, 0);
582 return 1;
583 }
584 print_line_info(ls, flags);
585 ls->oline --; /* emitted #line troubled oline */
586 return 0;
587}
588
589#ifdef UCPP_MMAP
590/*
591 * We open() the file, then fdopen() it and fseek() to its end. If the
592 * fseek() worked, we try to mmap() the file, up to the point where we
593 * arrived.
594 * On an architecture where end-of-lines are multibytes and translated
595 * into single '\n', bad things could happen. We strongly hope that, if
596 * we could fseek() to the end but could not mmap(), then we can get back.
597 */
598static void *find_file_map;
599static size_t map_length;
600
601FILE *fopen_mmap_file(char *name)
602{
603 FILE *f;
604 int fd;
605 long l;
606
607 find_file_map = 0;
608 fd = open(name, O_RDONLY, 0);
609 if (fd < 0) return 0;
610 l = lseek(fd, 0, SEEK_END2);
611 f = fdopen(fd, "r");
612 if (!f) {
613 close(fd);
614 return 0;
615 }
616 if (l < 0) return f; /* not seekable */
617 map_length = l;
618 if ((find_file_map = mmap(0, map_length, PROT_READ,
619 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
620 /* we could not mmap() the file; get back */
621 find_file_map = 0;
622 if (fseek(f, 0, SEEK_SET0)) {
623 /* bwaah... can't get back. This file is cursed. */
624 fclose(f);
625 return 0;
626 }
627 }
628 return f;
629}
630
631void set_input_file(struct lexer_state *ls, FILE *f)
632{
633 ls->input = f;
634 if (find_file_map) {
635 ls->from_mmap = 1;
636 ls->input_buf_sav = ls->input_buf;
637 ls->input_buf = find_file_map;
638 ls->pbuf = 0;
639 ls->ebuf = map_length;
640 } else {
641 ls->from_mmap = 0;
642 }
643}
644#endif
645
646/*
647 * Find a file by looking through the include path.
648 * return value: a FILE * on the file, opened in "r" mode, or 0.
649 *
650 * find_file_error will contain:
651 * FF_ERROR on error (file not found or impossible to read)
652 * FF_PROTECT file is protected and therefore useless to read
653 * FF_KNOWN file is already known
654 * FF_UNKNOWN file was not already known
655 */
656static int find_file_error;
657
658enum { FF_ERROR, FF_PROTECT, FF_KNOWN, FF_UNKNOWN };
659
660static FILE *find_file(char *name, int localdir)
661{
662 FILE *f;
663 int i, incdir = -1;
664 size_t nl = strlen(name);
665 char *s = 0;
666 struct found_file *ff = 0, *nff;
667 int lf = 0;
668 int nffa = 0;
669
670 find_file_error = FF_ERROR;
671 protect_detect.state = -1;
672 protect_detect.macro = 0;
673 if (localdir) {
674 int i;
675 char *rfn = current_long_filename ? current_long_filename
676 : current_filename;
677
678 for (i = strlen(rfn) - 1; i >= 0; i --)
679#ifdef MSDOS
680 if (rfn[i] == '\\') break;
681#else
682 if (rfn[i] == '/') break;
683#endif
684#if defined MSDOS
685 if (i >= 0 && *name != '\\' && (nl < 2 || name[1] != ':'))
686#elif defined AMIGA
687 if (i >= 0 && *name != '/' && (nl < 2 || name[1] != ':'))
688#else
689 if (i >= 0 && *name != '/')
690#endif
691 {
692 /*
693 * current file is somewhere else, and the provided
694 * file name is not absolute, so we must adjust the
695 * base for looking for the file; besides,
696 * found_files and found_files_loc are irrelevant
697 * for this search.
698 */
699 s = getmemmalloc(i + 2 + nl);
700 mmvmemcpy(s, rfn, i);
701#ifdef MSDOS
702 s[i] = '\\';
703#else
704 s[i] = '/';
705#endif
706 mmvmemcpy(s + i + 1, name, nl);
707 s[i + 1 + nl] = 0;
708 ff = HTT_get(&found_files, s);
709 } else ff = HTT_get(&found_files, name);
710 }
711 if (!ff) {
712 struct found_file_sys *ffs = HTT_get(&found_files_sys, name);
713
714 if (ffs) {
715 ff = ffs->rff;
716 incdir = ffs->incdir;
717 }
718 }
719 /*
720 * At that point: if the file was found in the cache, ff points to
721 * the cached descriptive structure; its name is s if s is not 0,
722 * name otherwise.
723 */
724 if (ff) goto found_file_cache;
725
726 /*
727 * This is the first time we find the file, or it was not protected.
728 */
729 protect_detect.ff = new_found_file();
730 nffa = 1;
731 if (localdir &&
732#ifdef UCPP_MMAP
733 (f = fopen_mmap_file(s ? s : name))
734#else
735 (f = fopen(s ? s : name, "r"))
736#endif
737 ) {
738 lf = 1;
739 goto found_file;
740 }
741 /*
742 * If s contains a name, that name is now irrelevant: it was a
743 * filename for a search in the current directory, and the file
744 * was not found.
745 */
746 if (s) {
747 freememfree(s);
748 s = 0;
749 }
750 for (i = 0; (size_t)i < include_path_nb; i ++) {
751 size_t ni = strlen(include_path[i]);
752
753 s = getmemmalloc(ni + nl + 2);
754 mmvmemcpy(s, include_path[i], ni);
755#ifdef AMIGA
756 /* contributed by Volker Barthelmann */
757 if (ni == 1 && *s == '.') {
758 *s = 0;
759 ni = 0;
760 }
761 if (ni > 0 && s[ni - 1] != ':' && s[ni - 1] != '/') {
762 s[ni] = '/';
763 mmvmemcpy(s + ni + 1, name, nl + 1);
764 } else {
765 mmvmemcpy(s + ni, name, nl + 1);
766 }
767#else
768 s[ni] = '/';
769 mmvmemcpy(s + ni + 1, name, nl + 1);
770#endif
771#ifdef MSDOS
772 /* on msdos systems, replace all / by \ */
773 {
774 char *c;
775
776 for (c = s; *c; c ++) if (*c == '/') *c = '\\';
777 }
778#endif
779 incdir = i;
780 if ((ff = HTT_get(&found_files, s)) != 0) {
781 /*
782 * The file is known, but not as a system include
783 * file under the name provided.
784 */
785 struct found_file_sys *ffs = new_found_file_sys();
786
787 ffs->rff = ff;
788 ffs->incdir = incdir;
789 HTT_put(&found_files_sys, ffs, name);
790 freememfree(s);
791 s = 0;
792 if (nffa) {
793 del_found_file(protect_detect.ff);
794 protect_detect.ff = 0;
795 nffa = 0;
796 }
797 goto found_file_cache;
798 }
799#ifdef UCPP_MMAP
800 f = fopen_mmap_file(s);
801#else
802 f = fopen(s, "r");
803#endif
804 if (f) goto found_file;
805 freememfree(s);
806 s = 0;
807 }
808zero_out:
809 if (s) freememfree(s);
810 if (nffa) {
811 del_found_file(protect_detect.ff);
812 protect_detect.ff = 0;
813 nffa = 0;
814 }
815 return 0;
816
817 /*
818 * This part is invoked when the file was found in the
819 * cache.
820 */
821found_file_cache:
822 if (ff->protect) {
823 if (get_macroucpp_get_macro(ff->protect)) {
824 /* file is protected, do not include it */
825 find_file_error = FF_PROTECT;
826 goto zero_out;
827 }
828 /* file is protected but the guardian macro is
829 not available; disable guardian detection. */
830 protect_detect.state = 0;
831 }
832 protect_detect.ff = ff;
833#ifdef UCPP_MMAP
834 f = fopen_mmap_file(HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned)));
835#else
836 f = fopen(HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned)), "r");
837#endif
838 if (!f) goto zero_out;
839 find_file_error = FF_KNOWN;
840 goto found_file_2;
841
842 /*
843 * This part is invoked when we found a new file, which was not
844 * yet referenced. If lf == 1, then the file was found directly,
845 * otherwise it was found in some system include directory.
846 * A new found_file structure has been allocated and is in
847 * protect_detect.ff
848 */
849found_file:
850 if (f && ((emit_dependencies == 1 && lf && current_incdir == -1)
851 || emit_dependencies == 2)) {
852 fprintf(emit_output, " %s", s ? s : name);
853 }
854 nff = protect_detect.ff;
855 nff->name = sdup(name);
856#ifdef AUDIT
857 if (
858#endif
859 HTT_put(&found_files, nff, s ? s : name)
860#ifdef AUDIT
861 ) ouchucpp_ouch("filename collided with a wraith")
862#endif
863 ;
864 if (!lf) {
865 struct found_file_sys *ffs = new_found_file_sys();
866
867 ffs->rff = nff;
868 ffs->incdir = incdir;
869 HTT_put(&found_files_sys, ffs, name);
870 }
871 if (s) freememfree(s);
872 s = 0;
873 find_file_error = FF_UNKNOWN;
874 ff = nff;
875
876found_file_2:
877 if (s) freememfree(s);
878 current_long_filename = HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned));
879#ifdef NO_LIBC_BUF
880 setbuf(f, 0);
881#endif
882 current_incdir = incdir;
883 return f;
884}
885
886/*
887 * Find the named file by looking through the end of the include path.
888 * This is for #include_next directives.
889 * #include_next <foo> and #include_next "foo" are considered identical,
890 * for all practical purposes.
891 */
892static FILE *find_file_next(char *name)
893{
894 int i;
895 size_t nl = strlen(name);
896 FILE *f;
897 struct found_file *ff;
898
899 find_file_error = FF_ERROR;
900 protect_detect.state = -1;
901 protect_detect.macro = 0;
902 for (i = current_incdir + 1; (size_t)i < include_path_nb; i ++) {
903 char *s;
904 size_t ni = strlen(include_path[i]);
905
906 s = getmemmalloc(ni + nl + 2);
907 mmvmemcpy(s, include_path[i], ni);
908 s[ni] = '/';
909 mmvmemcpy(s + ni + 1, name, nl + 1);
910#ifdef MSDOS
911 /* on msdos systems, replace all / by \ */
912 {
913 char *c;
914
915 for (c = s; *c; c ++) if (*c == '/') *c = '\\';
916 }
917#endif
918 ff = HTT_get(&found_files, s);
919 if (ff) {
920 /* file was found in the cache */
921 if (ff->protect) {
922 if (get_macroucpp_get_macro(ff->protect)) {
923 find_file_error = FF_PROTECT;
924 freememfree(s);
925 return 0;
926 }
927 /* file is protected but the guardian macro is
928 not available; disable guardian detection. */
929 protect_detect.state = 0;
930 }
931 protect_detect.ff = ff;
932#ifdef UCPP_MMAP
933 f = fopen_mmap_file(HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned)));
934#else
935 f = fopen(HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned)), "r");
936#endif
937 if (!f) {
938 /* file is referenced but yet unavailable. */
939 freememfree(s);
940 return 0;
941 }
942 find_file_error = FF_KNOWN;
943 freememfree(s);
944 s = HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned));
945 } else {
946#ifdef UCPP_MMAP
947 f = fopen_mmap_file(s);
948#else
949 f = fopen(s, "r");
950#endif
951 if (f) {
952 if (emit_dependencies == 2) {
953 fprintf(emit_output, " %s", s);
954 }
955 ff = protect_detect.ff = new_found_file();
956 ff->name = sdup(s);
957#ifdef AUDIT
958 if (
959#endif
960 HTT_put(&found_files, ff, s)
961#ifdef AUDIT
962 ) ouchucpp_ouch("filename collided with a wraith")
963#endif
964 ;
965 find_file_error = FF_UNKNOWN;
966 freememfree(s);
967 s = HASH_ITEM_NAME(ff)(((hash_item_header *)(ff))->ident + sizeof(unsigned));
968 }
969 }
970 if (f) {
971 current_long_filename = s;
972 current_incdir = i;
973 return f;
974 }
975 freememfree(s);
976 }
977 return 0;
978}
979
980/*
981 * The #if directive. This function parse the expression, performs macro
982 * expansion (and handles the "defined" operator), and call eval_expr.
983 * return value: 1 if the expression is true, 0 if it is false, -1 on error.
984 */
985static int handle_if(struct lexer_state *ls)
986{
987 struct token_fifo tf, tf1, tf2, tf3, *save_tf;
988 long l = ls->line;
989 unsigned long z;
990 int ret = 0, ltww = 1;
991
992 /* first, get the whole line */
993 tf.art = tf.nt = 0;
994 while (!next_tokenucpp_next_token(ls) && ls->ctok->type != NEWLINE) {
1
Loop condition is true. Entering loop body
4
Loop condition is true. Entering loop body
6
Loop condition is true. Entering loop body
995 struct token t;
996
997 if (ltww && ttMWS(ls->ctok->type)((ls->ctok->type) == NONE || (ls->ctok->type) == COMMENT
|| (ls->ctok->type) == OPT_NONE)
) continue;
2
Taking false branch
998 ltww = ttMWS(ls->ctok->type)((ls->ctok->type) == NONE || (ls->ctok->type) == COMMENT
|| (ls->ctok->type) == OPT_NONE)
;
999 t.type = ls->ctok->type;
1000 t.line = l;
1001 if (S_TOKEN(ls->ctok->type)((ls->ctok->type) >= NUMBER && (ls->ctok->
type) <= CHAR)
) {
7
Taking true branch
1002 t.name = sdup(ls->ctok->name);
1003 throw_awayucpp_throw_away(ls->gf, t.name);
8
Within the expansion of the macro 'throw_away':
a
Calling 'ucpp_throw_away'
b
Returning from 'ucpp_throw_away'
1004 }
1005 aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG)do { if (((tf.nt) % (32)) == 0) { if ((tf.nt) != 0) { (tf.t) =
incmem((tf.t), (tf.nt) * sizeof(t), ((tf.nt) + (32)) * sizeof
(t)); } else { (tf.t) = malloc((32) * sizeof(t)); } } (tf.t)[
(tf.nt) ++] = (t); } while (0)
;
3
Within the expansion of the macro 'aol':
5
Within the expansion of the macro 'aol':
10
Within the expansion of the macro 'aol':
1006 }
1007 if (ltww && tf.nt) if ((-- tf.nt) == 0) freememfree(tf.t);
1008 if (tf.nt == 0) {
11
Taking false branch
1009 errorucpp_error(l, "void condition for a #if/#elif");
1010 return -1;
1011 }
1012 /* handle the "defined" operator */
1013 tf1.art = tf1.nt = 0;
1014 while (tf.art < tf.nt) {
12
Loop condition is true. Entering loop body
15
Loop condition is true. Entering loop body
18
Loop condition is true. Entering loop body
22
Loop condition is false. Execution continues on line 1052
1015 struct token *ct, rt;
1016 struct macro *m;
1017 size_t nidx, eidx;
1018
1019 ct = tf.t + (tf.art ++);
1020 if (ct->type == NAME && !strcmp(ct->name, "defined")) {
19
Taking false branch
1021 if (tf.art >= tf.nt) goto store_token;
1022 nidx = tf.art;
1023 if (ttMWS(tf.t[nidx].type)((tf.t[nidx].type) == NONE || (tf.t[nidx].type) == COMMENT ||
(tf.t[nidx].type) == OPT_NONE)
)
1024 if (++ nidx >= tf.nt) goto store_token;
1025 if (tf.t[nidx].type == NAME) {
1026 eidx = nidx;
1027 goto check_macro;
1028 }
1029 if (tf.t[nidx].type != LPAR) goto store_token;
1030 if (++ nidx >= tf.nt) goto store_token;
1031 if (ttMWS(tf.t[nidx].type)((tf.t[nidx].type) == NONE || (tf.t[nidx].type) == COMMENT ||
(tf.t[nidx].type) == OPT_NONE)
)
1032 if (++ nidx >= tf.nt) goto store_token;
1033 if (tf.t[nidx].type != NAME) goto store_token;
1034 eidx = nidx + 1;
1035 if (eidx >= tf.nt) goto store_token;
1036 if (ttMWS(tf.t[eidx].type)((tf.t[eidx].type) == NONE || (tf.t[eidx].type) == COMMENT ||
(tf.t[eidx].type) == OPT_NONE)
)
1037 if (++ eidx >= tf.nt) goto store_token;
1038 if (tf.t[eidx].type != RPAR) goto store_token;
1039 goto check_macro;
1040 }
1041 store_token:
1042 aol(tf1.t, tf1.nt, *ct, TOKEN_LIST_MEMG)do { if (((tf1.nt) % (32)) == 0) { if ((tf1.nt) != 0) { (tf1.
t) = incmem((tf1.t), (tf1.nt) * sizeof(*ct), ((tf1.nt) + (32)
) * sizeof(*ct)); } else { (tf1.t) = malloc((32) * sizeof(*ct
)); } } (tf1.t)[(tf1.nt) ++] = (*ct); } while (0)
;
13
Within the expansion of the macro 'aol':
16
Within the expansion of the macro 'aol':
20
Within the expansion of the macro 'aol':
1043 continue;
14
Execution continues on line 1014
17
Execution continues on line 1014
21
Execution continues on line 1014
1044
1045 check_macro:
1046 m = get_macroucpp_get_macro(tf.t[nidx].name);
1047 rt.type = NUMBER;
1048 rt.name = m ? "1L" : "0L";
1049 aol(tf1.t, tf1.nt, rt, TOKEN_LIST_MEMG)do { if (((tf1.nt) % (32)) == 0) { if ((tf1.nt) != 0) { (tf1.
t) = incmem((tf1.t), (tf1.nt) * sizeof(rt), ((tf1.nt) + (32))
* sizeof(rt)); } else { (tf1.t) = malloc((32) * sizeof(rt));
} } (tf1.t)[(tf1.nt) ++] = (rt); } while (0)
;
1050 tf.art = eidx + 1;
1051 }
1052 freememfree(tf.t);
1053 if (tf1.nt == 0) {
23
Taking false branch
1054 errorucpp_error(l, "void condition (after expansion) for a #if/#elif");
1055 return -1;
1056 }
1057
1058 /* perform all macro substitutions */
1059 tf2.art = tf2.nt = 0;
1060 save_tf = ls->output_fifo;
1061 ls->output_fifo = &tf2;
1062 while (tf1.art < tf1.nt) {
24
Loop condition is true. Entering loop body
27
Loop condition is true. Entering loop body
30
Loop condition is true. Entering loop body
36
Loop condition is true. Entering loop body
1063 struct token *ct;
1064
1065 ct = tf1.t + (tf1.art ++);
1066 if (ct->type == NAME) {
25
Taking false branch
28
Taking false branch
31
Taking true branch
37
Taking false branch
1067 struct macro *m = get_macroucpp_get_macro(ct->name);
1068
1069 if (m) {
32
Assuming 'm' is non-null
33
Taking true branch
1070 if (substitute_macroucpp_substitute_macro(ls, m, &tf1, 0,
34
Taking false branch
1071#ifdef NO_PRAGMA_IN_DIRECTIVE
1072 1,
1073#else
1074 0,
1075#endif
1076 ct->line)) {
1077 ls->output_fifo = save_tf;
1078 goto error1;
1079 }
1080 continue;
35
Execution continues on line 1062
1081 }
1082 } else if ((ct->type == SHARP || ct->type == DIG_SHARP)
38
Taking true branch
1083 && (ls->flags & HANDLE_ASSERTIONS0x000800UL)) {
1084 /* we have an assertion; parse it */
1085 int nnp, ltww = 1;
1086 size_t i = tf1.art;
1087 struct token_fifo atl;
1088 char *aname;
1089 struct assert *a;
1090 int av = 0;
1091 struct token rt;
1092
1093 atl.art = atl.nt = 0;
1094 while (i < tf1.nt && ttMWS(tf1.t[i].type)((tf1.t[i].type) == NONE || (tf1.t[i].type) == COMMENT || (tf1
.t[i].type) == OPT_NONE)
) i ++;
1095 if (i >= tf1.nt) goto assert_error;
39
Taking false branch
1096 if (tf1.t[i].type != NAME) goto assert_error;
40
Taking false branch
1097 aname = tf1.t[i ++].name;
1098 while (i < tf1.nt && ttMWS(tf1.t[i].type)((tf1.t[i].type) == NONE || (tf1.t[i].type) == COMMENT || (tf1
.t[i].type) == OPT_NONE)
) i ++;
1099 if (i >= tf1.nt) goto assert_generic;
41
Taking false branch
1100 if (tf1.t[i].type != LPAR) goto assert_generic;
42
Taking false branch
1101 i ++;
1102 for (nnp = 1; nnp && i < tf1.nt; i ++) {
43
Loop condition is true. Entering loop body
47
Loop condition is false. Execution continues on line 1113
1103 if (ltww && ttMWS(tf1.t[i].type)((tf1.t[i].type) == NONE || (tf1.t[i].type) == COMMENT || (tf1
.t[i].type) == OPT_NONE)
) continue;
44
Taking false branch
1104 if (tf1.t[i].type == LPAR) nnp ++;
45
Taking true branch
1105 else if (tf1.t[i].type == RPAR
1106 && (-- nnp) == 0) {
1107 tf1.art = i + 1;
1108 break;
1109 }
1110 ltww = ttMWS(tf1.t[i].type)((tf1.t[i].type) == NONE || (tf1.t[i].type) == COMMENT || (tf1
.t[i].type) == OPT_NONE)
;
1111 aol(atl.t, atl.nt, tf1.t[i], TOKEN_LIST_MEMG)do { if (((atl.nt) % (32)) == 0) { if ((atl.nt) != 0) { (atl.
t) = incmem((atl.t), (atl.nt) * sizeof(tf1.t[i]), ((atl.nt) +
(32)) * sizeof(tf1.t[i])); } else { (atl.t) = malloc((32) * sizeof
(tf1.t[i])); } } (atl.t)[(atl.nt) ++] = (tf1.t[i]); } while (
0)
;
46
Within the expansion of the macro 'aol':
a
Memory is allocated
1112 }
1113 if (nnp) goto assert_error;
48
Taking true branch
49
Control jumps to line 1138
1114 if (ltww && atl.nt && (-- atl.nt) == 0) freememfree(atl.t);
1115 if (atl.nt == 0) goto assert_error;
1116
1117 /* the assertion is in aname and atl; check it */
1118 a = get_assertionucpp_get_assertion(aname);
1119 if (a) for (i = 0; i < a->nbval; i ++)
1120 if (!cmp_token_listucpp_cmp_token_list(&atl, a->val + i)) {
1121 av = 1;
1122 break;
1123 }
1124 rt.type = NUMBER;
1125 rt.name = av ? "1" : "0";
1126 aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG)do { if (((tf2.nt) % (32)) == 0) { if ((tf2.nt) != 0) { (tf2.
t) = incmem((tf2.t), (tf2.nt) * sizeof(rt), ((tf2.nt) + (32))
* sizeof(rt)); } else { (tf2.t) = malloc((32) * sizeof(rt));
} } (tf2.t)[(tf2.nt) ++] = (rt); } while (0)
;
1127 if (atl.nt) freememfree(atl.t);
1128 continue;
1129
1130 assert_generic:
1131 tf1.art = i;
1132 rt.type = NUMBER;
1133 rt.name = get_assertionucpp_get_assertion(aname) ? "1" : "0";
1134 aol(tf2.t, tf2.nt, rt, TOKEN_LIST_MEMG)do { if (((tf2.nt) % (32)) == 0) { if ((tf2.nt) != 0) { (tf2.
t) = incmem((tf2.t), (tf2.nt) * sizeof(rt), ((tf2.nt) + (32))
* sizeof(rt)); } else { (tf2.t) = malloc((32) * sizeof(rt));
} } (tf2.t)[(tf2.nt) ++] = (rt); } while (0)
;
1135 continue;
1136
1137 assert_error:
1138 errorucpp_error(l, "syntax error for assertion in #if");
50
Memory is never released; potential leak of memory pointed to by 'atl.t'
1139 ls->output_fifo = save_tf;
1140 goto error1;
1141 }
1142 aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG)do { if (((tf2.nt) % (32)) == 0) { if ((tf2.nt) != 0) { (tf2.
t) = incmem((tf2.t), (tf2.nt) * sizeof(*ct), ((tf2.nt) + (32)
) * sizeof(*ct)); } else { (tf2.t) = malloc((32) * sizeof(*ct
)); } } (tf2.t)[(tf2.nt) ++] = (*ct); } while (0)
;
26
Within the expansion of the macro 'aol':
29
Within the expansion of the macro 'aol':
1143 }
1144 ls->output_fifo = save_tf;
1145 freememfree(tf1.t);
1146 if (tf2.nt == 0) {
1147 errorucpp_error(l, "void condition (after expansion) for a #if/#elif");
1148 return -1;
1149 }
1150
1151 /*
1152 * suppress whitespace and replace rogue identifiers by 0
1153 */
1154 tf3.art = tf3.nt = 0;
1155 while (tf2.art < tf2.nt) {
1156 struct token *ct = tf2.t + (tf2.art ++);
1157
1158 if (ttMWS(ct->type)((ct->type) == NONE || (ct->type) == COMMENT || (ct->
type) == OPT_NONE)
) continue;
1159 if (ct->type == NAME) {
1160 /*
1161 * a rogue identifier; we replace it with "0".
1162 */
1163 struct token rt;
1164
1165 rt.type = NUMBER;
1166 rt.name = "0";
1167 aol(tf3.t, tf3.nt, rt, TOKEN_LIST_MEMG)do { if (((tf3.nt) % (32)) == 0) { if ((tf3.nt) != 0) { (tf3.
t) = incmem((tf3.t), (tf3.nt) * sizeof(rt), ((tf3.nt) + (32))
* sizeof(rt)); } else { (tf3.t) = malloc((32) * sizeof(rt));
} } (tf3.t)[(tf3.nt) ++] = (rt); } while (0)
;
1168 continue;
1169 }
1170 aol(tf3.t, tf3.nt, *ct, TOKEN_LIST_MEMG)do { if (((tf3.nt) % (32)) == 0) { if ((tf3.nt) != 0) { (tf3.
t) = incmem((tf3.t), (tf3.nt) * sizeof(*ct), ((tf3.nt) + (32)
) * sizeof(*ct)); } else { (tf3.t) = malloc((32) * sizeof(*ct
)); } } (tf3.t)[(tf3.nt) ++] = (*ct); } while (0)
;
1171 }
1172 freememfree(tf2.t);
1173
1174 if (tf3.nt == 0) {
1175 errorucpp_error(l, "void condition (after expansion) for a #if/#elif");
1176 return -1;
1177 }
1178 eval_lineucpp_eval_line = l;
1179 z = eval_exprucpp_eval_expr(&tf3, &ret, (ls->flags & WARN_STANDARD0x000001UL) != 0);
1180 freememfree(tf3.t);
1181 if (ret) return -1;
1182 return (z != 0);
1183
1184error1:
1185 if (tf1.nt) freememfree(tf1.t);
1186 if (tf2.nt) freememfree(tf2.t);
1187 return -1;
1188}
1189
1190/*
1191 * A #include was found; parse the end of line, replace macros if
1192 * necessary.
1193 *
1194 * If nex is set to non-zero, the directive is considered as a #include_next
1195 * (extension to C99, mimicked from GNU)
1196 */
1197static int handle_include(struct lexer_state *ls, unsigned long flags, int nex)
1198{
1199 int c, string_fname = 0;
1200 char *fname;
1201 unsigned char *fname2;
1202 size_t fname_ptr = 0;
1203 long l = ls->line;
1204 int x, y;
1205 FILE *f;
1206 struct token_fifo tf, tf2, *save_tf;
1207 size_t nl;
1208 int tgd;
1209 struct lexer_state alt_ls;
1210
1211#define left_angle(t) ((t) == LT || (t) == LEQ || (t) == LSH \
1212 || (t) == ASLSH || (t) == DIG_LBRK || (t) == LBRA)
1213#define right_angle(t) ((t) == GT || (t) == RSH || (t) == ARROW \
1214 || (t) == DIG_RBRK || (t) == DIG_RBRA)
1215
1216 while ((c = grap_charucpp_grap_char(ls)) >= 0 && c != '\n') {
1217 if (space_charucpp_space_char(c)) {
1218 discard_charucpp_discard_char(ls);
1219 continue;
1220 }
1221 if (c == '<') {
1222 discard_charucpp_discard_char(ls);
1223 while ((c = grap_charucpp_grap_char(ls)) >= 0) {
1224 discard_charucpp_discard_char(ls);
1225 if (c == '\n') goto include_last_chance;
1226 if (c == '>') break;
1227 aol(fname, fname_ptr, (char)c, FNAME_MEMG)do { if (((fname_ptr) % (32)) == 0) { if ((fname_ptr) != 0) {
(fname) = incmem((fname), (fname_ptr) * sizeof((char)c), ((fname_ptr
) + (32)) * sizeof((char)c)); } else { (fname) = malloc((32) *
sizeof((char)c)); } } (fname)[(fname_ptr) ++] = ((char)c); }
while (0)
;
1228 }
1229 aol(fname, fname_ptr, (char)0, FNAME_MEMG)do { if (((fname_ptr) % (32)) == 0) { if ((fname_ptr) != 0) {
(fname) = incmem((fname), (fname_ptr) * sizeof((char)0), ((fname_ptr
) + (32)) * sizeof((char)0)); } else { (fname) = malloc((32) *
sizeof((char)0)); } } (fname)[(fname_ptr) ++] = ((char)0); }
while (0)
;
1230 string_fname = 0;
1231 goto do_include;
1232 } else if (c == '"') {
1233 discard_charucpp_discard_char(ls);
1234 while ((c = grap_charucpp_grap_char(ls)) >= 0) {
1235 discard_charucpp_discard_char(ls);
1236 if (c == '\n') {
1237 /* macro replacements won't save that one */
1238 if (fname_ptr) freememfree(fname);
1239 goto include_error;
1240 }
1241 if (c == '"') break;
1242 aol(fname, fname_ptr, (char)c, FNAME_MEMG)do { if (((fname_ptr) % (32)) == 0) { if ((fname_ptr) != 0) {
(fname) = incmem((fname), (fname_ptr) * sizeof((char)c), ((fname_ptr
) + (32)) * sizeof((char)c)); } else { (fname) = malloc((32) *
sizeof((char)c)); } } (fname)[(fname_ptr) ++] = ((char)c); }
while (0)
;
1243 }
1244 aol(fname, fname_ptr, (char)0, FNAME_MEMG)do { if (((fname_ptr) % (32)) == 0) { if ((fname_ptr) != 0) {
(fname) = incmem((fname), (fname_ptr) * sizeof((char)0), ((fname_ptr
) + (32)) * sizeof((char)0)); } else { (fname) = malloc((32) *
sizeof((char)0)); } } (fname)[(fname_ptr) ++] = ((char)0); }
while (0)
;
1245 string_fname = 1;
1246 goto do_include;
1247 }
1248 goto include_macro;
1249 }
1250
1251include_last_chance:
1252 /*
1253 * We found a '<' but not the trailing '>'; so we tokenize the
1254 * line, and try to act upon it. The standard lets us free in that
1255 * matter, and no sane programmer would use such a construct, but
1256 * it is no reason not to support it.
1257 */
1258 if (fname_ptr == 0) goto include_error;
1259 fname2 = getmemmalloc(fname_ptr + 1);
1260 mmvmemcpy(fname2 + 1, fname, fname_ptr);
1261 fname2[0] = '<';
1262 /*
1263 * We merely copy the lexer_state structure; this should be ok,
1264 * since we do want to share the memory structure (garbage_fifo),
1265 * and do not touch any other context-full thing.
1266 */
1267 alt_ls = *ls;
1268 alt_ls.input = 0;
1269 alt_ls.input_string = fname2;
1270 alt_ls.pbuf = 0;
1271 alt_ls.ebuf = fname_ptr + 1;
1272 tf.art = tf.nt = 0;
1273 while (!next_tokenucpp_next_token(&alt_ls)) {
1274 if (!ttMWS(alt_ls.ctok->type)((alt_ls.ctok->type) == NONE || (alt_ls.ctok->type) == COMMENT
|| (alt_ls.ctok->type) == OPT_NONE)
) {
1275 struct token t;
1276
1277 t.type = alt_ls.ctok->type;
1278 t.line = l;
1279 if (S_TOKEN(alt_ls.ctok->type)((alt_ls.ctok->type) >= NUMBER && (alt_ls.ctok->
type) <= CHAR)
) {
1280 t.name = sdup(alt_ls.ctok->name);
1281 throw_awayucpp_throw_away(alt_ls.gf, t.name);
1282 }
1283 aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG)do { if (((tf.nt) % (32)) == 0) { if ((tf.nt) != 0) { (tf.t) =
incmem((tf.t), (tf.nt) * sizeof(t), ((tf.nt) + (32)) * sizeof
(t)); } else { (tf.t) = malloc((32) * sizeof(t)); } } (tf.t)[
(tf.nt) ++] = (t); } while (0)
;
1284 }
1285 }
1286 freememfree(fname2);
1287 if (alt_ls.pbuf < alt_ls.ebuf) goto include_error;
1288 /* tokenizing failed */
1289 goto include_macro2;
1290
1291include_error:
1292 errorucpp_error(l, "invalid '#include'");
1293 return 1;
1294
1295include_macro:
1296 tf.art = tf.nt = 0;
1297 while (!next_tokenucpp_next_token(ls) && ls->ctok->type != NEWLINE) {
1298 if (!ttMWS(ls->ctok->type)((ls->ctok->type) == NONE || (ls->ctok->type) == COMMENT
|| (ls->ctok->type) == OPT_NONE)
) {
1299 struct token t;
1300
1301 t.type = ls->ctok->type;
1302 t.line = l;
1303 if (S_TOKEN(ls->ctok->type)((ls->ctok->type) >= NUMBER && (ls->ctok->
type) <= CHAR)
) {
1304 t.name = sdup(ls->ctok->name);
1305 throw_awayucpp_throw_away(ls->gf, t.name);
1306 }
1307 aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG)do { if (((tf.nt) % (32)) == 0) { if ((tf.nt) != 0) { (tf.t) =
incmem((tf.t), (tf.nt) * sizeof(t), ((tf.nt) + (32)) * sizeof
(t)); } else { (tf.t) = malloc((32) * sizeof(t)); } } (tf.t)[
(tf.nt) ++] = (t); } while (0)
;
1308 }
1309 }
1310include_macro2:
1311 tf2.art = tf2.nt = 0;
1312 save_tf = ls->output_fifo;
1313 ls->output_fifo = &tf2;
1314 while (tf.art < tf.nt) {
1315 struct token *ct;
1316
1317 ct = tf.t + (tf.art ++);
1318 if (ct->type == NAME) {
1319 struct macro *m = get_macroucpp_get_macro(ct->name);
1320 if (m) {
1321 if (substitute_macroucpp_substitute_macro(ls, m, &tf, 0,
1322#ifdef NO_PRAGMA_IN_DIRECTIVE
1323 1,
1324#else
1325 0,
1326#endif
1327 ct->line)) {
1328 ls->output_fifo = save_tf;
1329 return -1;
1330 }
1331 continue;
1332 }
1333 }
1334 aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG)do { if (((tf2.nt) % (32)) == 0) { if ((tf2.nt) != 0) { (tf2.
t) = incmem((tf2.t), (tf2.nt) * sizeof(*ct), ((tf2.nt) + (32)
) * sizeof(*ct)); } else { (tf2.t) = malloc((32) * sizeof(*ct
)); } } (tf2.t)[(tf2.nt) ++] = (*ct); } while (0)
;
1335 }
1336 freememfree(tf.t);
1337 ls->output_fifo = save_tf;
1338 for (x = 0; (size_t)x < tf2.nt && ttWHI(tf2.t[x].type)(((tf2.t[x].type) == NONE || (tf2.t[x].type) == COMMENT || (tf2
.t[x].type) == OPT_NONE) || (tf2.t[x].type) == NEWLINE)
; x ++);
1339 for (y = tf2.nt - 1; y >= 0 && ttWHI(tf2.t[y].type)(((tf2.t[y].type) == NONE || (tf2.t[y].type) == COMMENT || (tf2
.t[y].type) == OPT_NONE) || (tf2.t[y].type) == NEWLINE)
; y --);
1340 if ((size_t)x >= tf2.nt) goto include_macro_err;
1341 if (tf2.t[x].type == STRING) {
1342 if (y != x) goto include_macro_err;
1343 if (tf2.t[x].name[0] == 'L') {
1344 if (ls->flags & WARN_STANDARD0x000001UL)
1345 warningucpp_warning(l, "wide string for #include");
1346 fname = sdup(tf2.t[x].name);
1347 nl = strlen(fname);
1348 *(fname + nl - 1) = 0;
1349 mmvwomemmove(fname, fname + 2, nl - 2);
1350 } else {
1351 fname = sdup(tf2.t[x].name);
1352 nl = strlen(fname);
1353 *(fname + nl - 1) = 0;
1354 mmvwomemmove(fname, fname + 1, nl - 1);
1355 }
1356 string_fname = 1;
1357 } else if (left_angle(tf2.t[x].type) && right_angle(tf2.t[y].type)) {
1358 int i, j;
1359
1360 if (ls->flags & WARN_ANNOYING0x000002UL) warningucpp_warning(l, "reconstruction "
1361 "of <foo> in #include");
1362 for (j = 0, i = x; i <= y; i ++) if (!ttWHI(tf2.t[i].type)(((tf2.t[i].type) == NONE || (tf2.t[i].type) == COMMENT || (tf2
.t[i].type) == OPT_NONE) || (tf2.t[i].type) == NEWLINE)
)
1363 j += strlen(tname(tf2.t[i])((((tf2.t[i]).type) >= NUMBER && ((tf2.t[i]).type)
<= CHAR) ? (tf2.t[i]).name : operators_name[(tf2.t[i]).type
])
);
1364 fname = getmemmalloc(j + 1);
1365 for (j = 0, i = x; i <= y; i ++) {
1366 if (ttWHI(tf2.t[i].type)(((tf2.t[i].type) == NONE || (tf2.t[i].type) == COMMENT || (tf2
.t[i].type) == OPT_NONE) || (tf2.t[i].type) == NEWLINE)
) continue;
1367 strcpy(fname + j, tname(tf2.t[i])((((tf2.t[i]).type) >= NUMBER && ((tf2.t[i]).type)
<= CHAR) ? (tf2.t[i]).name : operators_name[(tf2.t[i]).type
])
);
1368 j += strlen(tname(tf2.t[i])((((tf2.t[i]).type) >= NUMBER && ((tf2.t[i]).type)
<= CHAR) ? (tf2.t[i]).name : operators_name[(tf2.t[i]).type
])
);
1369 }
1370 *(fname + j - 1) = 0;
1371 mmvwomemmove(fname, fname + 1, j);
1372 string_fname = 0;
1373 } else goto include_macro_err;
1374 freememfree(tf2.t);
1375 goto do_include_next;
1376
1377include_macro_err:
1378 errorucpp_error(l, "macro expansion did not produce a valid filename "
1379 "for #include");
1380 if (tf2.nt) freememfree(tf2.t);
1381 return 1;
1382
1383do_include:
1384 tgd = 1;
1385 while (!next_tokenucpp_next_token(ls)) {
1386 if (tgd && !ttWHI(ls->ctok->type)(((ls->ctok->type) == NONE || (ls->ctok->type) ==
COMMENT || (ls->ctok->type) == OPT_NONE) || (ls->ctok
->type) == NEWLINE)
1387 && (ls->flags & WARN_STANDARD0x000001UL)) {
1388 warningucpp_warning(l, "trailing garbage in #include");
1389 tgd = 0;
1390 }
1391 if (ls->ctok->type == NEWLINE) break;
1392 }
1393
1394 /* the increment of ls->line is intended so that the line
1395 numbering is reported correctly in report_context() even if
1396 the #include is at the end of the file with no trailing newline */
1397 if (ls->ctok->type != NEWLINE) ls->line ++;
1398do_include_next:
1399 if (!(ls->flags & LEXER0x010000UL) && (ls->flags & KEEP_OUTPUT0x020000UL))
1400 put_charucpp_put_char(ls, '\n');
1401 push_file_context(ls);
1402 reinit_lexer_state(ls, 1);
1403#ifdef MSDOS
1404 /* on msdos systems, replace all / by \ */
1405 {
1406 char *d;
1407
1408 for (d = fname; *d; d ++) if (*d == '/') *d = '\\';
1409 }
1410#endif
1411 f = nex ? find_file_next(fname) : find_file(fname, string_fname);
1412 if (!f) {
1413 current_filename = 0;
1414 pop_file_context(ls);
1415 if (find_file_error == FF_ERROR) {
1416 errorucpp_error(l, "file '%s' not found", fname);
1417 freememfree(fname);
1418 return 1;
1419 }
1420 /* file was found, but it is useless to include it again */
1421 freememfree(fname);
1422 return 0;
1423 }
1424#ifdef UCPP_MMAP
1425 set_input_file(ls, f);
1426#else
1427 ls->input = f;
1428#endif
1429 current_filename = fname;
1430 enter_file(ls, flags);
1431 return 0;
1432
1433#undef left_angle
1434#undef right_angle
1435}
1436
1437/*
1438 * for #line directives
1439 */
1440static int handle_line(struct lexer_state *ls, unsigned long flags)
1441{
1442 char *fname;
1443 long l = ls->line;
1444 struct token_fifo tf, tf2, *save_tf;
1445 size_t nl, j;
1446 unsigned long z;
1447
1448 tf.art = tf.nt = 0;
1449 while (!next_tokenucpp_next_token(ls) && ls->ctok->type != NEWLINE) {
1450 if (!ttMWS(ls->ctok->type)((ls->ctok->type) == NONE || (ls->ctok->type) == COMMENT
|| (ls->ctok->type) == OPT_NONE)
) {
1451 struct token t;
1452
1453 t.type = ls->ctok->type;
1454 t.line = l;
1455 if (S_TOKEN(ls->ctok->type)((ls->ctok->type) >= NUMBER && (ls->ctok->
type) <= CHAR)
) {
1456 t.name = sdup(ls->ctok->name);
1457 throw_awayucpp_throw_away(ls->gf, t.name);
1458 }
1459 aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG)do { if (((tf.nt) % (32)) == 0) { if ((tf.nt) != 0) { (tf.t) =
incmem((tf.t), (tf.nt) * sizeof(t), ((tf.nt) + (32)) * sizeof
(t)); } else { (tf.t) = malloc((32) * sizeof(t)); } } (tf.t)[
(tf.nt) ++] = (t); } while (0)
;
1460 }
1461 }
1462 tf2.art = tf2.nt = 0;
1463 save_tf = ls->output_fifo;
1464 ls->output_fifo = &tf2;
1465 while (tf.art < tf.nt) {
1466 struct token *ct;
1467
1468 ct = tf.t + (tf.art ++);
1469 if (ct->type == NAME) {
1470 struct macro *m = get_macroucpp_get_macro(ct->name);
1471 if (m) {
1472 if (substitute_macroucpp_substitute_macro(ls, m, &tf, 0,
1473#ifdef NO_PRAGMA_IN_DIRECTIVE
1474 1,
1475#else
1476 0,
1477#endif
1478 ct->line)) {
1479 ls->output_fifo = save_tf;
1480 return -1;
1481 }
1482 continue;
1483 }
1484 }
1485 aol(tf2.t, tf2.nt, *ct, TOKEN_LIST_MEMG)do { if (((tf2.nt) % (32)) == 0) { if ((tf2.nt) != 0) { (tf2.
t) = incmem((tf2.t), (tf2.nt) * sizeof(*ct), ((tf2.nt) + (32)
) * sizeof(*ct)); } else { (tf2.t) = malloc((32) * sizeof(*ct
)); } } (tf2.t)[(tf2.nt) ++] = (*ct); } while (0)
;
1486 }
1487 freememfree(tf.t);
1488 for (tf2.art = 0; tf2.art < tf2.nt && ttWHI(tf2.t[tf2.art].type)(((tf2.t[tf2.art].type) == NONE || (tf2.t[tf2.art].type) == COMMENT
|| (tf2.t[tf2.art].type) == OPT_NONE) || (tf2.t[tf2.art].type
) == NEWLINE)
;
1489 tf2.art ++);
1490 ls->output_fifo = save_tf;
1491 if (tf2.art == tf2.nt || (tf2.t[tf2.art].type != NUMBER
1492 && tf2.t[tf2.art].type != CHAR)) {
1493 errorucpp_error(l, "not a valid number for #line");
1494 goto line_macro_err;
1495 }
1496 for (j = 0; tf2.t[tf2.art].name[j]; j ++)
1497 if (tf2.t[tf2.art].name[j] < '0'
1498 || tf2.t[tf2.art].name[j] > '9')
1499 if (ls->flags & WARN_STANDARD0x000001UL)
1500 warningucpp_warning(l, "non-standard line number in #line");
1501 if (catch(eval_exception)_setjmp ((ucpp_eval_exception))) goto line_macro_err;
1502 z = strtoconstucpp_strtoconst(tf2.t[tf2.art].name);
1503 if (j > 10 || z > 2147483647U) {
1504 errorucpp_error(l, "out-of-bound line number for #line");
1505 goto line_macro_err;
1506 }
1507 ls->oline = ls->line = z;
1508 if ((++ tf2.art) < tf2.nt) {
1509 size_t i;
1510
1511 for (i = tf2.art; i < tf2.nt && ttMWS(tf2.t[i].type)((tf2.t[i].type) == NONE || (tf2.t[i].type) == COMMENT || (tf2
.t[i].type) == OPT_NONE)
; i ++);
1512 if (i < tf2.nt) {
1513 if (tf2.t[i].type != STRING) {
1514 errorucpp_error(l, "not a valid filename for #line");
1515 goto line_macro_err;
1516 }
1517 if (tf2.t[i].name[0] == 'L') {
1518 if (ls->flags & WARN_STANDARD0x000001UL) {
1519 warningucpp_warning(l, "wide string for #line");
1520 }
1521 fname = sdup(tf2.t[i].name);
1522 nl = strlen(fname);
1523 *(fname + nl - 1) = 0;
1524 mmvwomemmove(fname, fname + 2, nl - 2);
1525 } else {
1526 fname = sdup(tf2.t[i].name);
1527 nl = strlen(fname);
1528 *(fname + nl - 1) = 0;
1529 mmvwomemmove(fname, fname + 1, nl - 1);
1530 }
1531 if (current_filename) freememfree(current_filename);
1532 current_filename = fname;
1533 }
1534 for (i ++; i < tf2.nt && ttMWS(tf2.t[i].type)((tf2.t[i].type) == NONE || (tf2.t[i].type) == COMMENT || (tf2
.t[i].type) == OPT_NONE)
; i ++);
1535 if (i < tf2.nt && (ls->flags & WARN_STANDARD0x000001UL)) {
1536 warningucpp_warning(l, "trailing garbage in #line");
1537 }
1538 }
1539 freememfree(tf2.t);
1540 enter_file(ls, flags);
1541 return 0;
1542
1543line_macro_err:
1544 if (tf2.nt) freememfree(tf2.t);
1545 return 1;
1546}
1547
1548/*
1549 * a #error directive: we emit the message without any modification
1550 * (except the usual backslash+newline and trigraphs)
1551 */
1552static void handle_error(struct lexer_state *ls)
1553{
1554 int c;
1555 size_t p = 0, lp = 128;
1556 long l = ls->line;
1557 unsigned char *buf = getmemmalloc(lp);
1558
1559 while ((c = grap_charucpp_grap_char(ls)) >= 0 && c != '\n') {
1560 discard_charucpp_discard_char(ls);
1561 wan(buf, p, (unsigned char)c, lp)do { if ((p) == (lp)) { (lp) += (lp); (buf) = incmem((buf), (
p) * sizeof((unsigned char)c), (lp) * sizeof((unsigned char)c
)); } (buf)[(p) ++] = ((unsigned char)c); } while (0)
;
1562 }
1563 wan(buf, p, 0, lp)do { if ((p) == (lp)) { (lp) += (lp); (buf) = incmem((buf), (
p) * sizeof(0), (lp) * sizeof(0)); } (buf)[(p) ++] = (0); } while
(0)
;
1564 errorucpp_error(l, "#error%s", buf);
1565 freememfree(buf);
1566}
1567
1568/*
1569 * convert digraph tokens to their standard equivalent.
1570 */
1571static int undig(int type)
1572{
1573 static int ud[6] = { LBRK, RBRK, LBRA, RBRA, SHARP, DSHARP };
1574
1575 return ud[type - DIG_LBRK];
1576}
1577
1578#ifdef PRAGMA_TOKENIZE
1579/*
1580 * Make a compressed representation of a token list; the contents of
1581 * the token_fifo are freed. Values equal to 0 are replaced by
1582 * PRAGMA_TOKEN_END (by default, (unsigned char)'\n') and the compressed
1583 * string is padded by a 0 (so that it may be * handled like a string).
1584 * Digraph tokens are replaced by their non-digraph equivalents.
1585 */
1586struct comp_token_fifo compress_token_listucpp_compress_token_list(struct token_fifo *tf)
1587{
1588 struct comp_token_fifo ct;
1589 size_t l;
1590
1591 for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
1592 l ++;
1593 if (S_TOKEN(tf->t[tf->art].type)((tf->t[tf->art].type) >= NUMBER && (tf->
t[tf->art].type) <= CHAR)
)
1594 l += strlen(tf->t[tf->art].name) + 1;
1595 }
1596 ct.t = getmemmalloc((ct.length = l) + 1);
1597 for (l = 0, tf->art = 0; tf->art < tf->nt; tf->art ++) {
1598 int tt = tf->t[tf->art].type;
1599
1600 if (tt == 0) tt = PRAGMA_TOKEN_END((unsigned char)'\n');
1601 if (tt > DIGRAPH_TOKENS && tt < DIGRAPH_TOKENS_END)
1602 tt = undig(tt);
1603 ct.t[l ++] = tt;
1604 if (S_TOKEN(tt)((tt) >= NUMBER && (tt) <= CHAR)) {
1605 char *tn = tf->t[tf->art].name;
1606 size_t sl = strlen(tn);
1607
1608 mmvmemcpy(ct.t + l, tn, sl);
1609 l += sl;
1610 ct.t[l ++] = PRAGMA_TOKEN_END((unsigned char)'\n');
1611 freememfree(tn);
1612 }
1613 }
1614 ct.t[l] = 0;
1615 if (tf->nt) freememfree(tf->t);
1616 ct.rp = 0;
1617 return ct;
1618}
1619#endif
1620
1621/*
1622 * A #pragma directive: we make a PRAGMA token containing the rest of
1623 * the line.
1624 *
1625 * We strongly hope that we are called only in LEXER mode.
1626 */
1627static void handle_pragma(struct lexer_state *ls)
1628{
1629 unsigned char *buf;
1630 struct token t;
1631 long l = ls->line;
1632
1633#ifdef PRAGMA_TOKENIZE
1634 struct token_fifo tf;
1635
1636 tf.art = tf.nt = 0;
1637 while (!next_tokenucpp_next_token(ls) && ls->ctok->type != NEWLINE)
1638 if (!ttMWS(ls->ctok->type)((ls->ctok->type) == NONE || (ls->ctok->type) == COMMENT
|| (ls->ctok->type) == OPT_NONE)
) break;
1639 if (ls->ctok->type != NEWLINE) {
1640 do {
1641 struct token t;
1642
1643 t.type = ls->ctok->type;
1644 if (ttMWS(t.type)((t.type) == NONE || (t.type) == COMMENT || (t.type) == OPT_NONE
)
) continue;
1645 if (S_TOKEN(t.type)((t.type) >= NUMBER && (t.type) <= CHAR)) t.name = sdup(ls->ctok->name);
1646 aol(tf.t, tf.nt, t, TOKEN_LIST_MEMG)do { if (((tf.nt) % (32)) == 0) { if ((tf.nt) != 0) { (tf.t) =
incmem((tf.t), (tf.nt) * sizeof(t), ((tf.nt) + (32)) * sizeof
(t)); } else { (tf.t) = malloc((32) * sizeof(t)); } } (tf.t)[
(tf.nt) ++] = (t); } while (0)
;
1647 } while (!next_tokenucpp_next_token(ls) && ls->ctok->type != NEWLINE);
1648 }
1649 if (tf.nt == 0) {
1650 /* void pragma are silently ignored */
1651 return;
1652 }
1653 buf = (compress_token_listucpp_compress_token_list(&tf)).t;
1654#else
1655 int c, x = 1, y = 32;
1656
1657 while ((c = grap_charucpp_grap_char(ls)) >= 0 && c != '\n') {
1658 discard_charucpp_discard_char(ls);
1659 if (!space_charucpp_space_char(c)) break;
1660 }
1661 /* void #pragma are ignored */
1662 if (c == '\n') return;
1663 buf = getmemmalloc(y);
1664 buf[0] = c;
1665 while ((c = grap_charucpp_grap_char(ls)) >= 0 && c != '\n') {
1666 discard_charucpp_discard_char(ls);
1667 wan(buf, x, c, y)do { if ((x) == (y)) { (y) += (y); (buf) = incmem((buf), (x) *
sizeof(c), (y) * sizeof(c)); } (buf)[(x) ++] = (c); } while (
0)
;
1668 }
1669 for (x --; x >= 0 && space_charucpp_space_char(buf[x]); x --);
1670 x ++;
1671 wan(buf, x, 0, y)do { if ((x) == (y)) { (y) += (y); (buf) = incmem((buf), (x) *
sizeof(0), (y) * sizeof(0)); } (buf)[(x) ++] = (0); } while (
0)
;
1672#endif
1673 t.type = PRAGMA;
1674 t.line = l;
1675 t.name = (char *)buf;
1676 aol(ls->output_fifo->t, ls->output_fifo->nt, t, TOKEN_LIST_MEMG)do { if (((ls->output_fifo->nt) % (32)) == 0) { if ((ls
->output_fifo->nt) != 0) { (ls->output_fifo->t) =
incmem((ls->output_fifo->t), (ls->output_fifo->nt
) * sizeof(t), ((ls->output_fifo->nt) + (32)) * sizeof(
t)); } else { (ls->output_fifo->t) = malloc((32) * sizeof
(t)); } } (ls->output_fifo->t)[(ls->output_fifo->
nt) ++] = (t); } while (0)
;
1677 throw_awayucpp_throw_away(ls->gf, (char *)buf);
1678}
1679
1680/*
1681 * We saw a # at the beginning of a line (or preceeded only by whitespace).
1682 * We check the directive name and act accordingly.
1683 */
1684static int handle_cpp(struct lexer_state *ls, int sharp_type)
1685{
1686#define condfset(x) do { \
1687 ls->condf[(x) / 32] |= 1UL << ((x) % 32); \
1688 } while (0)
1689#define condfclr(x) do { \
1690 ls->condf[(x) / 32] &= ~(1UL << ((x) % 32)); \
1691 } while (0)
1692#define condfval(x) ((ls->condf[(x) / 32] & (1UL << ((x) % 32))) != 0)
1693
1694 long l = ls->line;
1695 unsigned long save_flags = ls->flags;
1696 int ret = 0;
1697
1698 save_flags = ls->flags;
1699 ls->flags |= LEXER0x010000UL;
1700 while (!next_tokenucpp_next_token(ls)) {
1701 int t = ls->ctok->type;
1702
1703 switch (t) {
1704 case COMMENT:
1705 if (ls->flags & WARN_ANNOYING0x000002UL) {
1706 warningucpp_warning(l, "comment in the middle of "
1707 "a cpp directive");
1708 }
1709 /* fall through */
1710 case NONE:
1711 continue;
1712 case NEWLINE:
1713 /* null directive */
1714 if (ls->flags & WARN_ANNOYING0x000002UL) {
1715 /* truly an annoying warning; null directives
1716 are rare but may increase readability of
1717 some source files, and they are legal */
1718 warningucpp_warning(l, "null cpp directive");
1719 }
1720 if (!(ls->flags & LEXER0x010000UL)) put_charucpp_put_char(ls, '\n');
1721 goto handle_exit2;
1722 case NAME:
1723 break;
1724 default:
1725 if (ls->flags & FAIL_SHARP0x000020UL) {
1726 /* LPS 20050602 - ignores '#!' if on the first line */
1727 if( ( l == 1 ) &&
1728 ( ls->condcomp ) )
1729 {
1730 ret = 1;
1731 }
1732 else
1733 /* LPS 20050602 */
1734 if (ls->condcomp) {
1735 errorucpp_error(l, "rogue '#'");
1736 ret = 1;
1737 } else {
1738 if (ls->flags & WARN_STANDARD0x000001UL) {
1739 warningucpp_warning(l, "rogue '#' in code "
1740 "compiled out");
1741 ret = 0;
1742 }
1743 }
1744 ls->flags = save_flags;
1745 goto handle_warp_ign;
1746 } else {
1747 struct token u;
1748
1749 u.type = sharp_type;
1750 u.line = l;
1751 ls->flags = save_flags;
1752 print_tokenucpp_print_token(ls, &u, 0);
1753 print_tokenucpp_print_token(ls, ls->ctok, 0);
1754 if (ls->flags & WARN_ANNOYING0x000002UL) {
1755 warningucpp_warning(l, "rogue '#' dumped");
1756 }
1757 goto handle_exit3;
1758 }
1759 }
1760 if (ls->condcomp) {
1761 if (!strcmp(ls->ctok->name, "define")) {
1762 ret = handle_defineucpp_handle_define(ls);
1763 goto handle_exit;
1764 } else if (!strcmp(ls->ctok->name, "undef")) {
1765 ret = handle_undefucpp_handle_undef(ls);
1766 goto handle_exit;
1767 } else if (!strcmp(ls->ctok->name, "if")) {
1768 if ((++ ls->ifnest) > 63) goto too_many_if;
1769 condfclr(ls->ifnest - 1);
1770 ret = handle_if(ls);
1771 if (ret > 0) ret = 0;
1772 else if (ret == 0) {
1773 ls->condcomp = 0;
1774 ls->condmet = 0;
1775 ls->condnest = ls->ifnest - 1;
1776 }
1777 else ret = 1;
1778 goto handle_exit;
1779 } else if (!strcmp(ls->ctok->name, "ifdef")) {
1780 if ((++ ls->ifnest) > 63) goto too_many_if;
1781 condfclr(ls->ifnest - 1);
1782 ret = handle_ifdefucpp_handle_ifdef(ls);
1783 if (ret > 0) ret = 0;
1784 else if (ret == 0) {
1785 ls->condcomp = 0;
1786 ls->condmet = 0;
1787 ls->condnest = ls->ifnest - 1;
1788 }
1789 else ret = 1;
1790 goto handle_exit;
1791 } else if (!strcmp(ls->ctok->name, "ifndef")) {
1792 if ((++ ls->ifnest) > 63) goto too_many_if;
1793 condfclr(ls->ifnest - 1);
1794 ret = handle_ifndefucpp_handle_ifndef(ls);
1795 if (ret > 0) ret = 0;
1796 else if (ret == 0) {
1797 ls->condcomp = 0;
1798 ls->condmet = 0;
1799 ls->condnest = ls->ifnest - 1;
1800 }
1801 else ret = 1;
1802 goto handle_exit;
1803 } else if (!strcmp(ls->ctok->name, "else")) {
1804 if (ls->ifnest == 0
1805 || condfval(ls->ifnest - 1)) {
1806 errorucpp_error(l, "rogue #else");
1807 ret = 1;
1808 goto handle_warp;
1809 }
1810 condfset(ls->ifnest - 1);
1811 if (ls->ifnest == 1) protect_detect.state = 0;
1812 ls->condcomp = 0;
1813 ls->condmet = 1;
1814 ls->condnest = ls->ifnest - 1;
1815 goto handle_warp;
1816 } else if (!strcmp(ls->ctok->name, "elif")) {
1817 if (ls->ifnest == 0
1818 || condfval(ls->ifnest - 1)) {
1819 errorucpp_error(l, "rogue #elif");
1820 ret = 1;
1821 goto handle_warp_ign;
1822 }
1823 if (ls->ifnest == 1) protect_detect.state = 0;
1824 ls->condcomp = 0;
1825 ls->condmet = 1;
1826 ls->condnest = ls->ifnest - 1;
1827 goto handle_warp_ign;
1828 } else if (!strcmp(ls->ctok->name, "endif")) {
1829 if (ls->ifnest == 0) {
1830 errorucpp_error(l, "unmatched #endif");
1831 ret = 1;
1832 goto handle_warp;
1833 }
1834 if ((-- ls->ifnest) == 0
1835 && protect_detect.state == 2) {
1836 protect_detect.state = 3;
1837 }
1838 goto handle_warp;
1839 } else if (!strcmp(ls->ctok->name, "include")) {
1840 ret = handle_include(ls, save_flags, 0);
1841 goto handle_exit3;
1842 } else if (!strcmp(ls->ctok->name, "include_next")) {
1843 ret = handle_include(ls, save_flags, 1);
1844 goto handle_exit3;
1845 } else if (!strcmp(ls->ctok->name, "pragma")) {
1846 if (!(save_flags & LEXER0x010000UL)) {
1847#ifdef PRAGMA_DUMP
1848 /* dump #pragma in output */
1849 struct token u;
1850
1851 u.type = sharp_type;
1852 u.line = l;
1853 ls->flags = save_flags;
1854 print_tokenucpp_print_token(ls, &u, 0);
1855 print_tokenucpp_print_token(ls, ls->ctok, 0);
1856 while (ls->flags |= LEXER0x010000UL,
1857 !next_tokenucpp_next_token(ls)) {
1858 long save_line;
1859
1860 ls->flags &= ~LEXER0x010000UL;
1861 save_line = ls->line;
1862 ls->line = l;
1863 print_tokenucpp_print_token(ls, ls->ctok, 0);
1864 ls->line = save_line;
1865 if (ls->ctok->type == NEWLINE)
1866 break;
1867 }
1868 goto handle_exit3;
1869#else
1870 if (ls->flags & WARN_PRAGMA0x000010UL)
1871 warningucpp_warning(l, "#pragma ignored "
1872 "and not dumped");
1873 goto handle_warp_ign;
1874#endif
1875 }
1876 if (!(ls->flags & HANDLE_PRAGMA0x001000UL))
1877 goto handle_warp_ign;
1878 handle_pragma(ls);
1879 goto handle_exit;
1880 } else if (!strcmp(ls->ctok->name, "error")) {
1881 ret = 1;
1882 handle_error(ls);
1883 goto handle_exit;
1884 } else if (!strcmp(ls->ctok->name, "line")) {
1885 ret = handle_line(ls, save_flags);
1886 goto handle_exit;
1887 } else if ((ls->flags & HANDLE_ASSERTIONS0x000800UL)
1888 && !strcmp(ls->ctok->name, "assert")) {
1889 ret = handle_assertucpp_handle_assert(ls);
1890 goto handle_exit;
1891 } else if ((ls->flags & HANDLE_ASSERTIONS0x000800UL)
1892 && !strcmp(ls->ctok->name, "unassert")) {
1893 ret = handle_unassertucpp_handle_unassert(ls);
1894 goto handle_exit;
1895 }
1896 } else {
1897 if (!strcmp(ls->ctok->name, "else")) {
1898 if (condfval(ls->ifnest - 1)
1899 && (ls->flags & WARN_STANDARD0x000001UL)) {
1900 warningucpp_warning(l, "rogue #else in code "
1901 "compiled out");
1902 }
1903 if (ls->condnest == ls->ifnest - 1) {
1904 if (!ls->condmet) ls->condcomp = 1;
1905 }
1906 condfset(ls->ifnest - 1);
1907 if (ls->ifnest == 1) protect_detect.state = 0;
1908 goto handle_warp;
1909 } else if (!strcmp(ls->ctok->name, "elif")) {
1910 if (condfval(ls->ifnest - 1)
1911 && (ls->flags & WARN_STANDARD0x000001UL)) {
1912 warningucpp_warning(l, "rogue #elif in code "
1913 "compiled out");
1914 }
1915 if (ls->condnest != ls->ifnest - 1
1916 || ls->condmet)
1917 goto handle_warp_ign;
1918 if (ls->ifnest == 1) protect_detect.state = 0;
1919 ret = handle_if(ls);
1920 if (ret > 0) {
1921 ls->condcomp = 1;
1922 ls->condmet = 1;
1923 ret = 0;
1924 } else if (ret < 0) ret = 1;
1925 goto handle_exit;
1926 } else if (!strcmp(ls->ctok->name, "endif")) {
1927 if ((-- ls->ifnest) == ls->condnest) {
1928 if (ls->ifnest == 0 &&
1929 protect_detect.state == 2)
1930 protect_detect.state = 3;
1931 ls->condcomp = 1;
1932 }
1933 goto handle_warp;
1934 } else if (!strcmp(ls->ctok->name, "if")
1935 || !strcmp(ls->ctok->name, "ifdef")
1936 || !strcmp(ls->ctok->name, "ifndef")) {
1937 if ((++ ls->ifnest) > 63) goto too_many_if;
1938 condfclr(ls->ifnest - 1);
1939 }
1940 goto handle_warp_ign;
1941 }
1942 /*
1943 * Unrecognized directive. We emit either an error or
1944 * an annoying warning, depending on a command-line switch.
1945 */
1946 if (ls->flags & FAIL_SHARP0x000020UL) {
1947 errorucpp_error(l, "unknown cpp directive '#%s'",
1948 ls->ctok->name);
1949 goto handle_warp_ign;
1950 } else {
1951 struct token u;
1952
1953 u.type = sharp_type;
1954 u.line = l;
1955 ls->flags = save_flags;
1956 print_tokenucpp_print_token(ls, &u, 0);
1957 print_tokenucpp_print_token(ls, ls->ctok, 0);
1958 if (ls->flags & WARN_ANNOYING0x000002UL) {
1959 warningucpp_warning(l, "rogue '#' dumped");
1960 }
1961 }
1962 }
1963 return 1;
1964
1965handle_warp_ign:
1966 while (!next_tokenucpp_next_token(ls)) if (ls->ctok->type == NEWLINE) break;
1967 goto handle_exit;
1968handle_warp:
1969 while (!next_tokenucpp_next_token(ls)) {
1970 if (!ttWHI(ls->ctok->type)(((ls->ctok->type) == NONE || (ls->ctok->type) ==
COMMENT || (ls->ctok->type) == OPT_NONE) || (ls->ctok
->type) == NEWLINE)
&& (ls->flags & WARN_STANDARD0x000001UL)) {
1971 warningucpp_warning(l, "trailing garbage in "
1972 "preprocessing directive");
1973 }
1974 if (ls->ctok->type == NEWLINE) break;
1975 }
1976handle_exit:
1977 if (!(ls->flags & LEXER0x010000UL)) put_charucpp_put_char(ls, '\n');
1978handle_exit3:
1979 if (protect_detect.state == 1) {
1980 protect_detect.state = 0;
1981 } else if (protect_detect.state == -1) {
1982 /* just after the #include */
1983 protect_detect.state = 1;
1984 }
1985handle_exit2:
1986 ls->flags = save_flags;
1987 return ret;
1988too_many_if:
1989 errorucpp_error(l, "too many levels of conditional inclusion (max 63)");
1990 ret = 1;
1991 goto handle_warp;
1992#undef condfset
1993#undef condfclr
1994#undef condfval
1995}
1996
1997/*
1998 * This is the main entry function. It maintains count of #, and call the
1999 * appropriate functions when it encounters a cpp directive or a macro
2000 * name.
2001 * return value: positive on error; CPPERR_EOF means "end of input reached"
2002 */
2003int cpp(struct lexer_state *ls)
2004{
2005 int r = 0;
2006
2007 while (next_tokenucpp_next_token(ls)) {
2008 if (protect_detect.state == 3) {
2009 /*
2010 * At that point, protect_detect.ff->protect might
2011 * be non-zero, if the file has been recursively
2012 * included, and a guardian detected.
2013 */
2014 if (!protect_detect.ff->protect) {
2015 /* Cool ! A new guardian has been detected. */
2016 protect_detect.ff->protect =
2017 protect_detect.macro;
2018 } else if (protect_detect.macro) {
2019 /* We found a guardian but an old one. */
2020 freememfree(protect_detect.macro);
2021 }
2022 protect_detect.macro = 0;
2023 }
2024 if (ls->ifnest) {
2025 errorucpp_error(ls->line, "unterminated #if construction "
2026 "(depth %ld)", ls->ifnest);
2027 r = CPPERR_NEST900;
2028 }
2029 if (ls_depth == 0) return CPPERR_EOF1000;
2030 close_input(ls);
2031 if (!(ls->flags & LEXER0x010000UL) && !ls->ltwnl) {
2032 put_charucpp_put_char(ls, '\n');
2033 ls->ltwnl = 1;
2034 }
2035 pop_file_context(ls);
2036 ls->oline ++;
2037 if (enter_file(ls, ls->flags)) {
2038 ls->ctok->type = NEWLINE;
2039 ls->ltwnl = 1;
2040 break;
2041 }
2042 }
2043 if (!(ls->ltwnl && (ls->ctok->type == SHARP
2044 || ls->ctok->type == DIG_SHARP))
2045 && protect_detect.state == 1 && !ttWHI(ls->ctok->type)(((ls->ctok->type) == NONE || (ls->ctok->type) ==
COMMENT || (ls->ctok->type) == OPT_NONE) || (ls->ctok
->type) == NEWLINE)
) {
2046 /* the first non-whitespace token encountered is not
2047 a sharp introducing a cpp directive */
2048 protect_detect.state = 0;
2049 }
2050 if (protect_detect.state == 3 && !ttWHI(ls->ctok->type)(((ls->ctok->type) == NONE || (ls->ctok->type) ==
COMMENT || (ls->ctok->type) == OPT_NONE) || (ls->ctok
->type) == NEWLINE)
) {
2051 /* a non-whitespace token encountered after the #endif */
2052 protect_detect.state = 0;
2053 }
2054 if (ls->condcomp) {
2055 if (ls->ltwnl && (ls->ctok->type == SHARP
2056 || ls->ctok->type == DIG_SHARP)) {
2057 int x = handle_cpp(ls, ls->ctok->type);
2058
2059 ls->ltwnl = 1;
2060 return r ? r : x;
2061 }
2062 if (ls->ctok->type == NAME) {
2063 struct macro *m;
2064
2065 if ((m = get_macroucpp_get_macro(ls->ctok->name)) != 0) {
2066 int x;
2067
2068 x = substitute_macroucpp_substitute_macro(ls, m, 0, 1, 0,
2069 ls->ctok->line);
2070 if (!(ls->flags & LEXER0x010000UL))
2071 garbage_collectucpp_garbage_collect(ls->gf);
2072 return r ? r : x;
2073 }
2074 if (!(ls->flags & LEXER0x010000UL))
2075 print_tokenucpp_print_token(ls, ls->ctok, 0);
2076 }
2077 } else {
2078 if (ls->ltwnl && (ls->ctok->type == SHARP
2079 || ls->ctok->type == DIG_SHARP)) {
2080 int x = handle_cpp(ls, ls->ctok->type);
2081
2082 ls->ltwnl = 1;
2083 return r ? r : x;
2084 }
2085 }
2086 if (ls->ctok->type == NEWLINE) ls->ltwnl = 1;
2087 else if (!ttWHI(ls->ctok->type)(((ls->ctok->type) == NONE || (ls->ctok->type) ==
COMMENT || (ls->ctok->type) == OPT_NONE) || (ls->ctok
->type) == NEWLINE)
) ls->ltwnl = 0;
2088 return r ? r : -1;
2089}
2090
2091#ifndef STAND_ALONE1
2092/*
2093 * llex() and lex() are the lexing functions, when the preprocessor is
2094 * linked to another code. llex() should be called only by lex().
2095 */
2096static int llex(struct lexer_state *ls)
2097{
2098 struct token_fifo *tf = ls->output_fifo;
2099 int r;
2100
2101 if (tf->nt != 0) {
2102 if (tf->art < tf->nt) {
2103#ifdef INMACRO_FLAG
2104 if (!ls->inmacro) {
2105 ls->inmacro = 1;
2106 ls->macro_count ++;
2107 }
2108#endif
2109 ls->ctok = tf->t + (tf->art ++);
2110 if (ls->ctok->type > DIGRAPH_TOKENS
2111 && ls->ctok->type < DIGRAPH_TOKENS_END) {
2112 ls->ctok->type = undig(ls->ctok->type);
2113 }
2114 return 0;
2115 } else {
2116#ifdef INMACRO_FLAG
2117 ls->inmacro = 0;
2118#endif
2119 freememfree(tf->t);
2120 tf->art = tf->nt = 0;
2121 garbage_collectucpp_garbage_collect(ls->gf);
2122 ls->ctok = ls->save_ctok;
2123 }
2124 }
2125 r = cpp(ls);
2126 if (ls->ctok->type > DIGRAPH_TOKENS
2127 && ls->ctok->type < LAST_MEANINGFUL_TOKEN) {
2128 ls->ctok->type = undig(ls->ctok->type);
2129 }
2130 if (r > 0) return r;
2131 if (r < 0) return 0;
2132 return llex(ls);
2133}
2134
2135/*
2136 * lex() reads the next token from the processed stream and stores it
2137 * into ls->ctok.
2138 * return value: non zero on error (including CPPERR_EOF, which is not
2139 * quite an error)
2140 */
2141int lex(struct lexer_state *ls)
2142{
2143 int r;
2144
2145 do {
2146 r = llex(ls);
2147#ifdef SEMPER_FIDELIS
2148 } while (!r && !ls->condcomp);
2149#else
2150 } while (!r && (!ls->condcomp || (ttWHI(ls->ctok->type)(((ls->ctok->type) == NONE || (ls->ctok->type) ==
COMMENT || (ls->ctok->type) == OPT_NONE) || (ls->ctok
->type) == NEWLINE)
&&
2151 (!(ls->flags & LINE_NUM0x000200UL) || ls->ctok->type != NEWLINE))));
2152#endif
2153 return r;
2154}
2155#endif
2156
2157/*
2158 * check_cpp_errors() must be called when the end of input is reached;
2159 * it checks pending errors due to truncated constructs (actually none,
2160 * this is reserved for future evolutions).
2161 */
2162int check_cpp_errors(struct lexer_state *ls)
2163{
2164 if (ls->flags & KEEP_OUTPUT0x020000UL) {
2165 put_charucpp_put_char(ls, '\n');
2166 }
2167 if (emit_dependencies) fputc('\n', emit_output);
2168#ifndef NO_UCPP_BUF1
2169 if (!(ls->flags & LEXER0x010000UL)) {
2170 flush_output(ls);
2171 }
2172#endif
2173 if ((ls->flags & WARN_TRIGRAPHS0x000004UL) && ls->count_trigraphs)
2174 warningucpp_warning(0, "%ld trigraph(s) encountered", ls->count_trigraphs);
2175 return 0;
2176}
2177
2178/*
2179 * init_cpp() initializes static tables inside ucpp. It needs not be
2180 * called more than once.
2181 */
2182void init_cpp(void)
2183{
2184 init_cppmucpp_init_cppm();
2185}
2186
2187/*
2188 * (re)init the global tables.
2189 * If standard_assertions is non 0, init the assertions table.
2190 */
2191void init_tables(int with_assertions)
2192{
2193 time_t t;
2194 struct tm *ct;
2195
2196 init_buf_lexer_stateucpp_init_buf_lexer_state(&dsharp_lexerucpp_dsharp_lexer, 0);
2197#ifdef PRAGMA_TOKENIZE
2198 init_buf_lexer_stateucpp_init_buf_lexer_state(&tokenize_lexerucpp_tokenize_lexer, 0);
2199#endif
2200 time(&t);
2201 ct = localtime(&t);
2202#ifdef NOSTRFTIME
2203 /* we have a quite old compiler, that does not know the
2204 (standard since 1990) strftime() function. */
2205 {
2206 char *c = asctime(ct);
2207
2208 compile_timeucpp_compile_time[0] = '"';
2209 mmvmemcpy(compile_timeucpp_compile_time + 1, c + 11, 8);
2210 compile_timeucpp_compile_time[9] = '"';
2211 compile_timeucpp_compile_time[10] = 0;
2212 compile_dateucpp_compile_date[0] = '"';
2213 mmvmemcpy(compile_dateucpp_compile_date + 1, c + 4, 7);
2214 mmvmemcpy(compile_dateucpp_compile_date + 8, c + 20, 4);
2215 compile_dateucpp_compile_date[12] = '"';
2216 compile_dateucpp_compile_date[13] = 0;
2217 }
2218#else
2219 strftime(compile_timeucpp_compile_time, 12, "\"%H:%M:%S\"", ct);
2220 strftime(compile_dateucpp_compile_date, 24, "\"%b %d %Y\"", ct);
2221#endif
2222 init_macros();
2223 if (with_assertions) init_assertions();
2224 init_found_files();
2225}
2226
2227/*
2228 * Resets the include path.
2229 */
2230void init_include_path(char *incpath[])
2231{
2232 if (include_path_nb) {
2233 size_t i;
2234
2235 for (i = 0; i < include_path_nb; i ++)
2236 freememfree(include_path[i]);
2237 freememfree(include_path);
2238 include_path_nb = 0;
2239 }
2240 if (incpath) {
2241 int i;
2242
2243 for (i = 0; incpath[i]; i ++)
2244 aol(include_path, include_path_nb,do { if (((include_path_nb) % (16)) == 0) { if ((include_path_nb
) != 0) { (include_path) = incmem((include_path), (include_path_nb
) * sizeof(sdup(incpath[i])), ((include_path_nb) + (16)) * sizeof
(sdup(incpath[i]))); } else { (include_path) = malloc((16) * sizeof
(sdup(incpath[i]))); } } (include_path)[(include_path_nb) ++]
= (sdup(incpath[i])); } while (0)
2245 sdup(incpath[i]), INCPATH_MEMG)do { if (((include_path_nb) % (16)) == 0) { if ((include_path_nb
) != 0) { (include_path) = incmem((include_path), (include_path_nb
) * sizeof(sdup(incpath[i])), ((include_path_nb) + (16)) * sizeof
(sdup(incpath[i]))); } else { (include_path) = malloc((16) * sizeof
(sdup(incpath[i]))); } } (include_path)[(include_path_nb) ++]
= (sdup(incpath[i])); } while (0)
;
2246 }
2247}
2248
2249/*
2250 * add_incpath() adds "path" to the standard include path.
2251 */
2252void add_incpath(char *path)
2253{
2254 aol(include_path, include_path_nb, sdup(path), INCPATH_MEMG)do { if (((include_path_nb) % (16)) == 0) { if ((include_path_nb
) != 0) { (include_path) = incmem((include_path), (include_path_nb
) * sizeof(sdup(path)), ((include_path_nb) + (16)) * sizeof(sdup
(path))); } else { (include_path) = malloc((16) * sizeof(sdup
(path))); } } (include_path)[(include_path_nb) ++] = (sdup(path
)); } while (0)
;
2255}
2256
2257/*
2258 * This function cleans the memory. It should release all allocated
2259 * memory structures and may be called even if the current pre-processing
2260 * is not finished or reported an error.
2261 */
2262void wipeout()
2263{
2264 struct lexer_state ls;
2265
2266 if (include_path_nb > 0) {
2267 size_t i;
2268
2269 for (i = 0; i < include_path_nb; i ++)
2270 freememfree(include_path[i]);
2271 freememfree(include_path);
2272 include_path = 0;
2273 include_path_nb = 0;
2274 }
2275 if (current_filename) freememfree(current_filename);
2276 current_filename = 0;
2277 current_long_filename = 0;
2278 current_incdir = -1;
2279 protect_detect.state = 0;
2280 if (protect_detect.macro) freememfree(protect_detect.macro);
2281 protect_detect.macro = 0;
2282 protect_detect.ff = 0;
2283 init_lexer_state(&ls);
2284 while (ls_depth > 0) pop_file_context(&ls);
2285 free_lexer_state(&ls);
2286 free_lexer_state(&dsharp_lexerucpp_dsharp_lexer);
2287#ifdef PRAGMA_TOKENIZE
2288 free_lexer_state(&tokenize_lexerucpp_tokenize_lexer);
2289#endif
2290 if (found_files_init_done) HTT_kill(&found_files);
2291 found_files_init_done = 0;
2292 if (found_files_sys_init_done) HTT_kill(&found_files_sys);
2293 found_files_sys_init_done = 0;
2294 wipe_macrosucpp_wipe_macros();
2295 wipe_assertionsucpp_wipe_assertions();
2296}
2297
2298#ifdef STAND_ALONE1
2299/*
2300 * print some help
2301 */
2302static void usage(char *command_name)
2303{
2304 fprintf(stderrstderr,
2305 "Usage: %s [options] [file]\n"
2306 "language options:\n"
2307 " -C keep comments in output\n"
2308 " -s keep '#' when no cpp directive is recognized\n"
2309 " -l do not emit line numbers\n"
2310 " -lg emit gcc-like line numbers\n"
2311 " -CC disable C++-like comments\n"
2312 " -a, -na, -a0 handle (or not) assertions\n"
2313 " -V disable macros with extra arguments\n"
2314 " -u understand UTF-8 in source\n"
2315 " -X enable -a, -u and -Y\n"
2316 " -c90 mimic C90 behaviour\n"
2317 " -t disable trigraph support\n"
2318 "warning options:\n"
2319 " -wt emit a final warning when trigaphs are encountered\n"
2320 " -wtt emit warnings for each trigaph encountered\n"
2321 " -wa emit warnings that are usually useless\n"
2322 " -w0 disable standard warnings\n"
2323 "directory options:\n"
2324 " -I directory add 'directory' before the standard include path\n"
2325 " -J directory add 'directory' after the standard include path\n"
2326 " -zI do not use the standard include path\n"
2327 " -M emit Makefile-like dependencies instead of normal "
2328 "output\n"
2329 " -Ma emit also dependancies for system files\n"
2330 " -o file store output in file\n"
2331 "macro and assertion options:\n"
2332 " -Dmacro predefine 'macro'\n"
2333 " -Dmacro=def predefine 'macro' with 'def' content\n"
2334 " -Umacro undefine 'macro'\n"
2335 " -Afoo(bar) assert foo(bar)\n"
2336 " -Bfoo(bar) unassert foo(bar)\n"
2337 " -Y predefine system-dependant macros\n"
2338 " -Z do not predefine special macros\n"
2339 " -d emit defined macros\n"
2340 " -e emit assertions\n"
2341 "misc options:\n"
2342 " -v print version number and settings\n"
2343 " -h show this help\n",
2344 command_name);
2345}
2346
2347/*
2348 * print version and compile-time settings
2349 */
2350static void version(void)
2351{
2352 size_t i;
2353
2354 fprintf(stderrstderr, "ucpp version %d.%d\n", VERS_MAJ1, VERS_MIN3);
2355 fprintf(stderrstderr, "search path:\n");
2356 for (i = 0; i < include_path_nb; i ++)
2357 fprintf(stderrstderr, " %s\n", include_path[i]);
2358}
2359
2360/*
2361 * parse_opt() initializes many things according to the command-line
2362 * options.
2363 * Return values:
2364 * 0 on success
2365 * 1 on semantic error (redefinition of a special macro, for instance)
2366 * 2 on syntaxic error (unknown options for instance)
2367 */
2368static int parse_opt(int argc, char *argv[], struct lexer_state *ls)
2369{
2370 int i, ret = 0;
2371 char *filename = 0;
2372 int with_std_incpath = 1;
2373 int print_version = 0, print_defs = 0, print_asserts = 0;
2374 int system_macros = 0, standard_assertions = 1;
2375
2376 init_lexer_state(ls);
2377 ls->flags = DEFAULT_CPP_FLAGS(0x000080UL | 0x000001UL | 0x000010UL | 0x000020UL | 0x002000UL
| 0x000100UL | 0x000200UL | 0x100000UL | 0x020000UL | 0x008000UL
| 0x000800UL)
;
2378 emit_output = ls->output = stdoutstdout;
2379 for (i = 1; i < argc; i ++) if (argv[i][0] == '-') {
2380 if (!strcmp(argv[i], "-h")) {
2381 return 2;
2382 } else if (!strcmp(argv[i], "-C")) {
2383 ls->flags &= ~DISCARD_COMMENTS0x000080UL;
2384 } else if (!strcmp(argv[i], "-CC")) {
2385 ls->flags &= ~CPLUSPLUS_COMMENTS0x000100UL;
2386 } else if (!strcmp(argv[i], "-a")) {
2387 ls->flags |= HANDLE_ASSERTIONS0x000800UL;
2388 } else if (!strcmp(argv[i], "-na")) {
2389 ls->flags |= HANDLE_ASSERTIONS0x000800UL;
2390 standard_assertions = 0;
2391 } else if (!strcmp(argv[i], "-a0")) {
2392 ls->flags &= ~HANDLE_ASSERTIONS0x000800UL;
2393 } else if (!strcmp(argv[i], "-V")) {
2394 ls->flags &= ~MACRO_VAARG0x002000UL;
2395 } else if (!strcmp(argv[i], "-u")) {
2396 ls->flags |= UTF8_SOURCE0x004000UL;
2397 } else if (!strcmp(argv[i], "-X")) {
2398 ls->flags |= HANDLE_ASSERTIONS0x000800UL;
2399 ls->flags |= UTF8_SOURCE0x004000UL;
2400 system_macros = 1;
2401 } else if (!strcmp(argv[i], "-c90")) {
2402 ls->flags &= ~MACRO_VAARG0x002000UL;
2403 ls->flags &= ~CPLUSPLUS_COMMENTS0x000100UL;
2404 c99_compliant = 0;
2405 c99_hosted = -1;
2406 } else if (!strcmp(argv[i], "-t")) {
2407 ls->flags &= ~HANDLE_TRIGRAPHS0x008000UL;
2408 } else if (!strcmp(argv[i], "-wt")) {
2409 ls->flags |= WARN_TRIGRAPHS0x000004UL;
2410 } else if (!strcmp(argv[i], "-wtt")) {
2411 ls->flags |= WARN_TRIGRAPHS_MORE0x000008UL;
2412 } else if (!strcmp(argv[i], "-wa")) {
2413 ls->flags |= WARN_ANNOYING0x000002UL;
2414 } else if (!strcmp(argv[i], "-w0")) {
2415 ls->flags &= ~WARN_STANDARD0x000001UL;
2416 ls->flags &= ~WARN_PRAGMA0x000010UL;
2417 } else if (!strcmp(argv[i], "-s")) {
2418 ls->flags &= ~FAIL_SHARP0x000020UL;
2419 } else if (!strcmp(argv[i], "-l")) {
2420 ls->flags &= ~LINE_NUM0x000200UL;
2421 } else if (!strcmp(argv[i], "-lg")) {
2422 ls->flags |= GCC_LINE_NUM0x000400UL;
2423 } else if (!strcmp(argv[i], "-M")) {
2424 ls->flags &= ~KEEP_OUTPUT0x020000UL;
2425 emit_dependencies = 1;
2426 } else if (!strcmp(argv[i], "-Ma")) {
2427 ls->flags &= ~KEEP_OUTPUT0x020000UL;
2428 emit_dependencies = 2;
2429 } else if (!strcmp(argv[i], "-Y")) {
2430 system_macros = 1;
2431 } else if (!strcmp(argv[i], "-Z")) {
2432 no_special_macros = 1;
2433 } else if (!strcmp(argv[i], "-d")) {
2434 ls->flags &= ~KEEP_OUTPUT0x020000UL;
2435 print_defs = 1;
2436 } else if (!strcmp(argv[i], "-e")) {
2437 ls->flags &= ~KEEP_OUTPUT0x020000UL;
2438 print_asserts = 1;
2439 } else if (!strcmp(argv[i], "-zI")) {
2440 with_std_incpath = 0;
2441 } else if (!strcmp(argv[i], "-I") || !strcmp(argv[i], "-J")) {
2442 i ++;
2443 } else if (!strcmp(argv[i], "-o")) {
2444 if ((++ i) >= argc) {
2445 errorucpp_error(-1, "missing filename after -o");
2446 return 2;
2447 }
2448 if (argv[i][0] == '-' && argv[i][1] == 0) {
2449 emit_output = ls->output = stdoutstdout;
2450 } else {
2451 ls->output = fopen(argv[i], "w");
2452 if (!ls->output) {
2453 errorucpp_error(-1, "failed to open for "
2454 "writing: %s", argv[i]);
2455 return 2;
2456 }
2457 emit_output = ls->output;
2458 }
2459 } else if (!strcmp(argv[i], "-v")) {
2460 print_version = 1;
2461 } else if (argv[i][1] != 'I' && argv[i][1] != 'J'
2462 && argv[i][1] != 'D' && argv[i][1] != 'U'
2463 && argv[i][1] != 'A' && argv[i][1] != 'B')
2464 warningucpp_warning(-1, "unknown option '%s'", argv[i]);
2465 } else {
2466 if (filename != 0) {
2467 errorucpp_error(-1, "spurious duplicate filename '%s' - vs. '%s' ", argv[i], filename);
2468 return 2;
2469 }
2470 filename = argv[i];
2471 }
2472 init_tables(ls->flags & HANDLE_ASSERTIONS0x000800UL);
2473 init_include_path(0);
2474 if (filename) {
2475#ifdef UCPP_MMAP
2476 FILE *f = fopen_mmap_file(filename);
2477
2478 ls->input = 0;
2479 if (f) set_input_file(ls, f);
2480#else
2481 ls->input = fopen(filename, "r");
2482#endif
2483 if (!ls->input) {
2484 errorucpp_error(-1, "file '%s' not found", filename);
2485 return 1;
2486 }
2487#ifdef NO_LIBC_BUF
2488 setbuf(ls->input, 0);
2489#endif
2490 set_init_filename(filename, 1);
2491 } else {
2492 ls->input = stdinstdin;
2493 set_init_filename("<stdin>", 0);
2494 }
2495 for (i = 1; i < argc; i ++)
2496 if (argv[i][0] == '-' && argv[i][1] == 'I')
2497 add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
2498 if (system_macros) for (i = 0; system_macros_def[i]; i ++)
2499 ret = ret || define_macro(ls, system_macros_def[i]);
2500 for (i = 1; i < argc; i ++)
2501 if (argv[i][0] == '-' && argv[i][1] == 'D')
2502 ret = ret || define_macro(ls, argv[i] + 2);
2503 for (i = 1; i < argc; i ++)
2504 if (argv[i][0] == '-' && argv[i][1] == 'U')
2505 ret = ret || undef_macro(ls, argv[i] + 2);
2506 if (ls->flags & HANDLE_ASSERTIONS0x000800UL) {
2507 if (standard_assertions)
2508 for (i = 0; system_assertions_def[i]; i ++)
2509 make_assertion(system_assertions_def[i]);
2510 for (i = 1; i < argc; i ++)
2511 if (argv[i][0] == '-' && argv[i][1] == 'A')
2512 ret = ret || make_assertion(argv[i] + 2);
2513 for (i = 1; i < argc; i ++)
2514 if (argv[i][0] == '-' && argv[i][1] == 'B')
2515 ret = ret || destroy_assertion(argv[i] + 2);
2516 } else {
2517 for (i = 1; i < argc; i ++)
2518 if (argv[i][0] == '-'
2519 && (argv[i][1] == 'A' || argv[i][1] == 'B'))
2520 warningucpp_warning(-1, "assertions disabled");
2521 }
2522 if (with_std_incpath) {
2523 for (i = 0; include_path_std[i]; i ++)
2524 add_incpath(include_path_std[i]);
2525 }
2526 for (i = 1; i < argc; i ++)
2527 if (argv[i][0] == '-' && argv[i][1] == 'J')
2528 add_incpath(argv[i][2] ? argv[i] + 2 : argv[i + 1]);
2529
2530 if (print_version) {
2531 version();
2532 return 1;
2533 }
2534 if (print_defs) {
2535 print_defines();
2536 emit_defines = 1;
2537 }
2538 if (print_asserts && (ls->flags & HANDLE_ASSERTIONS0x000800UL)) {
2539 print_assertions();
2540 emit_assertions = 1;
2541 }
2542 return ret;
2543}
2544
2545int main(int argc, char *argv[])
2546{
2547 struct lexer_state ls;
2548 int r, fr = 0;
2549
2550 init_cpp();
2551 if ((r = parse_opt(argc, argv, &ls)) != 0) {
2552 if (r == 2) usage(argv[0]);
2553 return EXIT_FAILURE1;
2554 }
2555 enter_file(&ls, ls.flags);
2556 while ((r = cpp(&ls)) < CPPERR_EOF1000) fr = fr || (r > 0);
2557 fr = fr || check_cpp_errors(&ls);
2558 free_lexer_state(&ls);
2559 wipeout();
2560#ifdef MEM_DEBUG
2561 report_leaks();
2562#endif
2563 return fr ? EXIT_FAILURE1 : EXIT_SUCCESS0;
2564}
2565#endif