* add p cc
[mascara-docs.git] / compilers / pcc / pcc-1.0.0 / cc / cpp / cpp.c
blob1d186acf2b6916c4d1841a93542c2685a8a71dfd
1 /* $Id: cpp.c,v 1.124.2.2 2011/03/27 13:17:19 ragge Exp $ */
3 /*
4 * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
5 * All rights reserved.
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.
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.
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.
34 #include "config.h"
36 #ifdef HAVE_SYS_WAIT_H
37 #include <sys/wait.h>
38 #endif
39 #include <sys/stat.h>
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>
52 #include "compat.h"
53 #include "cpp.h"
54 #include "y.tab.h"
56 #define SBSIZE 1000000
58 static usch sbf[SBSIZE];
59 /* C command */
61 int tflag; /* traditional cpp syntax */
62 #ifdef CPP_DEBUG
63 int 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
71 int ofd;
72 usch outbuf[CPPBUF];
73 int obufp, istty;
74 int Cflag, Mflag, dMflag, Pflag;
75 usch *Mfile;
76 struct initar *initar;
77 int readmac, lastoch;
79 /* include dirs */
80 struct 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
89 static struct symtab *filloc;
90 static struct symtab *linloc;
91 static struct symtab *pragloc;
92 int trulvl;
93 int flslvl;
94 int elflvl;
95 int elslvl;
96 usch *stringbuf = sbf;
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.
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.
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.
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.
122 /* args for lookup() */
123 #define FIND 0
124 #define ENTER 1
126 static int readargs(struct symtab *sp, const usch **args);
127 void prline(const usch *s);
128 static void prrep(const usch *s);
129 static void exparg(int);
130 static void subarg(struct symtab *sp, const usch **args, int);
131 void define(void);
132 void include(void);
133 void include_next(void);
134 void line(void);
135 void flbuf(void);
136 void usage(void);
137 usch *xstrdup(const usch *str);
138 static void addidir(char *idir, struct incs **ww);
139 void imp(const char *);
140 #define IMP(x) if (dflag>1) imp(x)
143 main(int argc, char **argv)
145 struct initar *it;
146 struct symtab *nl;
147 register int ch;
148 const usch *fn1, *fn2;
150 #ifdef TIMING
151 struct timeval t1, t2;
153 (void)gettimeofday(&t1, NULL);
154 #endif
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;
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;
174 case 'M': /* Generate dependencies for make */
175 Mflag++;
176 break;
178 case 'P': /* Inhibit generation of line numbers */
179 Pflag++;
180 break;
182 case 'S':
183 case 'I':
184 addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
185 break;
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;
200 /* ignore others */
201 break;
203 case 't':
204 tflag = 1;
205 break;
207 case '?':
208 usage();
209 default:
210 error("bad arg %c\n", ch);
212 argc -= optind;
213 argv += optind;
215 filloc = lookup((const usch *)"__FILE__", ENTER);
216 linloc = lookup((const usch *)"__LINE__", ENTER);
217 filloc->value = linloc->value = stringbuf;
218 savch(OBJCT);
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);
230 if (tflag == 0) {
231 time_t t = time(NULL);
232 usch *n = (usch *)ctime(&t);
235 * Manually move in the predefined macros.
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;
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;
247 nl = lookup((const usch *)"__STDC__", ENTER);
248 savch(0); savch('1'); savch(OBJCT);
249 nl->value = stringbuf-1;
251 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
252 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
253 nl->value = stringbuf-1;
256 if (Mflag && !dMflag) {
257 usch *c;
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;
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 = 1; /* stdout */
278 istty = isatty(ofd);
280 if (argc && strcmp(argv[0], "-")) {
281 fn1 = fn2 = (usch *)argv[0];
282 } else {
283 fn1 = NULL;
284 fn2 = (const usch *)"";
286 if (pushfile(fn1, fn2, 0, NULL))
287 error("cannot open %s", argv[0]);
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;
299 fprintf(stderr, "cpp total time: %ld s %ld us\n",
300 t2.tv_sec, t2.tv_usec);
301 #endif
302 return 0;
305 static void
306 addidir(char *idir, struct incs **ww)
308 struct incs *w;
309 struct stat st;
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;
318 if (w->dev == st.st_dev && w->ino == st.st_ino)
319 return;
320 ww = &w->next;
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;
330 void
331 line()
333 static usch *lbuf;
334 static int llen;
335 usch *p;
336 int c;
338 if ((c = yylex()) != NUMBER)
339 goto bad;
340 ifiles->lineno = (int)(yylval.node.nd_val - 1);
342 if ((c = yylex()) == '\n')
343 return;
345 if (c != STRING)
346 goto bad;
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;
358 p[strlen((char *)p)-1] = 0;
359 if (strlcpy((char *)lbuf, (char *)&p[1], SBSIZE) >= SBSIZE)
360 error("line exceeded buffer size");
362 ifiles->fname = lbuf;
363 if (yylex() == '\n')
364 return;
366 bad: error("bad line directive");
370 * Search for and include next file.
371 * Return 1 on success.
373 static int
374 fsrch(const usch *fn, int idx, struct incs *w)
376 int i;
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;
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;
391 return 0;
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.
399 void
400 include()
402 struct symtab *nl;
403 usch *osp;
404 usch *fn, *safefn;
405 int c, it;
407 if (flslvl)
408 return;
409 osp = stringbuf;
411 while ((c = sloscan()) == WSPACE)
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();
424 if (c != STRING && c != '<')
425 goto bad;
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);
434 savch('\0');
435 while ((c = sloscan()) == WSPACE)
437 if (c != '\n')
438 goto bad;
439 it = SYSINC;
440 safefn = fn;
441 } else {
442 usch *nm = stringbuf;
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++;
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 */
466 if (fsrch(safefn, 0, incdir[0]))
467 goto okret;
469 error("cannot find '%s'", safefn);
470 /* error() do not return */
472 bad: error("bad include");
473 /* error() do not return */
474 okret:
475 prtline();
478 void
479 include_next()
481 struct symtab *nl;
482 usch *osp;
483 usch *fn;
484 int c;
486 if (flslvl)
487 return;
488 osp = stringbuf;
489 while ((c = sloscan()) == WSPACE)
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();
502 if (c != STRING && c != '<')
503 goto bad;
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);
515 savch('\0');
517 while ((c = sloscan()) == WSPACE)
519 if (c != '\n')
520 goto bad;
522 if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
523 error("cannot find '%s'", fn);
524 prtline();
525 return;
527 bad: error("bad include");
528 /* error() do not return */
531 static int
532 definp(void)
534 int c;
537 c = sloscan();
538 while (c == WSPACE);
539 return c;
542 void
543 getcmnt(void)
545 int c;
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;
557 cunput(c);
558 c = '*';
560 savch(c);
565 * Compare two replacement lists, taking in account comments etc.
567 static int
568 cmprepl(const usch *o, const usch *n)
570 for (; *o; o--, n--) {
571 /* comment skip */
572 if (*o == '/' && o[-1] == '*') {
573 while (*o != '*' || o[-1] != '/')
574 o--;
575 o -= 2;
577 if (*n == '/' && n[-1] == '*') {
578 while (*n != '*' || n[-1] != '/')
579 n--;
580 n -= 2;
582 while (*o == ' ' || *o == '\t')
583 o--;
584 while (*n == ' ' || *n == '\t')
585 n--;
586 if (*o != *n)
587 return 1;
589 return 0;
592 static int
593 isell(void)
595 int ch;
597 if ((ch = cinput()) != '.') {
598 cunput(ch);
599 return 0;
601 if ((ch = cinput()) != '.') {
602 cunput(ch);
603 cunput('.');
604 return 0;
606 return 1;
609 void
610 define()
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
622 if (flslvl)
623 return;
624 if (sloscan() != WSPACE || sloscan() != IDENT)
625 goto bad;
627 if (isdigit((int)yytext[0]))
628 goto bad;
630 np = lookup((usch *)yytext, ENTER);
631 redef = np->value != NULL;
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;
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;
662 #ifdef GCC_COMPAT
663 if (c == '.' && isell()) {
664 if (definp() != ')')
665 goto bad;
666 gccvari = args[--narg];
667 break;
669 #endif
670 if (c == ')')
671 break;
673 goto bad;
675 c = sloscan();
676 } else if (c == '\n') {
677 /* #define foo */
679 } else if (c != WSPACE)
680 goto bad;
682 while (c == WSPACE)
683 c = sloscan();
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;
696 /* parse replacement-list, substituting arguments */
697 savch('\0');
698 while (c != '\n') {
699 #ifdef GCC_COMPAT
700 wascon = 0;
701 loop:
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
723 continue;
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
741 in2: if (narg < 0) {
742 /* no meaning in object-type macro */
743 savch('#');
744 continue;
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;
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
765 savch(WARN);
766 if (mkstr)
767 savch(SNUFF), mkstr = 0;
768 break;
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;
786 #endif
787 if (mkstr)
788 error("not argument");
789 goto id;
791 savch(i);
792 savch(WARN);
793 if (mkstr)
794 savch(SNUFF), mkstr = 0;
795 break;
797 case CMNT: /* save comments */
798 getcmnt();
799 break;
801 default:
802 id: savstr((usch *)yytext);
803 break;
805 c = sloscan();
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;
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);
836 stringbuf = sbeg; /* forget this space */
837 } else
838 np->value = stringbuf-1;
840 #ifdef CPP_DEBUG
841 if (dflag) {
842 const usch *w = np->value;
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;
857 putchar('\n');
859 #endif
860 for (i = 0; i < narg; i++)
861 free(args[i]);
862 return;
864 bad: error("bad define");
867 void
868 xwarning(usch *s)
870 usch *t;
871 usch *sb = stringbuf;
872 int dummy;
874 flbuf();
875 savch(0);
876 if (ifiles != NULL) {
877 t = sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
878 write (2, t, strlen((char *)t));
880 dummy = write (2, s, strlen((char *)s));
881 dummy = write (2, "\n", 1);
882 stringbuf = sb;
885 void
886 xerror(usch *s)
888 usch *t;
889 int dummy;
891 flbuf();
892 savch(0);
893 if (ifiles != NULL) {
894 t = sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
895 dummy = write (2, t, strlen((char *)t));
897 dummy = write (2, s, strlen((char *)s));
898 dummy = write (2, "\n", 1);
899 exit(1);
902 static void
903 sss(void)
905 savch(EBLOCK);
906 savch(cinput());
907 savch(cinput());
910 static int
911 addmac(struct symtab *sp)
913 int c, i;
915 /* Check if it exists; then save some space */
916 /* May be more difficult to debug cpp */
917 for (i = 1; i < norepptr; i++)
918 if (norep[i] == sp)
919 return i;
920 if (norepptr >= RECMAX)
921 error("too many macros");
922 /* check norepptr */
923 if ((norepptr & 255) == 0)
924 norepptr++;
925 if (((norepptr >> 8) & 255) == 0)
926 norepptr += 256;
927 c = norepptr;
928 norep[norepptr++] = sp;
929 return c;
932 static void
933 doblk(void)
935 int c;
937 do {
938 donex();
939 } while ((c = sloscan()) == EBLOCK);
940 if (c != IDENT)
941 error("EBLOCK sync error");
944 /* Block next nr in lex buffer to expand */
946 donex(void)
948 int n, i;
950 if (bidx == RECMAX)
951 error("too deep macro recursion");
952 n = cinput();
953 n = MKB(n, cinput());
954 for (i = 0; i < bidx; i++)
955 if (bptr[i] == n)
956 return n; /* already blocked */
957 bptr[bidx++] = n;
958 /* XXX - check for sp buffer overflow */
959 if (dflag>1) {
960 printf("donex %d (%d) blocking:\n", bidx, n);
961 printf("donex %s(%d) blocking:", norep[n]->namep, n);
962 for (i = bidx-1; i >= 0; i--)
963 printf(" '%s'", norep[bptr[i]]->namep);
964 printf("\n");
966 return n;
970 * store a character into the "define" buffer.
972 void
973 savch(int c)
975 if (stringbuf-sbf < SBSIZE) {
976 *stringbuf++ = (usch)c;
977 } else {
978 stringbuf = sbf; /* need space to write error message */
979 error("Too much defining");
984 * convert _Pragma to #pragma for output.
985 * Syntax is already correct.
987 static void
988 pragoper(void)
990 usch *s;
991 int t;
993 while ((t = sloscan()) != '(')
996 while ((t = sloscan()) == WSPACE)
998 if (t != STRING)
999 error("pragma must have string argument");
1000 savstr((const usch *)"\n#pragma ");
1001 s = (usch *)yytext;
1002 if (*s == 'L')
1003 s++;
1004 for (; *s; s++) {
1005 if (*s == '\"')
1006 continue;
1007 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
1008 s++;
1009 savch(*s);
1011 sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
1012 while ((t = sloscan()) == WSPACE)
1014 if (t != ')')
1015 error("pragma syntax error");
1019 * Return true if it is OK to expand this symbol.
1021 static int
1022 okexp(struct symtab *sp)
1024 int i;
1026 if (sp == NULL)
1027 return 0;
1028 for (i = 0; i < bidx; i++)
1029 if (norep[bptr[i]] == sp)
1030 return 0;
1031 return 1;
1035 * Insert block(s) before each expanded name.
1036 * Input is in lex buffer, output on lex buffer.
1038 static void
1039 insblock(int bnr)
1041 usch *bp = stringbuf;
1042 int c, i;
1044 IMP("IB");
1045 while ((c = sloscan()) != WARN) {
1046 if (c == EBLOCK) {
1047 sss();
1048 continue;
1050 if (c == IDENT) {
1051 savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
1052 for (i = 0; i < bidx; i++)
1053 savch(EBLOCK), savch(bptr[i] & 255),
1054 savch(bptr[i] >> 8);
1056 savstr((const usch *)yytext);
1057 if (c == '\n')
1058 (void)cinput();
1060 savch(0);
1061 cunput(WARN);
1062 unpstr(bp);
1063 stringbuf = bp;
1064 IMP("IBRET");
1067 /* Delete next WARN on the input stream */
1068 static void
1069 delwarn(void)
1071 usch *bp = stringbuf;
1072 int c;
1074 IMP("DELWARN");
1075 while ((c = sloscan()) != WARN) {
1076 if (c == EBLOCK) {
1077 sss();
1078 } else
1079 savstr(yytext);
1081 savch(0);
1082 unpstr(bp);
1083 stringbuf = bp;
1084 IMP("DELWRET");
1088 * Handle defined macro keywords found on input stream.
1089 * When finished print out the full expanded line.
1090 * Everything on lex buffer except for the symtab.
1093 kfind(struct symtab *sp)
1095 struct symtab *nl;
1096 const usch *argary[MAXARGS+1], *cbp;
1097 usch *sbp;
1098 int c, o, chkf;
1100 DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
1101 IMP("KFIND");
1102 if (*sp->value == OBJCT) {
1103 if (sp == filloc) {
1104 unpstr(sheap("\"%s\"", ifiles->fname));
1105 return 1;
1106 } else if (sp == linloc) {
1107 unpstr(sheap("%d", ifiles->lineno));
1108 return 1;
1110 IMP("END1");
1111 cunput(WARN);
1112 for (cbp = sp->value-1; *cbp; cbp--)
1113 cunput(*cbp);
1114 insblock(addmac(sp));
1115 IMP("ENDX");
1116 exparg(1);
1118 upp: sbp = stringbuf;
1119 chkf = 1;
1120 if (obufp != 0)
1121 lastoch = outbuf[obufp-1];
1122 if (iswsnl(lastoch))
1123 chkf = 0;
1124 while ((c = sloscan()) != WARN) {
1125 switch (c) {
1126 case STRING:
1127 /* Remove embedded directives */
1128 for (cbp = (usch *)yytext; *cbp; cbp++) {
1129 if (*cbp == EBLOCK)
1130 cbp+=2;
1131 else if (*cbp != CONC)
1132 savch(*cbp);
1134 break;
1136 case EBLOCK:
1137 doblk();
1138 /* FALLTHROUGH */
1139 case IDENT:
1141 * Tricky: if this is the last identifier
1142 * in the expanded list, and it is defined
1143 * as a function-like macro, then push it
1144 * back on the input stream and let fastscan
1145 * handle it as a new macro.
1146 * BUT: if this macro is blocked then this
1147 * should not be done.
1149 nl = lookup((usch *)yytext, FIND);
1150 o = okexp(nl);
1151 bidx = 0;
1152 /* Deal with pragmas here */
1153 if (nl == pragloc) {
1154 pragoper();
1155 break;
1157 if (nl == NULL || !o || *nl->value == OBJCT) {
1158 /* Not fun-like macro */
1159 savstr(yytext);
1160 break;
1162 c = cinput();
1163 if (c == WARN) {
1164 /* succeeded, push back */
1165 unpstr(yytext);
1166 } else {
1167 savstr(yytext);
1169 cunput(c);
1170 break;
1172 default:
1173 if (chkf && c < 127)
1174 putch(' ');
1175 savstr(yytext);
1176 break;
1178 chkf = 0;
1180 IMP("END2");
1181 norepptr = 1;
1182 savch(0);
1183 stringbuf = sbp;
1184 return 1;
1186 /* Is a function-like macro */
1188 /* Search for '(' */
1189 sbp = stringbuf;
1190 while (iswsnl(c = cinput()))
1191 savch(c);
1192 savch(0);
1193 stringbuf = sbp;
1194 if (c != '(') {
1195 cunput(c);
1196 unpstr(sbp);
1197 return 0; /* Failed */
1200 /* Found one, output \n to be in sync */
1201 for (; *sbp; sbp++) {
1202 if (*sbp == '\n')
1203 putch('\n'), ifiles->lineno++;
1206 /* fetch arguments */
1207 if (readargs(sp, argary))
1208 error("readargs");
1210 c = addmac(sp);
1211 sbp = stringbuf;
1212 cunput(WARN);
1214 IMP("KEXP");
1215 subarg(sp, argary, 1);
1216 IMP("KNEX");
1217 insblock(c);
1218 IMP("KBLK");
1220 stringbuf = sbp;
1222 exparg(1);
1224 IMP("END");
1226 goto upp;
1231 * Replace and push-back on input stream the eventual replaced macro.
1232 * The check for whether it can expand or not should already have been done.
1233 * Blocks for this identifier will be added via insblock() after expansion.
1236 submac(struct symtab *sp, int lvl)
1238 const usch *argary[MAXARGS+1];
1239 const usch *cp;
1240 usch *bp;
1241 int ch;
1243 DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
1244 if (*sp->value == OBJCT) {
1245 if (sp == filloc) {
1246 unpstr(sheap("\"%s\"", ifiles->fname));
1247 return 1;
1248 } else if (sp == linloc) {
1249 unpstr(sheap("%d", ifiles->lineno));
1250 return 1;
1253 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
1254 /* expand object-type macros */
1255 ch = addmac(sp);
1256 cunput(WARN);
1258 for (cp = sp->value-1; *cp; cp--)
1259 cunput(*cp);
1260 insblock(ch);
1261 delwarn();
1262 return 1;
1266 * Function-like macro; see if it is followed by a (
1267 * Be careful about the expand/noexpand balance.
1268 * Store read data on heap meanwhile.
1269 * For directive #define foo() kaka
1270 * If input is <NEX><NEX>foo<EXP>()<EXP> then
1271 * output should be <NEX><NEX><EXP>kaka<EXP>.
1273 bp = stringbuf;
1274 while (iswsnl(ch = cinput()))
1275 savch(ch);
1276 savch(0);
1277 stringbuf = bp;
1278 if (ch != '(') {
1279 cunput(ch);
1280 unpstr(bp);
1281 return 0; /* Failed */
1284 /* no \n should be here */
1287 * A function-like macro has been found. Read in the arguments,
1288 * expand them and push-back everything for another scan.
1290 DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
1291 savch(0);
1292 if (readargs(sp, argary)) {
1293 /* Bailed out in the middle of arg list */
1294 unpstr(bp);
1295 if (dflag>1)printf("%d:noreadargs\n", lvl);
1296 stringbuf = bp;
1297 return 0;
1300 /* when all args are read from input stream */
1301 ch = addmac(sp);
1303 DDPRINT(("%d:submac pre\n", lvl));
1304 cunput(WARN);
1306 subarg(sp, argary, lvl+1);
1308 DDPRINT(("%d:submac post\n", lvl));
1309 insblock(ch);
1310 delwarn();
1312 stringbuf = bp; /* Reset heap */
1313 DPRINT(("%d:Return submac\n", lvl));
1314 IMP("SM1");
1315 return 1;
1319 * Read arguments and put in argument array.
1320 * If WARN is encountered return 1, otherwise 0.
1323 readargs(struct symtab *sp, const usch **args)
1325 const usch *vp = sp->value;
1326 int c, i, plev, narg, ellips = 0;
1327 int warn;
1329 DPRINT(("readargs\n"));
1331 narg = *vp--;
1332 if (narg == VARG) {
1333 narg = *vp--;
1334 ellips = 1;
1337 IMP("RDA1");
1339 * read arguments and store them on heap.
1341 warn = 0;
1342 c = '(';
1343 for (i = 0; i < narg && c != ')'; i++) {
1344 args[i] = stringbuf;
1345 plev = 0;
1346 while ((c = sloscan()) == WSPACE || c == '\n')
1347 if (c == '\n')
1348 putch(cinput());
1349 for (;;) {
1350 while (c == EBLOCK) {
1351 sss();
1352 c = sloscan();
1354 if (c == WARN) {
1355 warn++;
1356 goto oho;
1358 if (plev == 0 && (c == ')' || c == ','))
1359 break;
1360 if (c == '(')
1361 plev++;
1362 if (c == ')')
1363 plev--;
1364 savstr((usch *)yytext);
1365 oho: while ((c = sloscan()) == '\n') {
1366 putch(cinput());
1367 savch(' ');
1369 while (c == CMNT) {
1370 getcmnt();
1371 c = sloscan();
1373 if (c == 0)
1374 error("eof in macro");
1376 while (args[i] < stringbuf &&
1377 iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
1378 stringbuf--;
1379 savch('\0');
1380 if (dflag) {
1381 printf("readargs: save arg %d '", i);
1382 prline(args[i]);
1383 printf("'\n");
1387 IMP("RDA2");
1388 /* Handle varargs readin */
1389 if (ellips)
1390 args[i] = (const usch *)"";
1391 if (ellips && c != ')') {
1392 args[i] = stringbuf;
1393 plev = 0;
1394 while ((c = sloscan()) == WSPACE)
1396 for (;;) {
1397 if (plev == 0 && c == ')')
1398 break;
1399 if (c == '(')
1400 plev++;
1401 if (c == ')')
1402 plev--;
1403 if (c == EBLOCK) {
1404 sss();
1405 } else
1406 savstr((usch *)yytext);
1407 while ((c = sloscan()) == '\n') {
1408 cinput();
1409 savch(' ');
1412 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
1413 stringbuf--;
1414 savch('\0');
1417 if (narg == 0 && ellips == 0)
1418 while ((c = sloscan()) == WSPACE || c == '\n')
1419 if (c == '\n')
1420 cinput();
1422 if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1423 error("wrong arg count");
1424 while (warn)
1425 cunput(WARN), warn--;
1426 return 0;
1429 #if 0
1431 * Maybe an indentifier (for macro expansion).
1433 static int
1434 mayid(usch *s)
1436 for (; *s; s++)
1437 if (!isdigit(*s) && !isalpha(*s) && *s != '_')
1438 return 0;
1439 return 1;
1441 #endif
1444 * expand a function-like macro.
1445 * vp points to end of replacement-list
1446 * reads function arguments from sloscan()
1447 * result is pushed-back for more scanning.
1449 void
1450 subarg(struct symtab *nl, const usch **args, int lvl)
1452 int narg, instr, snuff;
1453 const usch *sp, *bp, *ap, *vp;
1455 DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
1456 vp = nl->value;
1457 narg = *vp--;
1458 if (narg == VARG)
1459 narg = *vp--;
1461 sp = vp;
1462 instr = snuff = 0;
1463 if (dflag>1) {
1464 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
1465 prrep(vp);
1466 printf("'\n");
1470 * push-back replacement-list onto lex buffer while replacing
1471 * arguments. Arguments are macro-expanded if required.
1473 while (*sp != 0) {
1474 if (*sp == SNUFF)
1475 cunput('\"'), snuff ^= 1;
1476 else if (*sp == CONC)
1478 else if (*sp == WARN) {
1480 if (sp[-1] == VARG) {
1481 bp = ap = args[narg];
1482 sp--;
1483 #ifdef GCC_COMPAT
1484 } else if (sp[-1] == GCCARG) {
1485 ap = args[narg];
1486 if (ap[0] == 0)
1487 ap = (const usch *)"0";
1488 bp = ap;
1489 sp--;
1490 #endif
1491 } else
1492 bp = ap = args[(int)*--sp];
1493 if (dflag>1){
1494 printf("%d:subarg GOTwarn; arglist '", lvl);
1495 prline(bp);
1496 printf("'\n");
1498 if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
1500 * Expand an argument; 6.10.3.1:
1501 * "A parameter in the replacement list,
1502 * is replaced by the corresponding argument
1503 * after all macros contained therein have
1504 * been expanded.".
1506 cunput(WARN);
1507 unpstr(bp);
1508 exparg(lvl+1);
1509 delwarn();
1510 } else {
1511 while (*bp)
1512 bp++;
1513 while (bp > ap) {
1514 bp--;
1515 if (snuff && !instr && iswsnl(*bp)) {
1516 while (iswsnl(*bp))
1517 bp--;
1518 cunput(' ');
1521 cunput(*bp);
1522 if ((*bp == '\'' || *bp == '"')
1523 && bp[-1] != '\\' && snuff) {
1524 instr ^= 1;
1525 if (instr == 0 && *bp == '"')
1526 cunput('\\');
1528 if (instr && (*bp == '\\' || *bp == '"'))
1529 cunput('\\');
1532 } else
1533 cunput(*sp);
1534 sp--;
1536 DPRINT(("%d:Return subarg\n", lvl));
1537 IMP("SUBARG");
1541 * Do a (correct) expansion of a WARN-terminated buffer of tokens.
1542 * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
1543 * Expansion blocking is not altered here unless when tokens are
1544 * concatenated, in which case they are removed.
1546 void
1547 exparg(int lvl)
1549 struct symtab *nl;
1550 int c, i;
1551 usch *och;
1552 usch *osb = stringbuf;
1553 int anychange;
1555 DPRINT(("%d:exparg\n", lvl));
1556 IMP("EXPARG");
1558 readmac++;
1559 rescan:
1560 anychange = 0;
1561 while ((c = sloscan()) != WARN) {
1562 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
1563 IMP("EA0");
1564 switch (c) {
1566 case EBLOCK:
1567 doblk();
1568 /* FALLTHROUGH */
1569 case IDENT:
1571 * Handle argument concatenation here.
1572 * In case of concatenation, scratch all blockings.
1574 DDPRINT(("%d:exparg ident %d\n", lvl, c));
1575 och = stringbuf;
1577 sav: savstr(yytext);
1579 if ((c = cinput()) == EBLOCK) {
1580 /* yep, are concatenating; forget blocks */
1581 do {
1582 (void)cinput();
1583 (void)cinput();
1584 } while ((c = sloscan()) == EBLOCK);
1585 bidx = 0;
1586 goto sav;
1588 cunput(c);
1590 DPRINT(("%d:exparg: str '%s'\n", lvl, och));
1591 IMP("EA1");
1592 /* see if ident is expandable */
1593 if ((nl = lookup(och, FIND)) && okexp(nl)) {
1594 if (submac(nl, lvl+1)) {
1595 /* Could expand, result on lexbuffer */
1596 stringbuf = och; /* clear saved name */
1597 anychange = 1;
1599 } else if (bidx) {
1600 /* must restore blocks */
1601 stringbuf = och;
1602 for (i = 0; i < bidx; i++)
1603 savch(EBLOCK), savch(bptr[i] & 255),
1604 savch(bptr[i] >> 8);
1605 savstr(yytext);
1607 bidx = 0;
1608 IMP("EA2");
1609 break;
1611 case CMNT:
1612 getcmnt();
1613 break;
1615 case '\n':
1616 cinput();
1617 savch(' ');
1618 break;
1620 default:
1621 savstr((usch *)yytext);
1622 break;
1625 *stringbuf = 0;
1626 cunput(WARN);
1627 unpstr(osb);
1628 DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
1629 IMP("EXPRET");
1630 stringbuf = osb;
1631 if (anychange)
1632 goto rescan;
1633 readmac--;
1636 void
1637 imp(const char *str)
1639 printf("%s (%d) '", str, bidx);
1640 prline(ifiles->curptr);
1641 printf("'\n");
1644 void
1645 prrep(const usch *s)
1647 while (*s) {
1648 switch (*s) {
1649 case WARN: printf("<ARG(%d)>", *--s); break;
1650 case CONC: printf("<CONC>"); break;
1651 case SNUFF: printf("<SNUFF>"); break;
1652 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
1653 default: printf("%c", *s); break;
1655 s--;
1659 void
1660 prline(const usch *s)
1662 while (*s) {
1663 switch (*s) {
1664 case WARN: printf("<WARN>"); break;
1665 case CONC: printf("<CONC>"); break;
1666 case SNUFF: printf("<SNUFF>"); break;
1667 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
1668 case '\n': printf("<NL>"); break;
1669 default: printf("%c", *s); break;
1671 s++;
1675 usch *
1676 savstr(const usch *str)
1678 usch *rv = stringbuf;
1680 do {
1681 if (stringbuf >= &sbf[SBSIZE]) {
1682 stringbuf = sbf; /* need space to write error message */
1683 error("out of macro space!");
1685 } while ((*stringbuf++ = *str++));
1686 stringbuf--;
1687 return rv;
1690 void
1691 unpstr(const usch *c)
1693 const usch *d = c;
1695 #if 0
1696 if (dflag>1) {
1697 printf("Xunpstr: '");
1698 prline(c);
1699 printf("'\n");
1701 #endif
1702 while (*d) {
1703 if (*d == EBLOCK)
1704 d += 2;
1705 d++;
1707 while (d > c) {
1708 cunput(*--d);
1712 void
1713 flbuf()
1715 if (obufp == 0)
1716 return;
1717 if (Mflag == 0 && write(ofd, outbuf, obufp) < 0)
1718 error("obuf write error");
1719 lastoch = outbuf[obufp-1];
1720 obufp = 0;
1723 void
1724 putch(int ch)
1726 outbuf[obufp++] = (usch)ch;
1727 if (obufp == CPPBUF || (istty && ch == '\n'))
1728 flbuf();
1731 void
1732 putstr(const usch *s)
1734 for (; *s; s++) {
1735 outbuf[obufp++] = *s;
1736 if (obufp == CPPBUF || (istty && *s == '\n'))
1737 flbuf();
1742 * convert a number to an ascii string. Store it on the heap.
1744 static void
1745 num2str(int num)
1747 static usch buf[12];
1748 usch *b = buf;
1749 int m = 0;
1751 if (num < 0)
1752 num = -num, m = 1;
1753 do {
1754 *b++ = (usch)(num % 10 + '0');
1755 num /= 10;
1756 } while (num);
1757 if (m)
1758 *b++ = '-';
1759 while (b > buf)
1760 savch(*--b);
1764 * similar to sprintf, but only handles %s and %d.
1765 * saves result on heap.
1767 usch *
1768 sheap(const char *fmt, ...)
1770 va_list ap;
1771 usch *op = stringbuf;
1773 va_start(ap, fmt);
1774 for (; *fmt; fmt++) {
1775 if (*fmt == '%') {
1776 fmt++;
1777 switch (*fmt) {
1778 case 's':
1779 savstr(va_arg(ap, usch *));
1780 break;
1781 case 'd':
1782 num2str(va_arg(ap, int));
1783 break;
1784 case 'c':
1785 savch(va_arg(ap, int));
1786 break;
1787 default:
1788 break; /* cannot call error() here */
1790 } else
1791 savch(*fmt);
1793 va_end(ap);
1794 *stringbuf = 0;
1795 return op;
1798 void
1799 usage()
1801 error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
1804 #ifdef notyet
1806 * Symbol table stuff.
1807 * The data structure used is a patricia tree implementation using only
1808 * bytes to store offsets.
1809 * The information stored is (lower address to higher):
1811 * unsigned char bitno[2]; bit number in the string
1812 * unsigned char left[3]; offset from base to left element
1813 * unsigned char right[3]; offset from base to right element
1815 #endif
1818 * This patricia implementation is more-or-less the same as
1819 * used in ccom for string matching.
1821 struct tree {
1822 int bitno;
1823 struct tree *lr[2];
1826 #define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
1827 #define LEFT_IS_LEAF 0x80000000
1828 #define RIGHT_IS_LEAF 0x40000000
1829 #define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0)
1830 #define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0)
1831 #define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
1832 #define CHECKBITS 8
1834 static struct tree *sympole;
1835 static int numsyms;
1838 * Allocate a symtab struct and store the string.
1840 static struct symtab *
1841 getsymtab(const usch *str)
1843 struct symtab *sp = malloc(sizeof(struct symtab));
1845 if (sp == NULL)
1846 error("getsymtab: couldn't allocate symtab");
1847 sp->namep = savstr(str);
1848 savch('\0');
1849 sp->value = NULL;
1850 sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
1851 sp->line = ifiles ? ifiles->lineno : 0;
1852 return sp;
1856 * Do symbol lookup in a patricia tree.
1857 * Only do full string matching, no pointer optimisations.
1859 struct symtab *
1860 lookup(const usch *key, int enterf)
1862 struct symtab *sp;
1863 struct tree *w, *new, *last;
1864 int len, cix, bit, fbit, svbit, ix, bitno;
1865 const usch *k, *m, *sm;
1867 /* Count full string length */
1868 for (k = key, len = 0; *k; k++, len++)
1871 switch (numsyms) {
1872 case 0: /* no symbols yet */
1873 if (enterf != ENTER)
1874 return NULL;
1875 sympole = (struct tree *)getsymtab(key);
1876 numsyms++;
1877 return (struct symtab *)sympole;
1879 case 1:
1880 w = sympole;
1881 svbit = 0; /* XXX gcc */
1882 break;
1884 default:
1885 w = sympole;
1886 bitno = len * CHECKBITS;
1887 for (;;) {
1888 bit = BITNO(w->bitno);
1889 fbit = bit > bitno ? 0 : P_BIT(key, bit);
1890 svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
1891 IS_LEFT_LEAF(w->bitno);
1892 w = w->lr[fbit];
1893 if (svbit)
1894 break;
1898 sp = (struct symtab *)w;
1900 sm = m = sp->namep;
1901 k = key;
1903 /* Check for correct string and return */
1904 for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
1906 if (*m == 0 && *k == 0) {
1907 if (enterf != ENTER && sp->value == NULL)
1908 return NULL;
1909 return sp;
1912 if (enterf != ENTER)
1913 return NULL; /* no string found and do not enter */
1915 ix = *m ^ *k;
1916 while ((ix & 1) == 0)
1917 ix >>= 1, cix++;
1919 /* Create new node */
1920 if ((new = malloc(sizeof *new)) == NULL)
1921 error("getree: couldn't allocate tree");
1922 bit = P_BIT(key, cix);
1923 new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
1924 new->lr[bit] = (struct tree *)getsymtab(key);
1926 if (numsyms++ == 1) {
1927 new->lr[!bit] = sympole;
1928 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
1929 sympole = new;
1930 return (struct symtab *)new->lr[bit];
1933 w = sympole;
1934 last = NULL;
1935 for (;;) {
1936 fbit = w->bitno;
1937 bitno = BITNO(w->bitno);
1938 if (bitno == cix)
1939 error("bitno == cix");
1940 if (bitno > cix)
1941 break;
1942 svbit = P_BIT(key, bitno);
1943 last = w;
1944 w = w->lr[svbit];
1945 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
1946 break;
1949 new->lr[!bit] = w;
1950 if (last == NULL) {
1951 sympole = new;
1952 } else {
1953 last->lr[svbit] = new;
1954 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
1956 if (bitno < cix)
1957 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
1958 return (struct symtab *)new->lr[bit];
1961 usch *
1962 xstrdup(const usch *str)
1964 size_t len = strlen((const char *)str)+1;
1965 usch *rv;
1967 if ((rv = malloc(len)) == NULL)
1968 error("xstrdup: out of mem");
1969 strlcpy((char *)rv, (const char *)str, len);
1970 return rv;