1/*	Id: cpp.c,v 1.252 2016/02/06 09:39:21 ragge Exp 	*/
2/*	$NetBSD: cpp.c,v 1.4 2016/02/09 20:37:32 plunky Exp $	*/
3
4/*
5 * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * The C preprocessor.
31 * This code originates from the V6 preprocessor with some additions
32 * from V7 cpp, and at last ansi/c99 support.
33 *
34 * 	- kfind() expands the input buffer onto XXX
35 *	- exparg() expand one buffer into another.
36 *		Recurses into submac() for fun-like macros.
37 *	- submac() replaces the given macro.
38 *		Recurses into subarg() for fun-like macros.
39 *	- subarg() expands fun-like macros.
40 *		Create strings, concats args, recurses into exparg.
41 */
42
43#include "config.h"
44
45#include <sys/stat.h>
46
47#include <fcntl.h>
48#ifdef HAVE_UNISTD_H
49#include <unistd.h>
50#endif
51#include <stdio.h>
52#include <stdarg.h>
53#include <stdlib.h>
54#include <string.h>
55#include <time.h>
56
57#include "compat.h"
58#include "cpp.h"
59
60#ifndef S_ISDIR
61#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
62#endif
63
64#define	SBSIZE	1000000
65
66static usch	sbf[SBSIZE];
67static int	counter;
68/* C command */
69
70int tflag;	/* traditional cpp syntax */
71#ifdef PCC_DEBUG
72int dflag;	/* debug printouts */
73//static void imp(const char *);
74static void prline(const usch *s);
75static void prrep(const usch *s);
76#define	DPRINT(x) if (dflag) printf x
77#define	DDPRINT(x) if (dflag > 1) printf x
78#define	IMP(x) if (dflag > 1) imp(x)
79#else
80#define DPRINT(x)
81#define DDPRINT(x)
82#define IMP(x)
83#endif
84
85int Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag;
86char *Mfile, *MPfile;
87struct initar *initar;
88char *Mxfile;
89int warnings, Mxlen;
90FILE *of;
91
92/* include dirs */
93struct incs {
94	struct incs *next;
95	usch *dir;
96	dev_t dev;
97	ino_t ino;
98} *incdir[2];
99
100static struct symtab *filloc;
101static struct symtab *linloc;
102static struct symtab *pragloc;
103static struct symtab *defloc;
104static struct symtab *ctrloc;
105int	trulvl;
106int	flslvl;
107int	elflvl;
108int	elslvl;
109usch *stringbuf = sbf;
110
111/*
112 * Macro replacement list syntax:
113 * - For object-type macros, replacement strings are stored as-is.
114 * - For function-type macros, macro args are substituted for the
115 *   character WARN followed by the argument number.
116 * - The value element points to the beginning of the string.
117 *
118 * The first character in the replacement list is the number of arguments:
119 *   VARG  - ends with ellipsis, next char is argcount without ellips.
120 *   OBJCT - object-type macro
121 *   0	   - empty parenthesis, foo()
122 *   1->   - number of args.
123 *
124 * WARN is used:
125 *	- in stored replacement lists to tell that an argument comes
126 *	- When expanding replacement lists to tell that the list ended.
127 *
128 * To ensure that an already expanded identifier won't get expanded
129 * again a EBLOCK char + its number is stored directly before any
130 * expanded identifier.
131 */
132
133/* args for lookup() */
134#define	FIND	0
135#define	ENTER	1
136
137/*
138 * No-replacement array.  If a macro is found and exists in this array
139 * then no replacement shall occur.
140 */
141struct blocker {
142	struct blocker *next;
143	struct symtab *sp;
144};
145struct blocker *blkidx[RECMAX];
146int blkidp;
147
148static int readargs2(usch **, struct symtab *sp, const usch **args);
149static int readargs1(struct symtab *sp, const usch **args);
150static struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *);
151static struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *);
152static void usage(void);
153static usch *xstrdup(const usch *str);
154static void addidir(char *idir, struct incs **ww);
155static void vsheap(const char *, va_list);
156static int skipws(struct iobuf *ib);
157static int getyp(usch *s);
158static void *xrealloc(void *p, int sz);
159static void *xmalloc(int sz);
160
161usch locs[] =
162	{ FILLOC, LINLOC, PRAGLOC, DEFLOC,
163	    'd','e','f','i','n','e','d',0, CTRLOC };
164
165int
166main(int argc, char **argv)
167{
168	struct initar *it;
169	register int ch;
170	const usch *fn1, *fn2;
171
172#ifdef TIMING
173	struct timeval t1, t2;
174
175	(void)gettimeofday(&t1, NULL);
176#endif
177
178	while ((ch = getopt(argc, argv, "ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
179		switch (ch) {
180		case 'A': /* assembler input */
181			Aflag++;
182			break;
183
184		case 'C': /* Do not discard comments */
185			Cflag++;
186			break;
187
188		case 'E': /* treat warnings as errors */
189			Eflag++;
190			break;
191
192		case 'D': /* define something */
193		case 'i': /* include */
194		case 'U': /* undef */
195			/* XXX should not need malloc() here */
196			if ((it = xmalloc(sizeof(struct initar))) == NULL)
197				error("couldn't apply -%c %s", ch, optarg);
198			it->type = ch;
199			it->str = optarg;
200			it->next = initar;
201			initar = it;
202			break;
203
204		case 'd':
205			while (*optarg) {
206				switch(*optarg) {
207				case 'M': /* display macro definitions */
208					dMflag = 1;
209					Mflag = 1;
210					break;
211
212				default: /* ignore others */
213					break;
214				}
215				optarg++;
216			}
217			break;
218
219		case 'I':
220		case 'S':
221			addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
222			break;
223
224		case 'M': /* Generate dependencies for make */
225			Mflag++;
226			break;
227
228		case 'P': /* Inhibit generation of line numbers */
229			Pflag++;
230			break;
231
232		case 't':
233			tflag = 1;
234			break;
235
236#ifdef PCC_DEBUG
237		case 'V':
238			dflag++;
239			break;
240#endif
241		case 'v':
242			fprintf(stderr, "PCC preprocessor version "VERSSTR"\n");
243			break;
244
245		case 'x':
246			if (strcmp(optarg, "MMD") == 0) {
247				MMDflag++;
248			} else if (strcmp(optarg, "MP") == 0) {
249				MPflag++;
250			} else if (strncmp(optarg, "MT,", 3) == 0 ||
251			    strncmp(optarg, "MQ,", 3) == 0) {
252				int l = strlen(optarg+3) + 2;
253				char *cp, *up;
254
255				if (optarg[1] == 'Q')
256					for (cp = optarg+3; *cp; cp++)
257						if (*cp == '$')
258							l++;
259				Mxlen += l;
260				Mxfile = cp = realloc(Mxfile, Mxlen);
261				for (up = Mxfile; *up; up++)
262					;
263				if (up != Mxfile)
264					*up++ = ' ';
265				for (cp = optarg+3; *cp; cp++) {
266					*up++ = *cp;
267					if (optarg[1] == 'Q' && *cp == '$')
268						*up++ = *cp;
269				}
270				*up = 0;
271			} else
272				usage();
273			break;
274
275		case '?':
276		default:
277			usage();
278		}
279	}
280
281	argc -= optind;
282	argv += optind;
283
284	filloc = lookup((const usch *)"__FILE__", ENTER);
285	linloc = lookup((const usch *)"__LINE__", ENTER);
286	pragloc = lookup((const usch *)"_Pragma", ENTER);
287	defloc = lookup((const usch *)"defined", ENTER);
288	ctrloc = lookup((const usch *)"__COUNTER__", ENTER);
289	filloc->value = locs;
290	linloc->value = locs+1;
291	pragloc->value = locs+2;
292	defloc->value = locs+3; /* also have macro name here */
293	ctrloc->value = locs+12;
294
295	if (Mflag && !dMflag) {
296		char *c;
297
298		if (argc < 1)
299			error("-M and no infile");
300		if ((c = strrchr(argv[0], '/')) == NULL)
301			c = argv[0];
302		else
303			c++;
304		Mfile = (char *)xstrdup((usch *)c);
305		if (MPflag)
306			MPfile = (char *)xstrdup((usch *)c);
307		if (Mxfile)
308			Mfile = Mxfile;
309		if ((c = strrchr(Mfile, '.')) == NULL)
310			error("-M and no extension: ");
311		c[1] = 'o';
312		c[2] = 0;
313	}
314
315	if (argc == 2) {
316		if ((of = freopen(argv[1], "w", stdout)) == NULL)
317			error("Can't creat %s", argv[1]);
318	} else
319		of = stdout;
320
321	if (argc && strcmp(argv[0], "-")) {
322		fn1 = fn2 = (usch *)argv[0];
323	} else {
324		fn1 = NULL;
325		fn2 = (const usch *)"";
326	}
327	if (pushfile(fn1, fn2, 0, NULL))
328		error("cannot open %s", argv[0]);
329
330	fclose(of);
331#ifdef TIMING
332	(void)gettimeofday(&t2, NULL);
333	t2.tv_sec -= t1.tv_sec;
334	t2.tv_usec -= t1.tv_usec;
335	if (t2.tv_usec < 0) {
336		t2.tv_usec += 1000000;
337		t2.tv_sec -= 1;
338	}
339	fprintf(stderr, "cpp total time: %ld s %ld us\n",
340	     (long)t2.tv_sec, (long)t2.tv_usec);
341#endif
342	if (Eflag && warnings > 0)
343		return 2;
344
345	return 0;
346}
347
348/*
349 * Write a character to an out buffer.
350 */
351static void
352putob(struct iobuf *ob, int ch)
353{
354	if (ob->cptr == ob->bsz) {
355		int sz = ob->bsz - ob->buf;
356		ob->buf = xrealloc(ob->buf, sz + BUFSIZ);
357		ob->cptr = ob->buf + sz;
358		ob->bsz = ob->buf + sz + BUFSIZ;
359	}
360//	DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch));
361	*ob->cptr++ = ch;
362}
363
364static int nbufused;
365/*
366 * Write a character to an out buffer.
367 */
368static struct iobuf *
369getobuf(void)
370{
371	struct iobuf *iob = xmalloc(sizeof(struct iobuf));
372
373	nbufused++;
374	iob->buf = iob->cptr = xmalloc(BUFSIZ);
375	iob->bsz = iob->buf + BUFSIZ;
376	iob->ro = 0;
377	return iob;
378}
379
380/*
381 * Create a read-only input buffer.
382 */
383static struct iobuf *
384mkrobuf(const usch *s)
385{
386	struct iobuf *iob = xmalloc(sizeof(struct iobuf));
387
388	nbufused++;
389	DPRINT(("mkrobuf %s\n", s));
390	iob->buf = iob->cptr = (usch *)s;
391	iob->bsz = iob->buf + strlen((char *)iob->buf);
392	iob->ro = 1;
393	return iob;
394}
395
396/*
397 * Copy a string to a buffer.
398 */
399static struct iobuf *
400strtobuf(usch *str, struct iobuf *iob)
401{
402	DPRINT(("strtobuf iob %p buf %p str %s\n", iob, iob->buf, str));
403	if (iob == NULL)
404		iob = getobuf();
405	do {
406		putob(iob, *str);
407	} while (*str++);
408	iob->cptr--;
409	return iob;
410}
411
412static void
413bufree(struct iobuf *iob)
414{
415	nbufused--;
416	if (iob->ro == 0)
417		free(iob->buf);
418	free(iob);
419}
420
421static void
422addidir(char *idir, struct incs **ww)
423{
424	struct incs *w;
425	struct stat st;
426
427	if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
428		return; /* ignore */
429	if (*ww != NULL) {
430		for (w = *ww; w->next; w = w->next) {
431#ifdef _WIN32
432			if (strcmp(w->dir, idir) == 0)
433				return;
434#else
435			if (w->dev == st.st_dev && w->ino == st.st_ino)
436				return;
437#endif
438		}
439#ifdef _WIN32
440		if (strcmp(w->dir, idir) == 0)
441			return;
442#else
443		if (w->dev == st.st_dev && w->ino == st.st_ino)
444			return;
445#endif
446		ww = &w->next;
447	}
448	if ((w = calloc(sizeof(struct incs), 1)) == NULL)
449		error("couldn't add path %s", idir);
450	w->dir = (usch *)idir;
451	w->dev = st.st_dev;
452	w->ino = st.st_ino;
453	*ww = w;
454}
455
456void
457line(void)
458{
459	struct symtab *nl;
460	int c, n, ln;
461	usch *cp;
462
463	cp = stringbuf;
464	c = skipws(0);
465	if (ISID0(c)) { /* expand macro */
466		heapid(c);
467		stringbuf = cp;
468		if ((nl = lookup(cp, FIND)) == 0 || kfind(nl) == 0)
469			goto bad;
470	} else {
471		do {
472			savch(c);
473		} while (ISDIGIT(c = cinput()));
474		cunput(c);
475		savch(0);
476	}
477
478	stringbuf = cp;
479	n = 0;
480	while (ISDIGIT(*cp))
481		n = n * 10 + *cp++ - '0';
482	if (*cp != 0)
483		goto bad;
484
485	/* Can only be decimal number here between 1-2147483647 */
486	if (n < 1 || n > 2147483647)
487		goto bad;
488
489	ln = n;
490	ifiles->escln = 0;
491	if ((c = skipws(NULL)) != '\n') {
492		if (c == 'L' || c == 'U' || c == 'u') {
493			n = c, c = cinput();
494			if (n == 'u' && c == '8')
495				c = cinput();
496			if (c == '\"')
497				warning("#line only allows character literals");
498		}
499		if (c != '\"')
500			goto bad;
501		/* loses space on heap... does it matter? */
502		ifiles->fname = stringbuf+1;
503		faststr(c, savch);
504		stringbuf--;
505		savch(0);
506
507		c = skipws(0);
508	}
509	if (c != '\n')
510		goto bad;
511
512	ifiles->lineno = ln;
513	prtline(1);
514	ifiles->lineno--;
515	cunput('\n');
516	return;
517
518bad:	error("bad #line");
519}
520
521#ifdef MACHOABI
522
523/*
524 * Search for framework header file.
525 * Return 1 on success.
526 */
527
528static int
529fsrch_macos_framework(const usch *fn, const usch *dir)
530{
531	usch *saved_stringbuf = stringbuf;
532	usch *s = (usch *)strchr((const char*)fn, '/');
533	usch *nm;
534	usch *p;
535	int len  = s - fn;
536
537	if (s == NULL)
538		return 0;
539
540//	fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir);
541
542	nm = savstr(dir);
543	savch(0);
544	p = savstr(fn);
545	stringbuf = p + len;
546	savch(0);
547//	fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn);
548	p = (usch *)strstr((const char *)nm, (const char *)p);
549//	fprintf(stderr, "p = %s\n", (const char *)p);
550	if (p != NULL) {
551		stringbuf = p;
552		savch(0);
553		return fsrch_macos_framework(fn, nm);
554	}
555
556	p = nm + strlen((char *)nm) - 1;
557	while (*p == '/')
558		p--;
559	while (*p != '/')
560		p--;
561	stringbuf = ++p;
562	savstr((const usch *)"Frameworks/");
563	stringbuf = savstr(fn) + len;
564	savstr((const usch*)".framework/Headers");
565	savstr(s);
566	savch(0);
567
568//	fprintf(stderr, "nm: %s\n", nm);
569
570	if (pushfile(nm, fn, SYSINC, NULL) == 0)
571		return 1;
572//	fprintf(stderr, "not found %s, continuing...\n", nm);
573
574	stringbuf = saved_stringbuf;
575
576	return 0;
577}
578
579#endif
580
581/*
582 * Search for and include next file.
583 * Return 1 on success.
584 */
585static int
586fsrch(const usch *fn, int idx, struct incs *w)
587{
588	int i;
589
590	for (i = idx; i < 2; i++) {
591		if (i > idx)
592			w = incdir[i];
593		for (; w; w = w->next) {
594			usch *nm = stringbuf;
595
596			savstr(w->dir); savch('/');
597			savstr(fn); savch(0);
598			if (pushfile(nm, fn, i, w->next) == 0)
599				return 1;
600			stringbuf = nm;
601		}
602	}
603
604#ifdef MACHOABI
605	/*
606	 * On MacOS, we may have to do some clever stuff
607	 * to resolve framework headers.
608	 */
609	{
610		usch *dir = stringbuf;
611		savstr(ifiles->orgfn);
612		stringbuf = (usch *)strrchr((char *)dir, '/');
613		if (stringbuf != NULL) {
614			stringbuf++;
615			savch(0);
616			if (fsrch_macos_framework(fn, dir) == 1)
617				return 1;
618		}
619		stringbuf = dir;
620
621		if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1)
622			return 1;
623
624		if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1)
625			return 1;
626	}
627#endif
628
629	return 0;
630}
631
632static void
633prem(void)
634{
635	error("premature EOF");
636}
637
638static struct iobuf *
639incfn(void)
640{
641	struct iobuf *ob;
642	struct symtab *nl;
643	usch *sb;
644	int c;
645
646	sb = stringbuf;
647	if (spechr[c = skipws(NULL)] & C_ID0) {
648		heapid(c);
649		if ((nl = lookup(sb, FIND)) == NULL)
650			return NULL;
651
652		stringbuf = sb;
653		if (kfind(nl) == 0)
654			return NULL;
655		ob = strtobuf(sb, NULL);
656	} else {
657		ob = getobuf();
658		putob(ob, c);
659		while ((c = cinput()) && c != '\n')
660			putob(ob, c);
661		if (c != '\n')
662			return NULL;
663		cunput(c);
664	}
665	putob(ob, 0);
666	ob->cptr--;
667
668	/* now we have an (expanded?) filename in obuf */
669	while (ob->buf < ob->cptr && ISWS(ob->cptr[-1]))
670		ob->cptr--;
671
672	if (ob->buf[0] != '\"' && ob->buf[0] != '<')
673		return NULL;
674	if (ob->cptr[-1] != '\"' && ob->cptr[-1] != '>')
675		return NULL;
676	ob->cptr[-1] = 0;
677	return ob;
678}
679
680/*
681 * Include a file. Include order:
682 * - For <...> files, first search -I directories, then system directories.
683 * - For "..." files, first search "current" dir, then as <...> files.
684 */
685void
686include(void)
687{
688	struct iobuf *ob;
689	usch *fn, *nm = NULL;
690
691	if (flslvl)
692		return;
693
694	if ((ob = incfn()) == NULL) /* get include file name in obuf */
695		error("bad #include");
696
697	fn = xstrdup(ob->buf) + 1;	/* Save on string heap? */
698	bufree(ob);
699	/* test absolute path first */
700	if (fn[0] == '/' && pushfile(fn, fn, 0, NULL) == 0)
701		goto okret;
702	if (fn[-1] == '\"') {
703		/* nope, failed, try to create a path for it */
704		if ((nm = (usch *)strrchr((char *)ifiles->orgfn, '/'))) {
705			ob = strtobuf((usch *)ifiles->orgfn, NULL);
706			ob->cptr = ob->buf + (nm - ifiles->orgfn) + 1;
707			strtobuf(fn, ob);
708			putob(ob, 0);
709			nm = xstrdup(ob->buf);
710			bufree(ob);
711		} else {
712			nm = xstrdup(fn);
713		}
714		if (pushfile(nm, nm, 0, NULL) == 0) {
715			free(fn-1);
716			goto okret;
717		}
718	}
719	if (fsrch(fn, 0, incdir[0]))
720		goto okret;
721
722	error("cannot find '%s'", fn);
723	/* error() do not return */
724
725okret:
726	if (nm)
727		free(nm);
728	prtline(1);
729}
730
731void
732include_next(void)
733{
734	struct iobuf *ob;
735	usch *nm;
736
737	if (flslvl)
738		return;
739
740	if ((ob = incfn()) == NULL) /* get include file name in obuf */
741		error("bad #include_next");
742
743	nm = xstrdup(ob->buf+1);
744	bufree(ob);
745
746	if (fsrch(nm, ifiles->idx, ifiles->incs) == 0)
747		error("cannot find '%s'", nm);
748	prtline(1);
749}
750
751/*
752 * Compare two replacement lists, taking in account comments etc.
753 */
754static int
755cmprepl(const usch *o, const usch *n)
756{
757	for (; *o; o++, n++) {
758		/* comment skip */
759		if (*o == '/' && o[1] == '*') {
760			while (*o != '*' || o[1] != '/')
761				o++;
762			o += 2;
763		}
764		if (*n == '/' && n[1] == '*') {
765			while (*n != '*' || n[1] != '/')
766				n++;
767			n += 2;
768		}
769		while (*o == ' ' || *o == '\t')
770			o++;
771		while (*n == ' ' || *n == '\t')
772			n++;
773		if (*o != *n)
774			return 1;
775	}
776	return 0;
777}
778
779static int
780isell(void)
781{
782	if (cinput() != '.' || cinput() != '.')
783		return 0;
784	return 1;
785}
786
787static int
788skipwscmnt(struct iobuf *ib)
789{
790	/* XXX comment */
791	return skipws(ib);
792}
793
794static int
795findarg(usch *s, usch **args, int narg)
796{
797	int i;
798
799	for (i = 0; i < narg; i++)
800		if (strcmp((char *)s, (char *)args[i]) == 0)
801			return i;
802	return -1;
803}
804
805/*
806 * gcc extensions:
807 * #define e(a...) f(s, a) ->  a works as __VA_ARGS__
808 * #define e(fmt, ...) f(s, fmt , ##__VA_ARGS__) -> remove , if no args
809 */
810void
811define(void)
812{
813	struct symtab *np;
814	usch *args[MAXARGS+1], *sbeg, *bp, cc[2], *vararg;
815	int c, i, redef, oCflag, t;
816	int narg = -1;
817	int wascon;
818
819	if (flslvl)
820		return;
821
822	oCflag = Cflag, Cflag = 0; /* Ignore comments here */
823	if (!ISID0(c = skipws(0)))
824		goto bad;
825
826	bp = heapid(c);
827	np = lookup(bp, ENTER);
828	if (np->value) {
829		stringbuf = bp;
830		redef = 1;
831	} else
832		redef = 0;
833
834	vararg = NULL;
835	sbeg = stringbuf++;
836	if ((c = cinput()) == '(') {
837		narg = 0;
838		/* function-like macros, deal with identifiers */
839		c = skipws(0);
840		for (;;) {
841			switch (c) {
842			case ')':
843				break;
844			case '.':
845				if (isell() == 0 || (c = skipws(0)) != ')')
846					goto bad;
847				vararg = (usch *)"__VA_ARGS__";
848				break;
849			default:
850				if (!ISID0(c))
851					goto bad;
852
853				bp = heapid(c);
854				/* make sure there is no arg of same name */
855				if (findarg(bp, args, narg) >= 0)
856					error("Duplicate parameter \"%s\"", bp);
857				if (narg == MAXARGS)
858					error("Too many macro args");
859				args[narg++] = xstrdup(bp);
860				stringbuf = bp;
861				switch ((c = skipws(0))) {
862				case ',': break;
863				case ')': continue;
864				case '.':
865					if (isell() == 0 || skipws(0) != ')')
866						goto bad;
867					vararg = args[--narg];
868					c = ')';
869					continue;
870				default:
871					goto bad;
872				}
873				c = skipws(0);
874			}
875			if (c == ')')
876				break;
877		}
878		c = skipws(0);
879	} else if (c == '\n') {
880		/* #define foo */
881		;
882	} else if (c == 0) {
883		prem();
884	} else if (!ISWS(c))
885		goto bad;
886
887	Cflag = oCflag; /* Enable comments again */
888
889	if (vararg)
890		stringbuf++;
891
892	if (ISWS(c))
893		c = skipwscmnt(0);
894
895#define	DELEWS() while (stringbuf > sbeg+1+(vararg!=NULL) && ISWS(stringbuf[-1])) stringbuf--
896
897	/* parse replacement-list, substituting arguments */
898	wascon = 0;
899	while (c != '\n') {
900		cc[0] = c, cc[1] = inc2();
901		t = getyp(cc);
902		cunput(cc[1]);
903
904		switch (t) {
905		case ' ':
906		case '\t':
907			savch(' '); /* save only one space */
908			while ((c = cinput()) == ' ' || c == '\t')
909				;
910			continue;
911
912		case '#':
913			if (cc[1] == '#') {
914				/* concat op */
915				(void)cinput(); /* eat # */
916				DELEWS();
917				savch(CONC);
918				if (ISID0(c = skipws(0)) && narg >= 0)
919					wascon = 1;
920				if (c == '\n')
921					goto bad; /* 6.10.3.3 p1 */
922				continue;
923			}
924
925			if (narg < 0) {
926				/* no meaning in object-type macro */
927				savch('#');
928				break;
929			}
930
931			/* remove spaces between # and arg */
932			savch(SNUFF);
933			c = skipws(0); /* whitespace, ignore */
934			if (!ISID0(c))
935				goto bad;
936			bp = heapid(c);
937			if (vararg && strcmp((char *)bp, (char *)vararg) == 0) {
938				stringbuf = bp;
939				savch(WARN);
940				savch(VARG);
941				savch(SNUFF);
942				break;
943
944			}
945			if ((i = findarg(bp, args, narg)) < 0)
946				goto bad;
947			stringbuf = bp;
948			savch(WARN);
949			savch(i);
950			savch(SNUFF);
951			break;
952
953		case NUMBER:
954			c = fastnum(c, savch);
955			continue;
956
957		case STRING:
958			if (c == 'L' || c == 'u' || c == 'U') {
959				savch(c);
960				if ((c = cinput()) == '8') {
961					savch(c);
962					c = cinput();
963				}
964			}
965			if (tflag)
966				savch(c);
967			else
968				faststr(c, savch);
969			break;
970
971		case IDENT:
972			bp = heapid(c);
973			stringbuf--; /* remove \0 */
974			if (narg < 0)
975				break; /* keep on heap */
976			if (vararg && strcmp((char *)bp, (char *)vararg) == 0) {
977				stringbuf = bp;
978				savch(WARN);
979				savch(wascon ? GCCARG : VARG);
980				break;
981			}
982
983			/* check if its an argument */
984			if ((i = findarg(bp, args, narg)) < 0)
985				break;
986			stringbuf = bp;
987			savch(WARN);
988			savch(i);
989			break;
990
991		case 0:
992			goto bad;
993
994		default:
995			savch(c);
996			break;
997		}
998		wascon = 0;
999		c = cinput();
1000	}
1001	cunput(c);
1002	/* remove trailing whitespace */
1003	DELEWS();
1004
1005	if (sbeg[1+(vararg != 0)] == CONC)
1006		goto bad; /* 6.10.3.3 p1 */
1007
1008	if (vararg) {
1009		sbeg[0] = VARG;
1010		sbeg[1] = narg;
1011	} else
1012		sbeg[0] = (narg < 0 ? OBJCT : narg);
1013	savch(0);
1014
1015	if (redef && ifiles->idx != SYSINC) {
1016		if (cmprepl(np->value, sbeg)) { /* not equal */
1017			np->value = sbeg;
1018			warning("%s redefined (previously defined at \"%s\" line %d)",
1019			    np->namep, np->file, np->line);
1020		} else
1021			stringbuf = sbeg;  /* forget this space */
1022	} else
1023		np->value = sbeg;
1024
1025#ifdef PCC_DEBUG
1026	if (dflag) {
1027		const usch *w = np->value;
1028
1029		printf("!define %s: ", np->namep);
1030		if (*w == OBJCT)
1031			printf("[object]");
1032		else if (*w == VARG)
1033			printf("[VARG%d]", *++w);
1034		else
1035			printf("[%d]", *w);
1036		putchar('\'');
1037		prrep(++w);
1038		printf("\'\n");
1039	}
1040#endif
1041	for (i = 0; i < narg; i++)
1042		free(args[i]);
1043	return;
1044
1045bad:	error("bad #define");
1046}
1047
1048void
1049warning(const char *fmt, ...)
1050{
1051	va_list ap;
1052
1053	if (ifiles != NULL)
1054		fprintf(stderr, "%s:%d: warning: ",
1055		    ifiles->fname, ifiles->lineno);
1056
1057	va_start(ap,fmt);
1058	vfprintf(stderr, fmt, ap);
1059	va_end(ap);
1060	fputc('\n', stderr);
1061
1062	warnings++;
1063}
1064
1065void
1066error(const char *fmt, ...)
1067{
1068	va_list ap;
1069
1070	if (ifiles != NULL)
1071		fprintf(stderr, "%s:%d: error: ",
1072		    ifiles->fname, ifiles->lineno);
1073
1074	va_start(ap, fmt);
1075	vfprintf(stderr, fmt, ap);
1076	va_end(ap);
1077	fputc('\n', stderr);
1078	exit(1);
1079}
1080
1081/*
1082 * store a character into the "define" buffer.
1083 */
1084void
1085savch(int c)
1086{
1087	if (stringbuf >= &sbf[SBSIZE])
1088		error("out of macro space!");
1089
1090	*stringbuf++ = (usch)c;
1091}
1092
1093static int
1094pragwin(struct iobuf *ib)
1095{
1096	return ib ? *ib->cptr++ : cinput();
1097}
1098
1099static int
1100skipws(struct iobuf *ib)
1101{
1102	int t;
1103
1104	while ((t = pragwin(ib)) == ' ' || t == '\t')
1105		;
1106	return t;
1107}
1108
1109/*
1110 * convert _Pragma() to #pragma for output.
1111 * Syntax is already correct.
1112 */
1113static void
1114pragoper(struct iobuf *ib)
1115{
1116	int t;
1117	usch *bp = stringbuf;
1118
1119	if (skipws(ib) != '(' || ((t = skipws(ib)) != '\"' && t != 'L'))
1120		goto err;
1121	if (t == 'L' && (t = pragwin(ib)) != '\"')
1122		goto err;
1123	savstr((const usch *)"\n#pragma ");
1124	while ((t = pragwin(ib)) != '\"') {
1125		if (t == BLKID) {
1126			pragwin(ib);
1127			continue;
1128		}
1129		if (t == '\"')
1130			continue;
1131		if (t == '\\') {
1132			if ((t = pragwin(ib)) != '\"' && t != '\\')
1133				savch('\\');
1134		}
1135		savch(t);
1136	}
1137	sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
1138	putstr(bp);
1139	stringbuf = bp;
1140	if (skipws(ib) == ')')
1141		return;
1142
1143err:	error("_Pragma() syntax error");
1144}
1145
1146static int
1147expok(struct symtab *sp, int l)
1148{
1149	struct blocker *w;
1150
1151	if (l == 0)
1152		return 1;
1153#ifdef PCC_DEBUG
1154if (dflag) { printf("expok blocked: "); for (w = blkidx[l]; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
1155#endif
1156	w = blkidx[l];
1157	while (w) {
1158		if (w->sp == sp)
1159			return 0;
1160		w = w->next;
1161	}
1162	return 1;
1163}
1164
1165static int
1166expokb(struct symtab *sp, struct blocker *bl)
1167{
1168	struct blocker *w;
1169
1170	if (bl == 0)
1171		return 1;
1172#ifdef PCC_DEBUG
1173if (dflag) { printf("expokb blocked: "); for (w = bl; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
1174#endif
1175	w = bl;
1176	while (w) {
1177		if (w->sp == sp)
1178			return 0;
1179		w = w->next;
1180	}
1181	return 1;
1182}
1183
1184static struct blocker *
1185blkget(struct symtab *sp, struct blocker *obl)
1186{
1187	struct blocker *bl = calloc(sizeof(*obl), 1);
1188
1189	bl->sp = sp;
1190	bl->next = obl;
1191	return bl;
1192}
1193
1194static int
1195blkix(struct blocker *obl)
1196{
1197	if (blkidp > 1 && blkidx[blkidp-1] == obl)
1198		return blkidp-1;
1199	if (blkidp == RECMAX)
1200		error("blkix");
1201	blkidx[blkidp] = obl;
1202	return blkidp++;
1203}
1204
1205static struct blocker *
1206mergeadd(struct blocker *bl, int m)
1207{
1208	struct blocker *w, *ww;
1209
1210	DPRINT(("mergeadd: %p %d\n", bl, m));
1211	if (bl == 0)
1212		return blkidx[m];
1213	if (m == 0)
1214		return bl;
1215
1216	blkidx[blkidp] = bl;
1217	for (w = blkidx[m]; w; w = w->next) {
1218		ww = calloc(sizeof(*w), 1);
1219		ww->sp = w->sp;
1220		ww->next = blkidx[blkidp];
1221		blkidx[blkidp] = ww;
1222	}
1223	DPRINT(("mergeadd return: %d ", blkidp));
1224#ifdef PCC_DEBUG
1225	if (dflag) {
1226		for (w = blkidx[blkidp]; w; w = w->next)
1227			printf("%s ", w->sp->namep);
1228		printf("\n");
1229	}
1230#endif
1231	return blkidx[blkidp++];
1232}
1233
1234static void
1235storeblk(int l, struct iobuf *ob)
1236{
1237	DPRINT(("storeblk: %d\n", l));
1238	putob(ob, BLKID);
1239	putob(ob, l);
1240}
1241
1242/*
1243 * Save filename on heap (with escaped chars).
1244 */
1245static usch *
1246unfname(void)
1247{
1248	usch *sb = stringbuf;
1249	const usch *bp = ifiles->fname;
1250
1251	savch('\"');
1252	for (; *bp; bp++) {
1253		if (*bp == '\"' || *bp == '\'' || *bp == '\\')
1254			savch('\\');
1255		savch(*bp);
1256	}
1257	savch('\"');
1258	*stringbuf = 0;
1259	return sb;
1260}
1261
1262/*
1263 * Version of fastnum that reads from a string and saves in ob.
1264 * We know that it is a number before calling this routine.
1265 */
1266static usch *
1267fstrnum(usch *s, struct iobuf *ob)
1268{
1269	if (*s == '.') {
1270		/* not digit, dot.  Next will be digit */
1271		putob(ob, *s++);
1272	}
1273	for (;;) {
1274		putob(ob, *s++);
1275		if ((spechr[*s] & C_EP)) {
1276			if (s[1] != '-' && s[1] != '+')
1277				break;
1278			putob(ob, *s++);
1279		} else if ((*s != '.') && ((spechr[*s] & C_ID) == 0))
1280			break;
1281	}
1282        return s;
1283}
1284
1285/*
1286 * get a string or character constant.
1287 * similar to faststr.
1288 */
1289static usch *
1290fstrstr(usch *s, struct iobuf *ob)
1291{
1292	int ch;
1293
1294	if (*s == 'L' || *s == 'U' || *s == 'u')
1295		putob(ob, *s++);
1296	if (*s == '8')
1297		putob(ob, *s++);
1298	ch = *s;
1299	putob(ob, *s++);
1300	while (*s != ch) {
1301		if (*s == '\\')
1302			putob(ob, *s++);
1303		putob(ob, *s++);
1304	}
1305	putob(ob, *s++);
1306	return s;
1307}
1308
1309/*
1310 * Save standard comments if found.
1311 */
1312static usch *
1313fcmnt(usch *s, struct iobuf *ob)
1314{
1315	putob(ob, *s++); /* / */
1316	putob(ob, *s++); /* * */
1317	for (;;s++) {
1318		putob(ob, *s);
1319		if (s[-1] == '*' && *s == '/')
1320			break;
1321	}
1322	return s+1;
1323}
1324
1325static int
1326getyp(usch *s)
1327{
1328
1329	if (ISID0(*s)) return IDENT;
1330	if ((*s == 'L' || *s == 'U' || *s == 'u') &&
1331	    (s[1] == '\'' || s[1] == '\"')) return STRING;
1332	if (s[0] == 'u' && s[1] == 'U' && s[2] == '\"') return STRING;
1333	if (s[0] == '\'' || s[0] == '\"') return STRING;
1334	if (spechr[*s] & C_DIGIT) return NUMBER;
1335	if (*s == '.' && (spechr[s[1]] & C_DIGIT)) return NUMBER;
1336	if (*s == '/' && (s[1] == '/' || s[1] == '*')) return CMNT;
1337	return *s;
1338
1339}
1340
1341/*
1342 * Check ib and print out the symbols there.
1343 * If expandable symbols found recurse and expand them.
1344 * If last identifier on the input list is expandable return it.
1345 * Expect ib to be zero-terminated.
1346 */
1347static struct symtab *
1348loopover(struct iobuf *ib)
1349{
1350	struct iobuf *xb, *xob;
1351	struct symtab *sp;
1352	usch *cp;
1353	int l, c, t;
1354
1355	ib->cptr = ib->buf; /* start from beginning */
1356#ifdef PCC_DEBUG
1357	if (dflag) {
1358		printf("loopover: '");
1359		prline(ib->cptr);
1360		printf("'\n");
1361	}
1362#endif
1363
1364	xb = getobuf();
1365	while ((c = *ib->cptr)) {
1366		switch (t = getyp(ib->cptr)) {
1367		case CMNT:
1368			xb->cptr = xb->buf;
1369			ib->cptr = fcmnt(ib->cptr, xb);
1370			*xb->cptr = 0;
1371			savstr(xb->buf);
1372			continue;
1373		case NUMBER:
1374			xb->cptr = xb->buf;
1375			ib->cptr = fstrnum(ib->cptr, xb);
1376			*xb->cptr = 0;
1377			savstr(xb->buf);
1378			continue;
1379		case STRING:
1380			xb->cptr = xb->buf;
1381			ib->cptr = fstrstr(ib->cptr,xb);
1382			*xb->cptr = 0;
1383			for (cp = xb->buf; *cp; cp++) {
1384				if (*cp <= BLKID) {
1385					if (*cp == BLKID)
1386						cp++;
1387					continue;
1388				}
1389				savch(*cp);
1390			}
1391			continue;
1392		case BLKID:
1393			l = ib->cptr[1];
1394			ib->cptr+=2;
1395			/* FALLTHROUGH */
1396		case IDENT:
1397			if (t != BLKID)
1398				l = 0;
1399			/*
1400			 * Tricky: if this is the last identifier
1401			 * in the expanded list, and it is defined
1402			 * as a function-like macro, then push it
1403			 * back on the input stream and let fastscan
1404			 * handle it as a new macro.
1405			 * BUT: if this macro is blocked then this
1406			 * should not be done.
1407			 */
1408			for (cp = ib->cptr; ISID(*ib->cptr); ib->cptr++)
1409				;
1410			if ((sp = lookup(cp, FIND)) == NULL) {
1411sstr:				for (; cp < ib->cptr; cp++)
1412					savch(*cp);
1413				continue;
1414			}
1415			if (expok(sp, l) == 0) {
1416				/* blocked */
1417				goto sstr;
1418			} else {
1419				if (*sp->value != OBJCT) {
1420					cp = ib->cptr;
1421					while (ISWS(*ib->cptr))
1422						ib->cptr++;
1423					if (*ib->cptr == 0) {
1424						bufree(xb);
1425						return sp;
1426					}
1427					ib->cptr = cp;
1428				}
1429newmac:				if ((xob = submac(sp, 1, ib, NULL)) == NULL) {
1430					savstr(sp->namep);
1431				} else {
1432					sp = loopover(xob);
1433					bufree(xob);
1434					if (sp != NULL)
1435						goto newmac;
1436				}
1437			}
1438			continue;
1439		default:
1440			savch(c);
1441		}
1442
1443		ib->cptr++;
1444	}
1445
1446	bufree(xb);
1447	DPRINT(("loopover return 0\n"));
1448	return 0;
1449}
1450
1451/*
1452 * Handle defined macro keywords found on input stream.
1453 * When finished print out the full expanded line.
1454 * Input here is from the lex buffer.
1455 * Return 1 if success, 0 otherwise.  fastscan restores stringbuf.
1456 * Scanned data is stored on heap.  Last scan prints out the buffer.
1457 */
1458int
1459kfind(struct symtab *sp)
1460{
1461	extern int inexpr;
1462	struct blocker *bl;
1463	struct iobuf *ib, *ob;
1464	const usch *argary[MAXARGS+1], *sbp;
1465	int c, n = 0;
1466
1467	blkidp = 1;
1468	sbp = stringbuf;
1469	DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
1470	switch (*sp->value) {
1471	case FILLOC:
1472		unfname();
1473		return 1;
1474
1475	case LINLOC:
1476		sheap("%d", ifiles->lineno);
1477		return 1;
1478
1479	case PRAGLOC:
1480		pragoper(NULL);
1481		return 1;
1482
1483	case DEFLOC:
1484	case OBJCT:
1485		bl = blkget(sp, NULL);
1486		ib = mkrobuf(sp->value+1);
1487		ob = getobuf();
1488		ob = exparg(1, ib, ob, bl);
1489		bufree(ib);
1490		break;
1491
1492	case CTRLOC:
1493		sheap("%d", counter++);
1494		return 1;
1495
1496	default:
1497		/* Search for '(' */
1498		while (ISWSNL(c = cinput()))
1499			if (c == '\n')
1500				n++;
1501		if (c != '(') {
1502			if (inexpr == 0)
1503				putstr(sp->namep);
1504			if (n == 0)
1505				putch(' ');
1506			else for (ifiles->lineno += n; n; n--)
1507				putch('\n');
1508			cunput(c);
1509			return 0; /* Failed */
1510		}
1511
1512		/* fetch arguments */
1513again:		if (readargs1(sp, argary))
1514			error("readargs");
1515
1516		bl = blkget(sp, NULL);
1517		ib = subarg(sp, argary, 1, bl);
1518		ob = getobuf();
1519		ob = exparg(1, ib, ob, bl);
1520		bufree(ib);
1521		break;
1522	}
1523
1524	/*
1525	 * Loop over stringbuf, output the data and remove remaining
1526	 * directives.  Start with extracting the last keyword (if any).
1527	 */
1528	putob(ob, 0); /* XXX needed? */
1529
1530	stringbuf = (usch *)sbp; /* XXX should check cleanup */
1531	if ((sp = loopover(ob))) {
1532		/* Search for '(' */
1533		while (ISWSNL(c = cinput()))
1534			if (c == '\n')
1535				n++;
1536		if (c == '(') {
1537			bufree(ob);
1538			goto again;
1539		}
1540		cunput(c);
1541		savstr(sp->namep);
1542	}
1543	bufree(ob);
1544
1545	for (ifiles->lineno += n; n; n--)
1546		savch('\n');
1547	savch(0);
1548	stringbuf = (usch *)sbp;
1549	if (nbufused)
1550		error("lost buffer");
1551	return 1;
1552}
1553
1554/*
1555 * Replace and push-back on input stream the eventual replaced macro.
1556 * The check for whether it can expand or not should already have been done.
1557 * Blocks for this identifier will be added via insblock() after expansion.
1558 * The same as kfind but read a string.
1559 */
1560struct iobuf *
1561submac(struct symtab *sp, int lvl, struct iobuf *ib, struct blocker *obl)
1562{
1563	struct blocker *bl;
1564	struct iobuf *ob;
1565	const usch *argary[MAXARGS+1];
1566	usch *cp, *pr;
1567
1568	DPRINT(("%d:submac: trying '%s'\n", lvl, sp->namep));
1569	switch (*sp->value) {
1570	case FILLOC:
1571		ob = strtobuf(unfname(), NULL);
1572		break;
1573	case LINLOC:
1574		ob = strtobuf(sheap("%d", ifiles->lineno), NULL);
1575		break;
1576	case PRAGLOC:
1577		pragoper(ib);
1578		ob = strtobuf((usch *)"", NULL);
1579		break;
1580	case OBJCT:
1581		bl = blkget(sp, obl);
1582		ib = mkrobuf(sp->value+1);
1583		ob = getobuf();
1584		DPRINT(("%d:submac: calling exparg\n", lvl));
1585		ob = exparg(lvl+1, ib, ob, bl);
1586		bufree(ib);
1587		DPRINT(("%d:submac: return exparg\n", lvl));
1588		break;
1589	case CTRLOC:
1590		ob = strtobuf(sheap("%d", counter++), NULL);
1591		break;
1592	default:
1593		cp = ib->cptr;
1594		while (ISWSNL(*ib->cptr))
1595			ib->cptr++;
1596		if (*ib->cptr != '(') {
1597			ib->cptr = cp;
1598			return 0;
1599		}
1600		cp = ib->cptr++;
1601		pr = stringbuf;
1602		if (readargs2(&ib->cptr, sp, argary)) {
1603			/* Bailed out in the middle of arg list */
1604			ib->cptr = cp; /* XXX */
1605			return 0;
1606		}
1607		bl = blkget(sp, obl);
1608		ib = subarg(sp, argary, lvl+1, bl);
1609		stringbuf = pr;
1610
1611		ob = getobuf();
1612		DPRINT(("%d:submac(: calling exparg\n", lvl));
1613		ob = exparg(lvl+1, ib, ob, bl);
1614		bufree(ib);
1615		DPRINT(("%d:submac(: return exparg\n", lvl));
1616		break;
1617	}
1618	putob(ob, 0);
1619	ob->cptr--;
1620
1621	return ob;
1622}
1623
1624static int
1625isdir(void)
1626{
1627	usch ch;
1628
1629	while ((ch = cinput()) == ' ' || ch == '\t')
1630		;
1631	if (ch == '#')
1632		return 1;
1633	cunput(ch);
1634	return 0;
1635}
1636
1637/*
1638 * Deal with directives inside a macro.
1639 * Doing so is really ugly but gcc allows it, so...
1640 */
1641static void
1642chkdir(void)
1643{
1644	usch ch;
1645
1646	for (;;) {
1647		if (isdir()) {
1648#ifndef GCC_COMPAT
1649			warning("conditionals inside macro arg list");
1650#endif
1651			ppdir();
1652		}
1653		if (flslvl == 0)
1654			return;
1655		while ((ch = cinput()) != '\n')
1656			;
1657		ifiles->lineno++;
1658		putch('\n');
1659	}
1660}
1661
1662static int
1663ra1_wsnl(int sp)
1664{
1665	int c;
1666
1667	while (ISWSNL(c = cinput())) {
1668		if (c == '\n') {
1669			putch('\n');
1670			chkdir();
1671			ifiles->lineno++;
1672			if (sp) savch(' ');
1673		}
1674	}
1675	return c;
1676}
1677
1678/*
1679 * Read arguments and put in argument array.
1680 * If EOF is encountered return 1, otherwise 0.
1681 */
1682int
1683readargs1(struct symtab *sp, const usch **args)
1684{
1685	const usch *vp = sp->value;
1686	int c, i, plev, narg, ellips = 0;
1687
1688	DPRINT(("readargs1\n"));
1689	narg = *vp++;
1690	if (narg == VARG) {
1691		narg = *vp++;
1692		ellips = 1;
1693	}
1694#ifdef PCC_DEBUG
1695	if (dflag > 1) {
1696		printf("narg %d varg %d: ", narg, ellips);
1697		prrep(vp);
1698		printf("\n");
1699	}
1700#endif
1701
1702	/*
1703	 * read arguments and store them on heap.
1704	 */
1705	c = '(';
1706	for (i = 0; i < narg && c != ')'; i++) {
1707		args[i] = stringbuf;
1708		plev = 0;
1709
1710		c = ra1_wsnl(0);
1711		for (;;) {
1712			if (plev == 0 && (c == ')' || c == ','))
1713				break;
1714			if (c == '(') plev++;
1715			if (c == ')') plev--;
1716			if (c == 0)
1717				error("eof in macro");
1718			else if (c == '/') Ccmnt(savch);
1719			else if (c == '\"' || c == '\'') faststr(c, savch);
1720			else if (ISID0(c)) {
1721				usch *bp = stringbuf;
1722				do {
1723					savch(c);
1724				} while ((spechr[c = cinput()] & C_ID));
1725				if ((sp = lookup(bp, FIND)) != NULL) {
1726					if (sp == linloc) {
1727						stringbuf = bp;
1728						sheap("%d", ifiles->lineno);
1729					} else if (sp == ctrloc) {
1730						stringbuf = bp;
1731						sheap("%d", counter++);
1732					}
1733				}
1734				cunput(c);
1735			} else
1736				savch(c);
1737			if ((c = cinput()) == '\n') {
1738				chkdir();
1739				ifiles->lineno++, putch(c), c = ' ';
1740			}
1741		}
1742
1743		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1744			stringbuf--;
1745		savch('\0');
1746#ifdef PCC_DEBUG
1747		if (dflag) {
1748			printf("readargs: save arg %d '", i);
1749			prline(args[i]);
1750			printf("'\n");
1751		}
1752#endif
1753	}
1754
1755	/* Handle varargs readin */
1756	if (ellips)
1757		args[i] = (const usch *)"";
1758	if (ellips && c != ')') {
1759		args[i] = stringbuf;
1760		plev = 0;
1761		c = ra1_wsnl(0);
1762		for (;;) {
1763			if (plev == 0 && c == ')')
1764				break;
1765			if (c == '(') plev++;
1766			if (c == ')') plev--;
1767			if (c == '\"' || c == '\'') faststr(c, savch);
1768			else
1769				savch(c);
1770			if ((c = cinput()) == '\n')
1771				ifiles->lineno++, c = ' ';
1772		}
1773		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1774			stringbuf--;
1775		savch('\0');
1776#ifdef PCC_DEBUG
1777		if (dflag) {
1778			printf("readargs: vararg arg %d '", i);
1779			prline(args[i]);
1780			printf("'\n");
1781		}
1782#endif
1783
1784	}
1785	if (narg == 0 && ellips == 0)
1786		c = ra1_wsnl(0);
1787
1788	if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1789		error("wrong arg count");
1790	return 0;
1791}
1792
1793static usch *raptr;
1794static int
1795raread(void)
1796{
1797	int rv;
1798
1799	if (raptr) {
1800		if ((rv = *raptr))
1801			raptr++;
1802	} else
1803		rv = cinput();
1804	return rv;
1805}
1806
1807
1808/*
1809 * Read arguments and put in argument array.
1810 * If EOF is encountered return 1, otherwise 0.
1811 */
1812int
1813readargs2(usch **inp, struct symtab *sp, const usch **args)
1814{
1815	const usch *vp = sp->value;
1816	usch *bp;
1817	int c, i, plev, narg, ellips = 0;
1818
1819	DPRINT(("readargs2 %s '", sp->namep));
1820#ifdef PCC_DEBUG
1821	if (dflag && inp) {
1822		prline(*inp);
1823		printf("'\n");
1824	}
1825#endif
1826	raptr = inp ? *inp : 0;
1827	narg = *vp++;
1828	if (narg == VARG) {
1829		narg = *vp++;
1830		ellips = 1;
1831	}
1832#ifdef PCC_DEBUG
1833	if (dflag > 1) {
1834		prrep(vp);
1835		printf("\n");
1836	}
1837#endif
1838
1839
1840	/*
1841	 * read arguments and store them on heap.
1842	 */
1843	c = '(';
1844	for (i = 0; i < narg && c != ')'; i++) {
1845		args[i] = stringbuf;
1846		plev = 0;
1847
1848		while ((c = raread()) == ' ' || c == '\t')
1849			;
1850		for (;;) {
1851			if (plev == 0 && (c == ')' || c == ','))
1852				break;
1853			if (c == '(') plev++;
1854			if (c == ')') plev--;
1855			if (c == 0) {
1856				if (raptr) {
1857					*inp = raptr;
1858					raptr = 0;
1859				} else
1860					error("eof in macro");
1861			} else if (c == BLKID) {
1862				savch(c), savch(raread());
1863			} else if (c == '/') {
1864				if ((c = raread()) == '*')
1865					error("FIXME ccmnt");
1866				savch('/');
1867				continue;
1868			} else if (c == '\"' || c == '\'') {
1869				if (raptr) {
1870					struct iobuf *xob = getobuf();
1871					raptr = fstrstr(raptr-1, xob);
1872					*xob->cptr = 0;
1873					savstr(xob->buf);
1874					bufree(xob);
1875				} else
1876					faststr(c, savch);
1877			} else if (ISID0(c)) {
1878				bp = stringbuf;
1879				do {
1880					savch(c);
1881				} while (ISID(c = raread()));
1882				*stringbuf = 0;
1883				if ((sp = lookup(bp, FIND)) && (sp == linloc)) {
1884					stringbuf = bp;
1885					sheap("%d", ifiles->lineno);
1886				}
1887				continue;
1888			} else
1889				savch(c);
1890			c = raread();
1891		}
1892
1893		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1894			stringbuf--;
1895		savch('\0');
1896#ifdef PCC_DEBUG
1897		if (dflag) {
1898			printf("readargs2: save arg %d '", i);
1899			prline(args[i]);
1900			printf("'\n");
1901		}
1902#endif
1903	}
1904
1905	/* Handle varargs readin */
1906	if (ellips)
1907		args[i] = (const usch *)"";
1908	if (ellips && c != ')') {
1909		args[i] = stringbuf;
1910		plev = 0;
1911		while ((c = raread()) == ' ' || c == '\t')
1912			;
1913		for (;;) {
1914			if (plev == 0 && c == ')')
1915				break;
1916			if (c == '(') plev++;
1917			if (c == ')') plev--;
1918			if (c == '\"' || c == '\'') {
1919				if (raptr) {
1920					struct iobuf *xob = getobuf();
1921					raptr = fstrstr(raptr-1, xob);
1922					*xob->cptr = 0;
1923					savstr(xob->buf);
1924					bufree(xob);
1925				} else
1926					faststr(c, savch);
1927			} else
1928				savch(c);
1929			c = raread();
1930		}
1931		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1932			stringbuf--;
1933		savch('\0');
1934
1935	}
1936	if (narg == 0 && ellips == 0) {
1937		while ((c = raread()) == ' ' || c == '\t')
1938			;
1939	}
1940
1941	if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1942		error("wrong arg count");
1943	if (raptr)
1944		*inp = raptr;
1945	return 0;
1946}
1947
1948/*
1949 * expand a function-like macro.
1950 * vp points to end of replacement-list
1951 * reads function arguments from input stream.
1952 * result is pushed-back for more scanning.
1953 */
1954struct iobuf *
1955subarg(struct symtab *nl, const usch **args, int lvl, struct blocker *bl)
1956{
1957	struct blocker *w;
1958	struct iobuf *ob, *cb, *nb;
1959	int narg, instr, snuff;
1960	const usch *sp, *bp, *ap, *vp, *tp;
1961
1962	DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
1963	ob = getobuf();
1964	vp = nl->value;
1965	narg = *vp++;
1966	if (narg == VARG)
1967		narg = *vp++;
1968
1969	sp = vp;
1970	instr = snuff = 0;
1971#ifdef PCC_DEBUG
1972	if (dflag>1) {
1973		printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
1974		prrep(vp);
1975		printf("' ");
1976		for (w = bl; w; w = w->next)
1977			printf("%s ", w->sp->namep);
1978		printf("\n");
1979	}
1980#endif
1981
1982	/*
1983	 * walk forward over replacement-list while replacing
1984	 * arguments.  Arguments are macro-expanded if required.
1985	 */
1986	while (*sp) {
1987		if (*sp == SNUFF)
1988			putob(ob, '\"'), snuff ^= 1;
1989		else if (*sp == CONC)
1990			;
1991		else if (*sp == WARN) {
1992
1993			if (sp[1] == VARG) {
1994				bp = ap = args[narg];
1995				sp++;
1996#ifdef GCC_COMPAT
1997			} else if (sp[1] == GCCARG) {
1998				/* XXX remove last , not add 0 */
1999				ap = args[narg];
2000				if (ap[0] == 0)
2001					ap = (const usch *)"0";
2002				bp = ap;
2003				sp++;
2004#endif
2005			} else
2006				bp = ap = args[(int)*++sp];
2007#ifdef PCC_DEBUG
2008			if (dflag>1){
2009				printf("%d:subarg GOTwarn; arglist '", lvl);
2010				prline(bp);
2011				printf("'\n");
2012			}
2013#endif
2014			if (sp[-2] != CONC && !snuff && sp[1] != CONC) {
2015				/*
2016				 * Expand an argument; 6.10.3.1:
2017				 * "A parameter in the replacement list,
2018				 *  is replaced by the corresponding argument
2019				 *  after all macros contained therein have
2020				 *  been expanded.".
2021				 */
2022				w = bl ? bl->next : NULL;
2023				cb = mkrobuf(bp);
2024				nb = getobuf();
2025				DPRINT(("%d:subarg: calling exparg\n", lvl));
2026				nb = exparg(lvl+1, cb, nb, w);
2027				DPRINT(("%d:subarg: return exparg\n", lvl));
2028				bufree(cb);
2029				strtobuf(nb->buf, ob);
2030				bufree(nb);
2031			} else {
2032				while (*bp) {
2033					if (snuff && !instr && ISWS(*bp)) {
2034						while (ISWS(*bp))
2035							bp++;
2036						putob(ob, ' ');
2037					}
2038
2039					if (snuff &&
2040					    (*bp == '\'' || *bp == '"')) {
2041						instr ^= 1;
2042						for (tp = bp - 1; *tp == '\\'; tp--)
2043							instr ^= 1;
2044						if (*bp == '"')
2045							putob(ob, '\\');
2046					}
2047					if (snuff && instr && *bp == '\\')
2048						putob(ob, '\\');
2049					putob(ob, *bp);
2050					bp++;
2051				}
2052			}
2053		} else if (ISID0(*sp)) {
2054			if (lookup(sp, FIND))
2055				storeblk(blkix(bl), ob);
2056			while (ISID(*sp))
2057				putob(ob, *sp++);
2058			sp--;
2059		} else
2060			putob(ob, *sp);
2061		sp++;
2062	}
2063	putob(ob, 0);
2064	ob->cptr = ob->buf;
2065	DPRINT(("%d:subarg retline %s\n", lvl, ob->buf));
2066	return ob;
2067}
2068
2069/*
2070 * Do a (correct) expansion of a WARN-terminated buffer of tokens.
2071 * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
2072 * Expansion blocking is not altered here unless when tokens are
2073 * concatenated, in which case they are removed.
2074 */
2075struct iobuf *
2076exparg(int lvl, struct iobuf *ib, struct iobuf *ob, struct blocker *bl)
2077{
2078	extern int inexpr;
2079	struct iobuf *nob;
2080	struct symtab *nl;
2081	int c, m;
2082	usch *cp, *bp, *sbp;
2083
2084	DPRINT(("%d:exparg: entry ib %s\n", lvl, ib->cptr));
2085#ifdef PCC_DEBUG
2086	if (dflag > 1) {
2087		printf("exparg entry: full ");
2088		prline(ib->cptr);
2089		printf("\n");
2090	}
2091#endif
2092
2093	while ((c = getyp(ib->cptr)) != 0) {
2094		ib->cptr++;
2095
2096		switch (c) {
2097
2098		case CMNT:
2099			ib->cptr = fcmnt(ib->cptr-1, ob);
2100			break;
2101		case NUMBER:
2102			ib->cptr = fstrnum(ib->cptr-1, ob);
2103			break;
2104		case STRING:
2105			ib->cptr = fstrstr(ib->cptr-1, ob);
2106			break;
2107		case BLKID:
2108			m = *ib->cptr++;
2109			ib->cptr++;
2110			/* FALLTHROUGH */
2111		case IDENT:
2112			if (c != BLKID)
2113				m = 0;
2114			for (cp = ib->cptr-1; ISID(*cp); cp++)
2115				;
2116#ifdef PCC_DEBUG
2117if (dflag) { printf("!! ident "); prline(ib->cptr-1); printf("\n"); }
2118#endif
2119			sbp = stringbuf;
2120			if (*cp == BLKID) {
2121				/* concatenation */
2122				bp = stringbuf;
2123				for (cp = ib->cptr-1;
2124				    ISID(*cp) || *cp == BLKID; cp++) {
2125					if (*cp == BLKID) {
2126						/* XXX add to block list */
2127						cp++;
2128					} else
2129						savch(*cp);
2130				}
2131				ib->cptr = cp;
2132				cp = stringbuf;
2133				savch(0);
2134			} else {
2135				bp = ib->cptr-1;
2136				ib->cptr = cp;
2137			}
2138#ifdef PCC_DEBUG
2139if (dflag) { printf("!! ident2 "); prline(bp); printf("\n"); }
2140#endif
2141			if ((nl = lookup(bp, FIND)) == NULL) {
2142sstr:				for (; bp < cp; bp++)
2143					putob(ob, *bp);
2144				stringbuf = sbp;
2145				break;
2146			} else if (inexpr && *nl->value == DEFLOC) {
2147				int gotlp = 0;
2148				while (ISWS(*ib->cptr)) ib->cptr++;
2149				if (*ib->cptr == '(')
2150					gotlp++, ib->cptr++;
2151				while (ISWS(*ib->cptr)) ib->cptr++;
2152				if (!ISID0(*ib->cptr))
2153					error("bad defined");
2154				putob(ob, lookup(ib->cptr, FIND) ? '1' : '0');
2155				while (ISID(*ib->cptr)) ib->cptr++;
2156				while (ISWS(*ib->cptr)) ib->cptr++;
2157				if (gotlp && *ib->cptr != ')')
2158					error("bad defined");
2159				ib->cptr++;
2160				break;
2161			}
2162			stringbuf = sbp;
2163			if (expokb(nl, bl) && expok(nl, m)) {
2164				if ((nob = submac(nl, lvl+1, ib, bl))) {
2165					if (nob->buf[0] == '-' ||
2166					    nob->buf[0] == '+')
2167						putob(ob, ' ');
2168					strtobuf(nob->buf, ob);
2169					if (ob->cptr[-1] == '-' ||
2170					    ob->cptr[-1] == '+')
2171						putob(ob, ' ');
2172					bufree(nob);
2173				} else {
2174					goto sblk;
2175				}
2176			} else {
2177				/* blocked */
2178sblk:				storeblk(blkix(mergeadd(bl, m)), ob);
2179				goto sstr;
2180			}
2181			break;
2182
2183		default:
2184			putob(ob, c);
2185			break;
2186		}
2187	}
2188	putob(ob, 0);
2189	ob->cptr--;
2190	DPRINT(("%d:exparg return: ob %s\n", lvl, ob->buf));
2191#ifdef PCC_DEBUG
2192	if (dflag > 1) {
2193		printf("%d:exparg: full ", lvl);
2194		prline(ob->buf);
2195		printf("\n");
2196	}
2197#endif
2198	return ob;
2199}
2200
2201#ifdef PCC_DEBUG
2202
2203static void
2204prrep(const usch *s)
2205{
2206	while (*s) {
2207		switch (*s) {
2208		case WARN:
2209			if (s[1] == VARG) printf("<VARG>");
2210			else if (s[1] == GCCARG) printf("<GCCARG>");
2211			else printf("<ARG(%d)>", s[1]);
2212			s++;
2213			break;
2214		case CONC: printf("<CONC>"); break;
2215		case SNUFF: printf("<SNUFF>"); break;
2216		case BLKID: printf("<BLKID(%d)>",s[1]); s++; break;
2217		default: printf("%c", *s); break;
2218		}
2219		s++;
2220	}
2221}
2222
2223static void
2224prline(const usch *s)
2225{
2226	while (*s) {
2227		switch (*s) {
2228		case BLKID: printf("<BLKID(%d)>", *++s); break;
2229		case WARN: printf("<WARN>"); break;
2230		case CONC: printf("<CONC>"); break;
2231		case SNUFF: printf("<SNUFF>"); break;
2232		case '\n': printf("<NL>"); break;
2233		default:
2234			if (*s > 0x7f)
2235				printf("<0x%x>", *s);
2236			else
2237				printf("%c", *s);
2238			break;
2239		}
2240		s++;
2241	}
2242}
2243#endif
2244
2245usch *
2246savstr(const usch *str)
2247{
2248	usch *rv = stringbuf;
2249
2250	do {
2251		if (stringbuf >= &sbf[SBSIZE])
2252			error("out of macro space!");
2253	} while ((*stringbuf++ = *str++));
2254	stringbuf--;
2255	return rv;
2256}
2257
2258void
2259putch(int ch)
2260{
2261	if (Mflag)
2262		return;
2263	fputc(ch, stdout);
2264}
2265
2266void
2267putstr(const usch *s)
2268{
2269	for (; *s; s++) {
2270		if (Mflag == 0)
2271			fputc(*s, stdout);
2272	}
2273}
2274
2275/*
2276 * convert a number to an ascii string. Store it on the heap.
2277 */
2278static void
2279num2str(int num)
2280{
2281	static usch buf[12];
2282	usch *b = buf;
2283	int m = 0;
2284
2285	if (num < 0)
2286		num = -num, m = 1;
2287	do {
2288		*b++ = (usch)(num % 10 + '0');
2289		num /= 10;
2290	} while (num);
2291	if (m)
2292		*b++ = '-';
2293	while (b > buf)
2294		savch(*--b);
2295}
2296
2297/*
2298 * similar to sprintf, but only handles %c, %s and %d.
2299 * saves result on heap.
2300 */
2301static void
2302vsheap(const char *fmt, va_list ap)
2303{
2304	for (; *fmt; fmt++) {
2305		if (*fmt == '%') {
2306			fmt++;
2307			switch (*fmt) {
2308			case 's':
2309				savstr(va_arg(ap, usch *));
2310				break;
2311			case 'd':
2312				num2str(va_arg(ap, int));
2313				break;
2314			case 'c':
2315				savch(va_arg(ap, int));
2316				break;
2317			default:
2318				error("bad sheap");
2319			}
2320		} else
2321			savch(*fmt);
2322	}
2323	*stringbuf = 0;
2324}
2325
2326usch *
2327sheap(const char *fmt, ...)
2328{
2329	va_list ap;
2330	usch *op = stringbuf;
2331
2332	va_start(ap, fmt);
2333	vsheap(fmt, ap);
2334	va_end(ap);
2335
2336	return op;
2337}
2338
2339static void
2340usage(void)
2341{
2342	error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
2343}
2344
2345#ifdef notyet
2346/*
2347 * Symbol table stuff.
2348 * The data structure used is a patricia tree implementation using only
2349 * bytes to store offsets.
2350 * The information stored is (lower address to higher):
2351 *
2352 *	unsigned char bitno[2]; bit number in the string
2353 *	unsigned char left[3];	offset from base to left element
2354 *	unsigned char right[3];	offset from base to right element
2355 */
2356#endif
2357
2358/*
2359 * This patricia implementation is more-or-less the same as
2360 * used in ccom for string matching.
2361 */
2362struct tree {
2363	int bitno;
2364	struct tree *lr[2];
2365};
2366
2367#define BITNO(x)		((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
2368#define LEFT_IS_LEAF		0x80000000
2369#define RIGHT_IS_LEAF		0x40000000
2370#define IS_LEFT_LEAF(x)		(((x) & LEFT_IS_LEAF) != 0)
2371#define IS_RIGHT_LEAF(x)	(((x) & RIGHT_IS_LEAF) != 0)
2372#define P_BIT(key, bit)		(key[bit >> 3] >> (bit & 7)) & 1
2373#define CHECKBITS		8
2374
2375static struct tree *sympole;
2376static int numsyms;
2377
2378static struct tree *
2379gtree(void)
2380{
2381	static int ntrees;
2382	static struct tree *tp;
2383
2384	if (ntrees == 0) {
2385		tp = xmalloc(BUFSIZ);
2386		ntrees = BUFSIZ/sizeof(*tp);
2387	}
2388	return &tp[--ntrees];
2389}
2390
2391/*
2392 * Allocate a symtab struct and store the string.
2393 */
2394static struct symtab *
2395getsymtab(const usch *str)
2396{
2397	static int nsyms;
2398	static struct symtab *spp;
2399	struct symtab *sp;
2400
2401	if (nsyms == 0) {
2402		spp = xmalloc(BUFSIZ);
2403		nsyms = BUFSIZ/sizeof(*sp);
2404	}
2405	sp = &spp[--nsyms];
2406
2407	sp->namep = str;
2408	sp->value = NULL;
2409	sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
2410	sp->line = ifiles ? ifiles->lineno : 0;
2411	return sp;
2412}
2413
2414/*
2415 * Do symbol lookup in a patricia tree.
2416 * Only do full string matching, no pointer optimisations.
2417 */
2418struct symtab *
2419lookup(const usch *key, int enterf)
2420{
2421	struct symtab *sp;
2422	struct tree *w, *new, *last;
2423	int len, cix, bit, fbit, svbit, ix, bitno;
2424	const usch *k, *m;
2425
2426	/* Count full string length */
2427	for (k = key, len = 0; ISID(*k) & C_ID; k++, len++)
2428		;
2429
2430	switch (numsyms) {
2431	case 0: /* no symbols yet */
2432		if (enterf != ENTER)
2433			return NULL;
2434		sympole = (struct tree *)getsymtab(key);
2435		numsyms++;
2436		return (struct symtab *)sympole;
2437
2438	case 1:
2439		w = sympole;
2440		svbit = 0; /* XXX gcc */
2441		break;
2442
2443	default:
2444		w = sympole;
2445		bitno = len * CHECKBITS;
2446		for (;;) {
2447			bit = BITNO(w->bitno);
2448			fbit = bit >= bitno ? 0 : P_BIT(key, bit);
2449			svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
2450			    IS_LEFT_LEAF(w->bitno);
2451			w = w->lr[fbit];
2452			if (svbit)
2453				break;
2454		}
2455	}
2456
2457	sp = (struct symtab *)w;
2458
2459	m = sp->namep;
2460	k = key;
2461
2462	/* Check for correct string and return */
2463	for (cix = 0; *m && ISID(*k) && *m == *k; m++, k++, cix += CHECKBITS)
2464		;
2465	if (*m == 0 && ISID(*k) == 0) {
2466		if (enterf != ENTER && sp->value == NULL)
2467			return NULL;
2468		return sp;
2469	}
2470
2471	if (enterf != ENTER)
2472		return NULL; /* no string found and do not enter */
2473
2474	ix = *m ^ *k;
2475	while ((ix & 1) == 0)
2476		ix >>= 1, cix++;
2477
2478	/* Create new node */
2479	new = gtree();
2480	bit = P_BIT(key, cix);
2481	new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
2482	new->lr[bit] = (struct tree *)getsymtab(key);
2483
2484	if (numsyms++ == 1) {
2485		new->lr[!bit] = sympole;
2486		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
2487		sympole = new;
2488		return (struct symtab *)new->lr[bit];
2489	}
2490
2491	w = sympole;
2492	last = NULL;
2493	for (;;) {
2494		fbit = w->bitno;
2495		bitno = BITNO(w->bitno);
2496		if (bitno == cix)
2497			error("bitno == cix");
2498		if (bitno > cix)
2499			break;
2500		svbit = P_BIT(key, bitno);
2501		last = w;
2502		w = w->lr[svbit];
2503		if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
2504			break;
2505	}
2506
2507	new->lr[!bit] = w;
2508	if (last == NULL) {
2509		sympole = new;
2510	} else {
2511		last->lr[svbit] = new;
2512		last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
2513	}
2514	if (bitno < cix)
2515		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
2516	return (struct symtab *)new->lr[bit];
2517}
2518
2519static void *
2520xmalloc(int sz)
2521{
2522	usch *rv;
2523
2524	if ((rv = (void *)malloc(sz)) == NULL)
2525		error("xmalloc: out of mem");
2526	return rv;
2527}
2528
2529static void *
2530xrealloc(void *p, int sz)
2531{
2532	usch *rv;
2533
2534	if ((rv = (void *)realloc(p, sz)) == NULL)
2535		error("xrealloc: out of mem");
2536	return rv;
2537}
2538
2539static usch *
2540xstrdup(const usch *str)
2541{
2542	usch *rv;
2543
2544	if ((rv = (usch *)strdup((const char *)str)) == NULL)
2545		error("xstrdup: out of mem");
2546	return rv;
2547}
2548