source: mainline/uspace/app/pcc/cc/cpp/cpp.c@ b6759f4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b6759f4 was b6759f4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Fix conflict introduced in mainline.

  • Property mode set to 100644
File size: 37.7 KB
Line 
1/* $Id: cpp.c,v 1.124.2.2 2011/03/27 13:17:19 ragge Exp $ */
2
3/*
4 * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * The C preprocessor.
30 * This code originates from the V6 preprocessor with some additions
31 * from V7 cpp, and at last ansi/c99 support.
32 */
33
34#include "config.h"
35
36#ifdef HAVE_SYS_WAIT_H
37#include <sys/wait.h>
38#endif
39#include <sys/stat.h>
40
41#include <fcntl.h>
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45#include <stdio.h>
46#include <stdarg.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50#include <ctype.h>
51
52#include "compat.h"
53#include "cpp.h"
54#include "y.tab.h"
55
56#define SBSIZE 1000000
57
58static usch sbf[SBSIZE];
59/* C command */
60
61int tflag; /* traditional cpp syntax */
62#ifdef CPP_DEBUG
63int dflag; /* debug printouts */
64#define DPRINT(x) if (dflag) printf x
65#define DDPRINT(x) if (dflag > 1) printf x
66#else
67#define DPRINT(x)
68#define DDPRINT(x)
69#endif
70
71int ofd;
72usch outbuf[CPPBUF];
73int obufp, istty;
74int Cflag, Mflag, dMflag, Pflag;
75usch *Mfile;
76struct initar *initar;
77int readmac, lastoch;
78
79/* include dirs */
80struct incs {
81 struct incs *next;
82 usch *dir;
83 dev_t dev;
84 ino_t ino;
85} *incdir[2];
86#define INCINC 0
87#define SYSINC 1
88
89static struct symtab *filloc;
90static struct symtab *linloc;
91static struct symtab *pragloc;
92int trulvl;
93int flslvl;
94int elflvl;
95int elslvl;
96usch *stringbuf = sbf;
97
98/*
99 * Macro replacement list syntax:
100 * - For object-type macros, replacement strings are stored as-is.
101 * - For function-type macros, macro args are substituted for the
102 * character WARN followed by the argument number.
103 * - The value element points to the end of the string, to simplify
104 * pushback onto the input queue.
105 *
106 * The first character (from the end) in the replacement list is
107 * the number of arguments:
108 * VARG - ends with ellipsis, next char is argcount without ellips.
109 * OBJCT - object-type macro
110 * 0 - empty parenthesis, foo()
111 * 1-> - number of args.
112 *
113 * WARN is used:
114 * - in stored replacement lists to tell that an argument comes
115 * - When expanding replacement lists to tell that the list ended.
116 *
117 * To ensure that an already expanded identifier won't get expanded
118 * again a EBLOCK char + its number is stored directly before any
119 * expanded identifier.
120 */
121
122/* args for lookup() */
123#define FIND 0
124#define ENTER 1
125
126static int readargs(struct symtab *sp, const usch **args);
127void prline(const usch *s);
128static void prrep(const usch *s);
129static void exparg(int);
130static void subarg(struct symtab *sp, const usch **args, int);
131void define(void);
132void include(void);
133void include_next(void);
134void line(void);
135void flbuf(void);
136void usage(void);
137usch *xstrdup(const usch *str);
138static void addidir(char *idir, struct incs **ww);
139void imp(const char *);
140#define IMP(x) if (dflag>1) imp(x)
141
142int
143main(int argc, char **argv)
144{
145 struct initar *it;
146 struct symtab *nl;
147 register int ch;
148 const usch *fn1, *fn2;
149
150#ifdef TIMING
151 struct timeval t1, t2;
152
153 (void)gettimeofday(&t1, NULL);
154#endif
155
156 while ((ch = getopt(argc, argv, "CD:I:MPS:U:d:i:tvV?")) != -1)
157 switch (ch) {
158 case 'C': /* Do not discard comments */
159 Cflag++;
160 break;
161
162 case 'i': /* include */
163 case 'U': /* undef */
164 case 'D': /* define something */
165 /* XXX should not need malloc() here */
166 if ((it = malloc(sizeof(struct initar))) == NULL)
167 error("couldn't apply -%c %s", ch, optarg);
168 it->type = ch;
169 it->str = optarg;
170 it->next = initar;
171 initar = it;
172 break;
173
174 case 'M': /* Generate dependencies for make */
175 Mflag++;
176 break;
177
178 case 'P': /* Inhibit generation of line numbers */
179 Pflag++;
180 break;
181
182 case 'S':
183 case 'I':
184 addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
185 break;
186
187#ifdef CPP_DEBUG
188 case 'V':
189 dflag++;
190 break;
191#endif
192 case 'v':
193 printf("cpp: %s\n", VERSSTR);
194 break;
195 case 'd':
196 if (optarg[0] == 'M') {
197 dMflag = 1;
198 Mflag = 1;
199 }
200 /* ignore others */
201 break;
202
203 case 't':
204 tflag = 1;
205 break;
206
207 case '?':
208 usage();
209 default:
210 error("bad arg %c\n", ch);
211 }
212 argc -= optind;
213 argv += optind;
214
215 filloc = lookup((const usch *)"__FILE__", ENTER);
216 linloc = lookup((const usch *)"__LINE__", ENTER);
217 filloc->value = linloc->value = stringbuf;
218 savch(OBJCT);
219
220 /* create a complete macro for pragma */
221 pragloc = lookup((const usch *)"_Pragma", ENTER);
222 savch(0);
223 savstr((const usch *)"_Pragma(");
224 savch(0);
225 savch(WARN);
226 savch(')');
227 pragloc->value = stringbuf;
228 savch(1);
229
230 if (tflag == 0) {
231 time_t t = time(NULL);
232 usch *n = (usch *)ctime(&t);
233
234 /*
235 * Manually move in the predefined macros.
236 */
237 nl = lookup((const usch *)"__TIME__", ENTER);
238 savch(0); savch('"'); n[19] = 0; savstr(&n[11]); savch('"');
239 savch(OBJCT);
240 nl->value = stringbuf-1;
241
242 nl = lookup((const usch *)"__DATE__", ENTER);
243 savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
244 savstr(&n[20]); savch('"'); savch(OBJCT);
245 nl->value = stringbuf-1;
246
247 nl = lookup((const usch *)"__STDC__", ENTER);
248 savch(0); savch('1'); savch(OBJCT);
249 nl->value = stringbuf-1;
250
251 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
252 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
253 nl->value = stringbuf-1;
254 }
255
256 if (Mflag && !dMflag) {
257 usch *c;
258
259 if (argc < 1)
260 error("-M and no infile");
261 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
262 c = (usch *)argv[0];
263 else
264 c++;
265 Mfile = stringbuf;
266 savstr(c); savch(0);
267 if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
268 error("-M and no extension: ");
269 c[1] = 'o';
270 c[2] = 0;
271 }
272
273 if (argc == 2) {
274 if ((ofd = open(argv[1], O_WRONLY|O_CREAT, 0600)) < 0)
275 error("Can't creat %s", argv[1]);
276 } else
277 ofd = fileno(stdout);
278 istty = isatty(ofd);
279
280 if (argc && strcmp(argv[0], "-")) {
281 fn1 = fn2 = (usch *)argv[0];
282 } else {
283 fn1 = NULL;
284 fn2 = (const usch *)"";
285 }
286 if (pushfile(fn1, fn2, 0, NULL))
287 error("cannot open %s", argv[0]);
288
289 flbuf();
290 close(ofd);
291#ifdef TIMING
292 (void)gettimeofday(&t2, NULL);
293 t2.tv_sec -= t1.tv_sec;
294 t2.tv_usec -= t1.tv_usec;
295 if (t2.tv_usec < 0) {
296 t2.tv_usec += 1000000;
297 t2.tv_sec -= 1;
298 }
299 fprintf(stderr, "cpp total time: %ld s %ld us\n",
300 t2.tv_sec, t2.tv_usec);
301#endif
302 return 0;
303}
304
305static void
306addidir(char *idir, struct incs **ww)
307{
308 struct incs *w;
309 struct stat st;
310
311 if (stat(idir, &st) == -1 || S_ISDIR(st.st_mode) == 0)
312 return; /* ignore */
313 if (*ww != NULL) {
314 for (w = *ww; w->next; w = w->next) {
315 if (w->dev == st.st_dev && w->ino == st.st_ino)
316 return;
317 }
318 if (w->dev == st.st_dev && w->ino == st.st_ino)
319 return;
320 ww = &w->next;
321 }
322 if ((w = calloc(sizeof(struct incs), 1)) == NULL)
323 error("couldn't add path %s", idir);
324 w->dir = (usch *)idir;
325 w->dev = st.st_dev;
326 w->ino = st.st_ino;
327 *ww = w;
328}
329
330void
331line()
332{
333 static usch *lbuf;
334 static int llen;
335 usch *p;
336 int c;
337
338 if ((c = yylex()) != NUMBER)
339 goto bad;
340 ifiles->lineno = (int)(yylval.node.nd_val - 1);
341
342 if ((c = yylex()) == '\n')
343 return;
344
345 if (c != STRING)
346 goto bad;
347
348 p = (usch *)yytext;
349 if (*p == 'L')
350 p++;
351 c = strlen((char *)p);
352 if (llen < c) {
353 /* XXX may loose heap space */
354 lbuf = stringbuf;
355 stringbuf += c;
356 llen = c;
357 }
358 p[strlen((char *)p)-1] = 0;
359 if (strlcpy((char *)lbuf, (char *)&p[1], SBSIZE) >= SBSIZE)
360 error("line exceeded buffer size");
361
362 ifiles->fname = lbuf;
363 if (yylex() == '\n')
364 return;
365
366bad: error("bad line directive");
367}
368
369/*
370 * Search for and include next file.
371 * Return 1 on success.
372 */
373static int
374fsrch(const usch *fn, int idx, struct incs *w)
375{
376 int i;
377
378 for (i = idx; i < 2; i++) {
379 if (i > idx)
380 w = incdir[i];
381 for (; w; w = w->next) {
382 usch *nm = stringbuf;
383
384 savstr(w->dir); savch('/');
385 savstr(fn); savch(0);
386 if (pushfile(nm, fn, i, w->next) == 0)
387 return 1;
388 stringbuf = nm;
389 }
390 }
391 return 0;
392}
393
394/*
395 * Include a file. Include order:
396 * - For <...> files, first search -I directories, then system directories.
397 * - For "..." files, first search "current" dir, then as <...> files.
398 */
399void
400include()
401{
402 struct symtab *nl;
403 usch *osp;
404 usch *fn, *safefn;
405 int c;
406
407 if (flslvl)
408 return;
409 osp = stringbuf;
410
411 while ((c = sloscan()) == WSPACE)
412 ;
413 if (c == IDENT) {
414 /* sloscan() will not expand idents */
415 if ((nl = lookup((usch *)yytext, FIND)) == NULL)
416 goto bad;
417 if (kfind(nl))
418 unpstr(stringbuf);
419 else
420 unpstr(nl->namep);
421 stringbuf = osp;
422 c = yylex();
423 }
424 if (c != STRING && c != '<')
425 goto bad;
426
427 if (c == '<') {
428 fn = stringbuf;
429 while ((c = sloscan()) != '>' && c != '\n') {
430 if (c == '\n') /* XXX check - cannot reach */
431 goto bad;
432 savstr((usch *)yytext);
433 }
434 savch('\0');
435 while ((c = sloscan()) == WSPACE)
436 ;
437 if (c != '\n')
438 goto bad;
439 (void) SYSINC;
440 safefn = fn;
441 } else {
442 usch *nm = stringbuf;
443
444 yytext[strlen((char *)yytext)-1] = 0;
445 fn = (usch *)&yytext[1];
446 /* first try to open file relative to previous file */
447 /* but only if it is not an absolute path */
448 if (*fn != '/') {
449 savstr(ifiles->orgfn);
450 if ((stringbuf =
451 (usch *)strrchr((char *)nm, '/')) == NULL)
452 stringbuf = nm;
453 else
454 stringbuf++;
455 }
456 safefn = stringbuf;
457 savstr(fn); savch(0);
458 c = yylex();
459 if (c != '\n')
460 goto bad;
461 if (pushfile(nm, safefn, 0, NULL) == 0)
462 goto okret;
463 /* XXX may loose stringbuf space */
464 }
465
466 if (fsrch(safefn, 0, incdir[0]))
467 goto okret;
468
469 error("cannot find '%s'", safefn);
470 /* error() do not return */
471
472bad: error("bad include");
473 /* error() do not return */
474okret:
475 prtline();
476}
477
478void
479include_next()
480{
481 struct symtab *nl;
482 usch *osp;
483 usch *fn;
484 int c;
485
486 if (flslvl)
487 return;
488 osp = stringbuf;
489 while ((c = sloscan()) == WSPACE)
490 ;
491 if (c == IDENT) {
492 /* sloscan() will not expand idents */
493 if ((nl = lookup((usch *)yytext, FIND)) == NULL)
494 goto bad;
495 if (kfind(nl))
496 unpstr(stringbuf);
497 else
498 unpstr(nl->namep);
499 stringbuf = osp;
500 c = yylex();
501 }
502 if (c != STRING && c != '<')
503 goto bad;
504
505 fn = stringbuf;
506 if (c == STRING) {
507 savstr((usch *)&yytext[1]);
508 stringbuf[-1] = 0;
509 } else { /* < > */
510 while ((c = sloscan()) != '>') {
511 if (c == '\n')
512 goto bad;
513 savstr((usch *)yytext);
514 }
515 savch('\0');
516 }
517 while ((c = sloscan()) == WSPACE)
518 ;
519 if (c != '\n')
520 goto bad;
521
522 if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
523 error("cannot find '%s'", fn);
524 prtline();
525 return;
526
527bad: error("bad include");
528 /* error() do not return */
529}
530
531static int
532definp(void)
533{
534 int c;
535
536 do
537 c = sloscan();
538 while (c == WSPACE);
539 return c;
540}
541
542void
543getcmnt(void)
544{
545 int c;
546
547 savstr((usch *)yytext);
548 savch(cinput()); /* Lost * */
549 for (;;) {
550 c = cinput();
551 if (c == '*') {
552 c = cinput();
553 if (c == '/') {
554 savstr((const usch *)"*/");
555 return;
556 }
557 cunput(c);
558 c = '*';
559 }
560 savch(c);
561 }
562}
563
564/*
565 * Compare two replacement lists, taking in account comments etc.
566 */
567static int
568cmprepl(const usch *o, const usch *n)
569{
570 for (; *o; o--, n--) {
571 /* comment skip */
572 if (*o == '/' && o[-1] == '*') {
573 while (*o != '*' || o[-1] != '/')
574 o--;
575 o -= 2;
576 }
577 if (*n == '/' && n[-1] == '*') {
578 while (*n != '*' || n[-1] != '/')
579 n--;
580 n -= 2;
581 }
582 while (*o == ' ' || *o == '\t')
583 o--;
584 while (*n == ' ' || *n == '\t')
585 n--;
586 if (*o != *n)
587 return 1;
588 }
589 return 0;
590}
591
592static int
593isell(void)
594{
595 int ch;
596
597 if ((ch = cinput()) != '.') {
598 cunput(ch);
599 return 0;
600 }
601 if ((ch = cinput()) != '.') {
602 cunput(ch);
603 cunput('.');
604 return 0;
605 }
606 return 1;
607}
608
609void
610define()
611{
612 struct symtab *np;
613 usch *args[MAXARGS+1], *ubuf, *sbeg;
614 int c, i, redef;
615 int mkstr = 0, narg = -1;
616 int ellips = 0;
617#ifdef GCC_COMPAT
618 usch *gccvari = NULL;
619 int wascon;
620#endif
621
622 if (flslvl)
623 return;
624 if (sloscan() != WSPACE || sloscan() != IDENT)
625 goto bad;
626
627 if (isdigit((int)yytext[0]))
628 goto bad;
629
630 np = lookup((usch *)yytext, ENTER);
631 redef = np->value != NULL;
632
633 readmac = 1;
634 sbeg = stringbuf;
635 if ((c = sloscan()) == '(') {
636 narg = 0;
637 /* function-like macros, deal with identifiers */
638 c = definp();
639 for (;;) {
640 if (c == ')')
641 break;
642 if (c == '.' && isell()) {
643 ellips = 1;
644 if (definp() != ')')
645 goto bad;
646 break;
647 }
648 if (c == IDENT) {
649 /* make sure there is no arg of same name */
650 for (i = 0; i < narg; i++)
651 if (!strcmp((char *) args[i], (char *)yytext))
652 error("Duplicate macro "
653 "parameter \"%s\"", yytext);
654 if (narg == MAXARGS)
655 error("Too many macro args");
656 args[narg++] = xstrdup(yytext);
657 if ((c = definp()) == ',') {
658 if ((c = definp()) == ')')
659 goto bad;
660 continue;
661 }
662#ifdef GCC_COMPAT
663 if (c == '.' && isell()) {
664 if (definp() != ')')
665 goto bad;
666 gccvari = args[--narg];
667 break;
668 }
669#endif
670 if (c == ')')
671 break;
672 }
673 goto bad;
674 }
675 c = sloscan();
676 } else if (c == '\n') {
677 /* #define foo */
678 ;
679 } else if (c != WSPACE)
680 goto bad;
681
682 while (c == WSPACE)
683 c = sloscan();
684
685 /* replacement list cannot start with ## operator */
686 if (c == '#') {
687 if ((c = sloscan()) == '#')
688 goto bad;
689 savch('\0');
690#ifdef GCC_COMPAT
691 wascon = 0;
692#endif
693 goto in2;
694 }
695
696 /* parse replacement-list, substituting arguments */
697 savch('\0');
698 while (c != '\n') {
699#ifdef GCC_COMPAT
700 wascon = 0;
701loop:
702#endif
703 switch (c) {
704 case WSPACE:
705 /* remove spaces if it surrounds a ## directive */
706 ubuf = stringbuf;
707 savstr((usch *)yytext);
708 c = sloscan();
709 if (c == '#') {
710 if ((c = sloscan()) != '#')
711 goto in2;
712 stringbuf = ubuf;
713 savch(CONC);
714 if ((c = sloscan()) == WSPACE)
715 c = sloscan();
716#ifdef GCC_COMPAT
717 if (c == '\n')
718 break;
719 wascon = 1;
720 goto loop;
721#endif
722 }
723 continue;
724
725 case '#':
726 c = sloscan();
727 if (c == '#') {
728 /* concat op */
729 savch(CONC);
730 if ((c = sloscan()) == WSPACE)
731 c = sloscan();
732#ifdef GCC_COMPAT
733 if (c == '\n')
734 break;
735 wascon = 1;
736 goto loop;
737#else
738 continue;
739#endif
740 }
741in2: if (narg < 0) {
742 /* no meaning in object-type macro */
743 savch('#');
744 continue;
745 }
746 /* remove spaces between # and arg */
747 savch(SNUFF);
748 if (c == WSPACE)
749 c = sloscan(); /* whitespace, ignore */
750 mkstr = 1;
751 if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
752 continue;
753
754 /* FALLTHROUGH */
755 case IDENT:
756 if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
757 if (ellips == 0)
758 error("unwanted %s", yytext);
759#ifdef GCC_COMPAT
760 savch(wascon ? GCCARG : VARG);
761#else
762 savch(VARG);
763#endif
764
765 savch(WARN);
766 if (mkstr)
767 savch(SNUFF), mkstr = 0;
768 break;
769 }
770 if (narg < 0)
771 goto id; /* just add it if object */
772 /* check if its an argument */
773 for (i = 0; i < narg; i++)
774 if (strcmp((char *)yytext, (char *)args[i]) == 0)
775 break;
776 if (i == narg) {
777#ifdef GCC_COMPAT
778 if (gccvari &&
779 strcmp((char *)yytext, (char *)gccvari) == 0) {
780 savch(wascon ? GCCARG : VARG);
781 savch(WARN);
782 if (mkstr)
783 savch(SNUFF), mkstr = 0;
784 break;
785 }
786#endif
787 if (mkstr)
788 error("not argument");
789 goto id;
790 }
791 savch(i);
792 savch(WARN);
793 if (mkstr)
794 savch(SNUFF), mkstr = 0;
795 break;
796
797 case CMNT: /* save comments */
798 getcmnt();
799 break;
800
801 default:
802id: savstr((usch *)yytext);
803 break;
804 }
805 c = sloscan();
806 }
807 readmac = 0;
808 /* remove trailing whitespace */
809 while (stringbuf > sbeg) {
810 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
811 stringbuf--;
812 /* replacement list cannot end with ## operator */
813 else if (stringbuf[-1] == CONC)
814 goto bad;
815 else
816 break;
817 }
818#ifdef GCC_COMPAT
819 if (gccvari) {
820 savch(narg);
821 savch(VARG);
822 } else
823#endif
824 if (ellips) {
825 savch(narg);
826 savch(VARG);
827 } else
828 savch(narg < 0 ? OBJCT : narg);
829 if (redef && ifiles->idx != SYSINC) {
830 if (cmprepl(np->value, stringbuf-1)) {
831 sbeg = stringbuf;
832 np->value = stringbuf-1;
833 warning("%s redefined\nprevious define: %s:%d",
834 np->namep, np->file, np->line);
835 }
836 stringbuf = sbeg; /* forget this space */
837 } else
838 np->value = stringbuf-1;
839
840#ifdef CPP_DEBUG
841 if (dflag) {
842 const usch *w = np->value;
843
844 printf("!define: ");
845 if (*w == OBJCT)
846 printf("[object]");
847 else if (*w == VARG)
848 printf("[VARG%d]", *--w);
849 while (*--w) {
850 switch (*w) {
851 case WARN: printf("<%d>", *--w); break;
852 case CONC: printf("<##>"); break;
853 case SNUFF: printf("<\">"); break;
854 default: putchar(*w); break;
855 }
856 }
857 putchar('\n');
858 }
859#endif
860 for (i = 0; i < narg; i++)
861 free(args[i]);
862 return;
863
864bad: error("bad define");
865}
866
867void
868xwarning(usch *s)
869{
870 usch *t;
871 usch *sb = stringbuf;
872
873 flbuf();
874 savch(0);
875 if (ifiles != NULL) {
876 t = sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
877 write (2, t, strlen((char *)t));
878 }
879 write (2, s, strlen((char *)s));
880 write (2, "\n", 1);
881 stringbuf = sb;
882}
883
884void
885xerror(usch *s)
886{
887 usch *t;
888
889 flbuf();
890 savch(0);
891 if (ifiles != NULL) {
892 t = sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
893 write (2, t, strlen((char *)t));
894 }
895 write (2, s, strlen((char *)s));
896 write (2, "\n", 1);
897 exit(1);
898}
899
900static void
901sss(void)
902{
903 savch(EBLOCK);
904 savch(cinput());
905 savch(cinput());
906}
907
908static int
909addmac(struct symtab *sp)
910{
911 int c, i;
912
913 /* Check if it exists; then save some space */
914 /* May be more difficult to debug cpp */
915 for (i = 1; i < norepptr; i++)
916 if (norep[i] == sp)
917 return i;
918 if (norepptr >= RECMAX)
919 error("too many macros");
920 /* check norepptr */
921 if ((norepptr & 255) == 0)
922 norepptr++;
923 if (((norepptr >> 8) & 255) == 0)
924 norepptr += 256;
925 c = norepptr;
926 norep[norepptr++] = sp;
927 return c;
928}
929
930static void
931doblk(void)
932{
933 int c;
934
935 do {
936 donex();
937 } while ((c = sloscan()) == EBLOCK);
938 if (c != IDENT)
939 error("EBLOCK sync error");
940}
941
942/* Block next nr in lex buffer to expand */
943int
944donex(void)
945{
946 int n, i;
947
948 if (bidx == RECMAX)
949 error("too deep macro recursion");
950 n = cinput();
951 n = MKB(n, cinput());
952 for (i = 0; i < bidx; i++)
953 if (bptr[i] == n)
954 return n; /* already blocked */
955 bptr[bidx++] = n;
956 /* XXX - check for sp buffer overflow */
957 if (dflag>1) {
958 printf("donex %d (%d) blocking:\n", bidx, n);
959 printf("donex %s(%d) blocking:", norep[n]->namep, n);
960 for (i = bidx-1; i >= 0; i--)
961 printf(" '%s'", norep[bptr[i]]->namep);
962 printf("\n");
963 }
964 return n;
965}
966
967/*
968 * store a character into the "define" buffer.
969 */
970void
971savch(int c)
972{
973 if (stringbuf-sbf < SBSIZE) {
974 *stringbuf++ = (usch)c;
975 } else {
976 stringbuf = sbf; /* need space to write error message */
977 error("Too much defining");
978 }
979}
980
981/*
982 * convert _Pragma to #pragma for output.
983 * Syntax is already correct.
984 */
985static void
986pragoper(void)
987{
988 usch *s;
989 int t;
990
991 while ((t = sloscan()) != '(')
992 ;
993
994 while ((t = sloscan()) == WSPACE)
995 ;
996 if (t != STRING)
997 error("pragma must have string argument");
998 savstr((const usch *)"\n#pragma ");
999 s = (usch *)yytext;
1000 if (*s == 'L')
1001 s++;
1002 for (; *s; s++) {
1003 if (*s == '\"')
1004 continue;
1005 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
1006 s++;
1007 savch(*s);
1008 }
1009 sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
1010 while ((t = sloscan()) == WSPACE)
1011 ;
1012 if (t != ')')
1013 error("pragma syntax error");
1014}
1015
1016/*
1017 * Return true if it is OK to expand this symbol.
1018 */
1019static int
1020okexp(struct symtab *sp)
1021{
1022 int i;
1023
1024 if (sp == NULL)
1025 return 0;
1026 for (i = 0; i < bidx; i++)
1027 if (norep[bptr[i]] == sp)
1028 return 0;
1029 return 1;
1030}
1031
1032/*
1033 * Insert block(s) before each expanded name.
1034 * Input is in lex buffer, output on lex buffer.
1035 */
1036static void
1037insblock(int bnr)
1038{
1039 usch *bp = stringbuf;
1040 int c, i;
1041
1042 IMP("IB");
1043 while ((c = sloscan()) != WARN) {
1044 if (c == EBLOCK) {
1045 sss();
1046 continue;
1047 }
1048 if (c == IDENT) {
1049 savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
1050 for (i = 0; i < bidx; i++)
1051 savch(EBLOCK), savch(bptr[i] & 255),
1052 savch(bptr[i] >> 8);
1053 }
1054 savstr((const usch *)yytext);
1055 if (c == '\n')
1056 (void)cinput();
1057 }
1058 savch(0);
1059 cunput(WARN);
1060 unpstr(bp);
1061 stringbuf = bp;
1062 IMP("IBRET");
1063}
1064
1065/* Delete next WARN on the input stream */
1066static void
1067delwarn(void)
1068{
1069 usch *bp = stringbuf;
1070 int c;
1071
1072 IMP("DELWARN");
1073 while ((c = sloscan()) != WARN) {
1074 if (c == EBLOCK) {
1075 sss();
1076 } else
1077 savstr(yytext);
1078 }
1079 savch(0);
1080 unpstr(bp);
1081 stringbuf = bp;
1082 IMP("DELWRET");
1083}
1084
1085/*
1086 * Handle defined macro keywords found on input stream.
1087 * When finished print out the full expanded line.
1088 * Everything on lex buffer except for the symtab.
1089 */
1090int
1091kfind(struct symtab *sp)
1092{
1093 struct symtab *nl;
1094 const usch *argary[MAXARGS+1], *cbp;
1095 usch *sbp;
1096 int c, o, chkf;
1097
1098 DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
1099 IMP("KFIND");
1100 if (*sp->value == OBJCT) {
1101 if (sp == filloc) {
1102 unpstr(sheap("\"%s\"", ifiles->fname));
1103 return 1;
1104 } else if (sp == linloc) {
1105 unpstr(sheap("%d", ifiles->lineno));
1106 return 1;
1107 }
1108 IMP("END1");
1109 cunput(WARN);
1110 for (cbp = sp->value-1; *cbp; cbp--)
1111 cunput(*cbp);
1112 insblock(addmac(sp));
1113 IMP("ENDX");
1114 exparg(1);
1115
1116upp: sbp = stringbuf;
1117 chkf = 1;
1118 if (obufp != 0)
1119 lastoch = outbuf[obufp-1];
1120 if (iswsnl(lastoch))
1121 chkf = 0;
1122 while ((c = sloscan()) != WARN) {
1123 switch (c) {
1124 case STRING:
1125 /* Remove embedded directives */
1126 for (cbp = (usch *)yytext; *cbp; cbp++) {
1127 if (*cbp == EBLOCK)
1128 cbp+=2;
1129 else if (*cbp != CONC)
1130 savch(*cbp);
1131 }
1132 break;
1133
1134 case EBLOCK:
1135 doblk();
1136 /* FALLTHROUGH */
1137 case IDENT:
1138 /*
1139 * Tricky: if this is the last identifier
1140 * in the expanded list, and it is defined
1141 * as a function-like macro, then push it
1142 * back on the input stream and let fastscan
1143 * handle it as a new macro.
1144 * BUT: if this macro is blocked then this
1145 * should not be done.
1146 */
1147 nl = lookup((usch *)yytext, FIND);
1148 o = okexp(nl);
1149 bidx = 0;
1150 /* Deal with pragmas here */
1151 if (nl == pragloc) {
1152 pragoper();
1153 break;
1154 }
1155 if (nl == NULL || !o || *nl->value == OBJCT) {
1156 /* Not fun-like macro */
1157 savstr(yytext);
1158 break;
1159 }
1160 c = cinput();
1161 if (c == WARN) {
1162 /* succeeded, push back */
1163 unpstr(yytext);
1164 } else {
1165 savstr(yytext);
1166 }
1167 cunput(c);
1168 break;
1169
1170 default:
1171 if (chkf && c < 127)
1172 putch(' ');
1173 savstr(yytext);
1174 break;
1175 }
1176 chkf = 0;
1177 }
1178 IMP("END2");
1179 norepptr = 1;
1180 savch(0);
1181 stringbuf = sbp;
1182 return 1;
1183 }
1184 /* Is a function-like macro */
1185
1186 /* Search for '(' */
1187 sbp = stringbuf;
1188 while (iswsnl(c = cinput()))
1189 savch(c);
1190 savch(0);
1191 stringbuf = sbp;
1192 if (c != '(') {
1193 cunput(c);
1194 unpstr(sbp);
1195 return 0; /* Failed */
1196 }
1197
1198 /* Found one, output \n to be in sync */
1199 for (; *sbp; sbp++) {
1200 if (*sbp == '\n')
1201 putch('\n'), ifiles->lineno++;
1202 }
1203
1204 /* fetch arguments */
1205 if (readargs(sp, argary))
1206 error("readargs");
1207
1208 c = addmac(sp);
1209 sbp = stringbuf;
1210 cunput(WARN);
1211
1212 IMP("KEXP");
1213 subarg(sp, argary, 1);
1214 IMP("KNEX");
1215 insblock(c);
1216 IMP("KBLK");
1217
1218 stringbuf = sbp;
1219
1220 exparg(1);
1221
1222 IMP("END");
1223
1224 goto upp;
1225
1226}
1227
1228/*
1229 * Replace and push-back on input stream the eventual replaced macro.
1230 * The check for whether it can expand or not should already have been done.
1231 * Blocks for this identifier will be added via insblock() after expansion.
1232 */
1233int
1234submac(struct symtab *sp, int lvl)
1235{
1236 const usch *argary[MAXARGS+1];
1237 const usch *cp;
1238 usch *bp;
1239 int ch;
1240
1241 DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
1242 if (*sp->value == OBJCT) {
1243 if (sp == filloc) {
1244 unpstr(sheap("\"%s\"", ifiles->fname));
1245 return 1;
1246 } else if (sp == linloc) {
1247 unpstr(sheap("%d", ifiles->lineno));
1248 return 1;
1249 }
1250
1251 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
1252 /* expand object-type macros */
1253 ch = addmac(sp);
1254 cunput(WARN);
1255
1256 for (cp = sp->value-1; *cp; cp--)
1257 cunput(*cp);
1258 insblock(ch);
1259 delwarn();
1260 return 1;
1261 }
1262
1263 /*
1264 * Function-like macro; see if it is followed by a (
1265 * Be careful about the expand/noexpand balance.
1266 * Store read data on heap meanwhile.
1267 * For directive #define foo() kaka
1268 * If input is <NEX><NEX>foo<EXP>()<EXP> then
1269 * output should be <NEX><NEX><EXP>kaka<EXP>.
1270 */
1271 bp = stringbuf;
1272 while (iswsnl(ch = cinput()))
1273 savch(ch);
1274 savch(0);
1275 stringbuf = bp;
1276 if (ch != '(') {
1277 cunput(ch);
1278 unpstr(bp);
1279 return 0; /* Failed */
1280 }
1281
1282 /* no \n should be here */
1283
1284 /*
1285 * A function-like macro has been found. Read in the arguments,
1286 * expand them and push-back everything for another scan.
1287 */
1288 DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
1289 savch(0);
1290 if (readargs(sp, argary)) {
1291 /* Bailed out in the middle of arg list */
1292 unpstr(bp);
1293 if (dflag>1)printf("%d:noreadargs\n", lvl);
1294 stringbuf = bp;
1295 return 0;
1296 }
1297
1298 /* when all args are read from input stream */
1299 ch = addmac(sp);
1300
1301 DDPRINT(("%d:submac pre\n", lvl));
1302 cunput(WARN);
1303
1304 subarg(sp, argary, lvl+1);
1305
1306 DDPRINT(("%d:submac post\n", lvl));
1307 insblock(ch);
1308 delwarn();
1309
1310 stringbuf = bp; /* Reset heap */
1311 DPRINT(("%d:Return submac\n", lvl));
1312 IMP("SM1");
1313 return 1;
1314}
1315
1316/*
1317 * Read arguments and put in argument array.
1318 * If WARN is encountered return 1, otherwise 0.
1319 */
1320int
1321readargs(struct symtab *sp, const usch **args)
1322{
1323 const usch *vp = sp->value;
1324 int c, i, plev, narg, ellips = 0;
1325 int warn;
1326
1327 DPRINT(("readargs\n"));
1328
1329 narg = *vp--;
1330 if (narg == VARG) {
1331 narg = *vp--;
1332 ellips = 1;
1333 }
1334
1335 IMP("RDA1");
1336 /*
1337 * read arguments and store them on heap.
1338 */
1339 warn = 0;
1340 c = '(';
1341 for (i = 0; i < narg && c != ')'; i++) {
1342 args[i] = stringbuf;
1343 plev = 0;
1344 while ((c = sloscan()) == WSPACE || c == '\n')
1345 if (c == '\n')
1346 putch(cinput());
1347 for (;;) {
1348 while (c == EBLOCK) {
1349 sss();
1350 c = sloscan();
1351 }
1352 if (c == WARN) {
1353 warn++;
1354 goto oho;
1355 }
1356 if (plev == 0 && (c == ')' || c == ','))
1357 break;
1358 if (c == '(')
1359 plev++;
1360 if (c == ')')
1361 plev--;
1362 savstr((usch *)yytext);
1363oho: while ((c = sloscan()) == '\n') {
1364 putch(cinput());
1365 savch(' ');
1366 }
1367 while (c == CMNT) {
1368 getcmnt();
1369 c = sloscan();
1370 }
1371 if (c == 0)
1372 error("eof in macro");
1373 }
1374 while (args[i] < stringbuf &&
1375 iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
1376 stringbuf--;
1377 savch('\0');
1378 if (dflag) {
1379 printf("readargs: save arg %d '", i);
1380 prline(args[i]);
1381 printf("'\n");
1382 }
1383 }
1384
1385 IMP("RDA2");
1386 /* Handle varargs readin */
1387 if (ellips)
1388 args[i] = (const usch *)"";
1389 if (ellips && c != ')') {
1390 args[i] = stringbuf;
1391 plev = 0;
1392 while ((c = sloscan()) == WSPACE)
1393 ;
1394 for (;;) {
1395 if (plev == 0 && c == ')')
1396 break;
1397 if (c == '(')
1398 plev++;
1399 if (c == ')')
1400 plev--;
1401 if (c == EBLOCK) {
1402 sss();
1403 } else
1404 savstr((usch *)yytext);
1405 while ((c = sloscan()) == '\n') {
1406 cinput();
1407 savch(' ');
1408 }
1409 }
1410 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
1411 stringbuf--;
1412 savch('\0');
1413
1414 }
1415 if (narg == 0 && ellips == 0)
1416 while ((c = sloscan()) == WSPACE || c == '\n')
1417 if (c == '\n')
1418 cinput();
1419
1420 if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1421 error("wrong arg count");
1422 while (warn)
1423 cunput(WARN), warn--;
1424 return 0;
1425}
1426
1427#if 0
1428/*
1429 * Maybe an indentifier (for macro expansion).
1430 */
1431static int
1432mayid(usch *s)
1433{
1434 for (; *s; s++)
1435 if (!isdigit(*s) && !isalpha(*s) && *s != '_')
1436 return 0;
1437 return 1;
1438}
1439#endif
1440
1441/*
1442 * expand a function-like macro.
1443 * vp points to end of replacement-list
1444 * reads function arguments from sloscan()
1445 * result is pushed-back for more scanning.
1446 */
1447void
1448subarg(struct symtab *nl, const usch **args, int lvl)
1449{
1450 int narg, instr, snuff;
1451 const usch *sp, *bp, *ap, *vp;
1452
1453 DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
1454 vp = nl->value;
1455 narg = *vp--;
1456 if (narg == VARG)
1457 narg = *vp--;
1458
1459 sp = vp;
1460 instr = snuff = 0;
1461 if (dflag>1) {
1462 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
1463 prrep(vp);
1464 printf("'\n");
1465 }
1466
1467 /*
1468 * push-back replacement-list onto lex buffer while replacing
1469 * arguments. Arguments are macro-expanded if required.
1470 */
1471 while (*sp != 0) {
1472 if (*sp == SNUFF)
1473 cunput('\"'), snuff ^= 1;
1474 else if (*sp == CONC)
1475 ;
1476 else if (*sp == WARN) {
1477
1478 if (sp[-1] == VARG) {
1479 bp = ap = args[narg];
1480 sp--;
1481#ifdef GCC_COMPAT
1482 } else if (sp[-1] == GCCARG) {
1483 ap = args[narg];
1484 if (ap[0] == 0)
1485 ap = (const usch *)"0";
1486 bp = ap;
1487 sp--;
1488#endif
1489 } else
1490 bp = ap = args[(int)*--sp];
1491 if (dflag>1){
1492 printf("%d:subarg GOTwarn; arglist '", lvl);
1493 prline(bp);
1494 printf("'\n");
1495 }
1496 if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
1497 /*
1498 * Expand an argument; 6.10.3.1:
1499 * "A parameter in the replacement list,
1500 * is replaced by the corresponding argument
1501 * after all macros contained therein have
1502 * been expanded.".
1503 */
1504 cunput(WARN);
1505 unpstr(bp);
1506 exparg(lvl+1);
1507 delwarn();
1508 } else {
1509 while (*bp)
1510 bp++;
1511 while (bp > ap) {
1512 bp--;
1513 if (snuff && !instr && iswsnl(*bp)) {
1514 while (iswsnl(*bp))
1515 bp--;
1516 cunput(' ');
1517 }
1518
1519 cunput(*bp);
1520 if ((*bp == '\'' || *bp == '"')
1521 && bp[-1] != '\\' && snuff) {
1522 instr ^= 1;
1523 if (instr == 0 && *bp == '"')
1524 cunput('\\');
1525 }
1526 if (instr && (*bp == '\\' || *bp == '"'))
1527 cunput('\\');
1528 }
1529 }
1530 } else
1531 cunput(*sp);
1532 sp--;
1533 }
1534 DPRINT(("%d:Return subarg\n", lvl));
1535 IMP("SUBARG");
1536}
1537
1538/*
1539 * Do a (correct) expansion of a WARN-terminated buffer of tokens.
1540 * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
1541 * Expansion blocking is not altered here unless when tokens are
1542 * concatenated, in which case they are removed.
1543 */
1544void
1545exparg(int lvl)
1546{
1547 struct symtab *nl;
1548 int c, i;
1549 usch *och;
1550 usch *osb = stringbuf;
1551 int anychange;
1552
1553 DPRINT(("%d:exparg\n", lvl));
1554 IMP("EXPARG");
1555
1556 readmac++;
1557rescan:
1558 anychange = 0;
1559 while ((c = sloscan()) != WARN) {
1560 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
1561 IMP("EA0");
1562 switch (c) {
1563
1564 case EBLOCK:
1565 doblk();
1566 /* FALLTHROUGH */
1567 case IDENT:
1568 /*
1569 * Handle argument concatenation here.
1570 * In case of concatenation, scratch all blockings.
1571 */
1572 DDPRINT(("%d:exparg ident %d\n", lvl, c));
1573 och = stringbuf;
1574
1575sav: savstr(yytext);
1576
1577 if ((c = cinput()) == EBLOCK) {
1578 /* yep, are concatenating; forget blocks */
1579 do {
1580 (void)cinput();
1581 (void)cinput();
1582 } while ((c = sloscan()) == EBLOCK);
1583 bidx = 0;
1584 goto sav;
1585 }
1586 cunput(c);
1587
1588 DPRINT(("%d:exparg: str '%s'\n", lvl, och));
1589 IMP("EA1");
1590 /* see if ident is expandable */
1591 if ((nl = lookup(och, FIND)) && okexp(nl)) {
1592 if (submac(nl, lvl+1)) {
1593 /* Could expand, result on lexbuffer */
1594 stringbuf = och; /* clear saved name */
1595 anychange = 1;
1596 }
1597 } else if (bidx) {
1598 /* must restore blocks */
1599 stringbuf = och;
1600 for (i = 0; i < bidx; i++)
1601 savch(EBLOCK), savch(bptr[i] & 255),
1602 savch(bptr[i] >> 8);
1603 savstr(yytext);
1604 }
1605 bidx = 0;
1606 IMP("EA2");
1607 break;
1608
1609 case CMNT:
1610 getcmnt();
1611 break;
1612
1613 case '\n':
1614 cinput();
1615 savch(' ');
1616 break;
1617
1618 default:
1619 savstr((usch *)yytext);
1620 break;
1621 }
1622 }
1623 *stringbuf = 0;
1624 cunput(WARN);
1625 unpstr(osb);
1626 DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
1627 IMP("EXPRET");
1628 stringbuf = osb;
1629 if (anychange)
1630 goto rescan;
1631 readmac--;
1632}
1633
1634void
1635imp(const char *str)
1636{
1637 printf("%s (%d) '", str, bidx);
1638 prline(ifiles->curptr);
1639 printf("'\n");
1640}
1641
1642void
1643prrep(const usch *s)
1644{
1645 while (*s) {
1646 switch (*s) {
1647 case WARN: printf("<ARG(%d)>", *--s); break;
1648 case CONC: printf("<CONC>"); break;
1649 case SNUFF: printf("<SNUFF>"); break;
1650 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
1651 default: printf("%c", *s); break;
1652 }
1653 s--;
1654 }
1655}
1656
1657void
1658prline(const usch *s)
1659{
1660 while (*s) {
1661 switch (*s) {
1662 case WARN: printf("<WARN>"); break;
1663 case CONC: printf("<CONC>"); break;
1664 case SNUFF: printf("<SNUFF>"); break;
1665 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
1666 case '\n': printf("<NL>"); break;
1667 default: printf("%c", *s); break;
1668 }
1669 s++;
1670 }
1671}
1672
1673usch *
1674savstr(const usch *str)
1675{
1676 usch *rv = stringbuf;
1677
1678 do {
1679 if (stringbuf >= &sbf[SBSIZE]) {
1680 stringbuf = sbf; /* need space to write error message */
1681 error("out of macro space!");
1682 }
1683 } while ((*stringbuf++ = *str++));
1684 stringbuf--;
1685 return rv;
1686}
1687
1688void
1689unpstr(const usch *c)
1690{
1691 const usch *d = c;
1692
1693#if 0
1694 if (dflag>1) {
1695 printf("Xunpstr: '");
1696 prline(c);
1697 printf("'\n");
1698 }
1699#endif
1700 while (*d) {
1701 if (*d == EBLOCK)
1702 d += 2;
1703 d++;
1704 }
1705 while (d > c) {
1706 cunput(*--d);
1707 }
1708}
1709
1710static ssize_t
1711_write_all(int fd, const void* buffer, size_t count)
1712{
1713 size_t remaining = count;
1714 while (remaining > 0) {
1715 ssize_t retval = write(ofd, buffer, remaining);
1716 if (retval < 0) {
1717 return retval;
1718 }
1719 remaining -= retval;
1720 buffer += retval;
1721 }
1722 return count;
1723}
1724
1725void
1726flbuf()
1727{
1728 if (obufp == 0)
1729 return;
1730 if (Mflag == 0 && _write_all(ofd, outbuf, obufp) < 0)
1731 error("obuf write error");
1732 lastoch = outbuf[obufp-1];
1733 obufp = 0;
1734}
1735
1736void
1737putch(int ch)
1738{
1739 outbuf[obufp++] = (usch)ch;
1740 if (obufp == CPPBUF || (istty && ch == '\n'))
1741 flbuf();
1742}
1743
1744void
1745putstr(const usch *s)
1746{
1747 for (; *s; s++) {
1748 outbuf[obufp++] = *s;
1749 if (obufp == CPPBUF || (istty && *s == '\n'))
1750 flbuf();
1751 }
1752}
1753
1754/*
1755 * convert a number to an ascii string. Store it on the heap.
1756 */
1757static void
1758num2str(int num)
1759{
1760 static usch buf[12];
1761 usch *b = buf;
1762 int m = 0;
1763
1764 if (num < 0)
1765 num = -num, m = 1;
1766 do {
1767 *b++ = (usch)(num % 10 + '0');
1768 num /= 10;
1769 } while (num);
1770 if (m)
1771 *b++ = '-';
1772 while (b > buf)
1773 savch(*--b);
1774}
1775
1776/*
1777 * similar to sprintf, but only handles %s and %d.
1778 * saves result on heap.
1779 */
1780usch *
1781sheap(const char *fmt, ...)
1782{
1783 va_list ap;
1784 usch *op = stringbuf;
1785
1786 va_start(ap, fmt);
1787 for (; *fmt; fmt++) {
1788 if (*fmt == '%') {
1789 fmt++;
1790 switch (*fmt) {
1791 case 's':
1792 savstr(va_arg(ap, usch *));
1793 break;
1794 case 'd':
1795 num2str(va_arg(ap, int));
1796 break;
1797 case 'c':
1798 savch(va_arg(ap, int));
1799 break;
1800 default:
1801 break; /* cannot call error() here */
1802 }
1803 } else
1804 savch(*fmt);
1805 }
1806 va_end(ap);
1807 *stringbuf = 0;
1808 return op;
1809}
1810
1811void
1812usage()
1813{
1814 error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
1815}
1816
1817#ifdef notyet
1818/*
1819 * Symbol table stuff.
1820 * The data structure used is a patricia tree implementation using only
1821 * bytes to store offsets.
1822 * The information stored is (lower address to higher):
1823 *
1824 * unsigned char bitno[2]; bit number in the string
1825 * unsigned char left[3]; offset from base to left element
1826 * unsigned char right[3]; offset from base to right element
1827 */
1828#endif
1829
1830/*
1831 * This patricia implementation is more-or-less the same as
1832 * used in ccom for string matching.
1833 */
1834struct tree {
1835 int bitno;
1836 struct tree *lr[2];
1837};
1838
1839#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
1840#define LEFT_IS_LEAF 0x80000000
1841#define RIGHT_IS_LEAF 0x40000000
1842#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0)
1843#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0)
1844#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
1845#define CHECKBITS 8
1846
1847static struct tree *sympole;
1848static int numsyms;
1849
1850/*
1851 * Allocate a symtab struct and store the string.
1852 */
1853static struct symtab *
1854getsymtab(const usch *str)
1855{
1856 struct symtab *sp = malloc(sizeof(struct symtab));
1857
1858 if (sp == NULL)
1859 error("getsymtab: couldn't allocate symtab");
1860 sp->namep = savstr(str);
1861 savch('\0');
1862 sp->value = NULL;
1863 sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
1864 sp->line = ifiles ? ifiles->lineno : 0;
1865 return sp;
1866}
1867
1868/*
1869 * Do symbol lookup in a patricia tree.
1870 * Only do full string matching, no pointer optimisations.
1871 */
1872struct symtab *
1873lookup(const usch *key, int enterf)
1874{
1875 struct symtab *sp;
1876 struct tree *w, *new, *last;
1877 int len, cix, bit, fbit, svbit, ix, bitno;
1878 const usch *k, *m;
1879
1880 /* Count full string length */
1881 for (k = key, len = 0; *k; k++, len++)
1882 ;
1883
1884 switch (numsyms) {
1885 case 0: /* no symbols yet */
1886 if (enterf != ENTER)
1887 return NULL;
1888 sympole = (struct tree *)getsymtab(key);
1889 numsyms++;
1890 return (struct symtab *)sympole;
1891
1892 case 1:
1893 w = sympole;
1894 svbit = 0; /* XXX gcc */
1895 break;
1896
1897 default:
1898 w = sympole;
1899 bitno = len * CHECKBITS;
1900 for (;;) {
1901 bit = BITNO(w->bitno);
1902 fbit = bit > bitno ? 0 : P_BIT(key, bit);
1903 svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
1904 IS_LEFT_LEAF(w->bitno);
1905 w = w->lr[fbit];
1906 if (svbit)
1907 break;
1908 }
1909 }
1910
1911 sp = (struct symtab *)w;
1912
1913 m = sp->namep;
1914 k = key;
1915
1916 /* Check for correct string and return */
1917 for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
1918 ;
1919 if (*m == 0 && *k == 0) {
1920 if (enterf != ENTER && sp->value == NULL)
1921 return NULL;
1922 return sp;
1923 }
1924
1925 if (enterf != ENTER)
1926 return NULL; /* no string found and do not enter */
1927
1928 ix = *m ^ *k;
1929 while ((ix & 1) == 0)
1930 ix >>= 1, cix++;
1931
1932 /* Create new node */
1933 if ((new = malloc(sizeof *new)) == NULL)
1934 error("getree: couldn't allocate tree");
1935 bit = P_BIT(key, cix);
1936 new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
1937 new->lr[bit] = (struct tree *)getsymtab(key);
1938
1939 if (numsyms++ == 1) {
1940 new->lr[!bit] = sympole;
1941 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
1942 sympole = new;
1943 return (struct symtab *)new->lr[bit];
1944 }
1945
1946 w = sympole;
1947 last = NULL;
1948 for (;;) {
1949 fbit = w->bitno;
1950 bitno = BITNO(w->bitno);
1951 if (bitno == cix)
1952 error("bitno == cix");
1953 if (bitno > cix)
1954 break;
1955 svbit = P_BIT(key, bitno);
1956 last = w;
1957 w = w->lr[svbit];
1958 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
1959 break;
1960 }
1961
1962 new->lr[!bit] = w;
1963 if (last == NULL) {
1964 sympole = new;
1965 } else {
1966 last->lr[svbit] = new;
1967 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
1968 }
1969 if (bitno < cix)
1970 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
1971 return (struct symtab *)new->lr[bit];
1972}
1973
1974usch *
1975xstrdup(const usch *str)
1976{
1977 size_t len = strlen((const char *)str)+1;
1978 usch *rv;
1979
1980 if ((rv = malloc(len)) == NULL)
1981 error("xstrdup: out of mem");
1982 strlcpy((char *)rv, (const char *)str, len);
1983 return rv;
1984}
Note: See TracBrowser for help on using the repository browser.