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