xref: /netbsd/external/bsd/pcc/dist/pcc/cc/cpp/cpp.c (revision c555ae24)
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 
66 static usch	sbf[SBSIZE];
67 static int	counter;
68 /* C command */
69 
70 int tflag;	/* traditional cpp syntax */
71 #ifdef PCC_DEBUG
72 int dflag;	/* debug printouts */
73 //static void imp(const char *);
74 static void prline(const usch *s);
75 static 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 
85 int Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag;
86 char *Mfile, *MPfile;
87 struct initar *initar;
88 char *Mxfile;
89 int warnings, Mxlen;
90 FILE *of;
91 
92 /* include dirs */
93 struct incs {
94 	struct incs *next;
95 	usch *dir;
96 	dev_t dev;
97 	ino_t ino;
98 } *incdir[2];
99 
100 static struct symtab *filloc;
101 static struct symtab *linloc;
102 static struct symtab *pragloc;
103 static struct symtab *defloc;
104 static struct symtab *ctrloc;
105 int	trulvl;
106 int	flslvl;
107 int	elflvl;
108 int	elslvl;
109 usch *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  */
141 struct blocker {
142 	struct blocker *next;
143 	struct symtab *sp;
144 };
145 struct blocker *blkidx[RECMAX];
146 int blkidp;
147 
148 static int readargs2(usch **, struct symtab *sp, const usch **args);
149 static int readargs1(struct symtab *sp, const usch **args);
150 static struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *);
151 static struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *);
152 static void usage(void);
153 static usch *xstrdup(const usch *str);
154 static void addidir(char *idir, struct incs **ww);
155 static void vsheap(const char *, va_list);
156 static int skipws(struct iobuf *ib);
157 static int getyp(usch *s);
158 static void *xrealloc(void *p, int sz);
159 static void *xmalloc(int sz);
160 
161 usch locs[] =
162 	{ FILLOC, LINLOC, PRAGLOC, DEFLOC,
163 	    'd','e','f','i','n','e','d',0, CTRLOC };
164 
165 int
main(int argc,char ** argv)166 main(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  */
351 static void
putob(struct iobuf * ob,int ch)352 putob(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 
364 static int nbufused;
365 /*
366  * Write a character to an out buffer.
367  */
368 static struct iobuf *
getobuf(void)369 getobuf(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  */
383 static struct iobuf *
mkrobuf(const usch * s)384 mkrobuf(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  */
399 static struct iobuf *
strtobuf(usch * str,struct iobuf * iob)400 strtobuf(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 
412 static void
bufree(struct iobuf * iob)413 bufree(struct iobuf *iob)
414 {
415 	nbufused--;
416 	if (iob->ro == 0)
417 		free(iob->buf);
418 	free(iob);
419 }
420 
421 static void
addidir(char * idir,struct incs ** ww)422 addidir(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 
456 void
line(void)457 line(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 
518 bad:	error("bad #line");
519 }
520 
521 #ifdef MACHOABI
522 
523 /*
524  * Search for framework header file.
525  * Return 1 on success.
526  */
527 
528 static int
fsrch_macos_framework(const usch * fn,const usch * dir)529 fsrch_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  */
585 static int
fsrch(const usch * fn,int idx,struct incs * w)586 fsrch(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 
632 static void
prem(void)633 prem(void)
634 {
635 	error("premature EOF");
636 }
637 
638 static struct iobuf *
incfn(void)639 incfn(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  */
685 void
include(void)686 include(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 
725 okret:
726 	if (nm)
727 		free(nm);
728 	prtline(1);
729 }
730 
731 void
include_next(void)732 include_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  */
754 static int
cmprepl(const usch * o,const usch * n)755 cmprepl(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 
779 static int
isell(void)780 isell(void)
781 {
782 	if (cinput() != '.' || cinput() != '.')
783 		return 0;
784 	return 1;
785 }
786 
787 static int
skipwscmnt(struct iobuf * ib)788 skipwscmnt(struct iobuf *ib)
789 {
790 	/* XXX comment */
791 	return skipws(ib);
792 }
793 
794 static int
findarg(usch * s,usch ** args,int narg)795 findarg(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  */
810 void
define(void)811 define(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 
1045 bad:	error("bad #define");
1046 }
1047 
1048 void
warning(const char * fmt,...)1049 warning(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 
1065 void
error(const char * fmt,...)1066 error(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  */
1084 void
savch(int c)1085 savch(int c)
1086 {
1087 	if (stringbuf >= &sbf[SBSIZE])
1088 		error("out of macro space!");
1089 
1090 	*stringbuf++ = (usch)c;
1091 }
1092 
1093 static int
pragwin(struct iobuf * ib)1094 pragwin(struct iobuf *ib)
1095 {
1096 	return ib ? *ib->cptr++ : cinput();
1097 }
1098 
1099 static int
skipws(struct iobuf * ib)1100 skipws(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  */
1113 static void
pragoper(struct iobuf * ib)1114 pragoper(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 
1143 err:	error("_Pragma() syntax error");
1144 }
1145 
1146 static int
expok(struct symtab * sp,int l)1147 expok(struct symtab *sp, int l)
1148 {
1149 	struct blocker *w;
1150 
1151 	if (l == 0)
1152 		return 1;
1153 #ifdef PCC_DEBUG
1154 if (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 
1165 static int
expokb(struct symtab * sp,struct blocker * bl)1166 expokb(struct symtab *sp, struct blocker *bl)
1167 {
1168 	struct blocker *w;
1169 
1170 	if (bl == 0)
1171 		return 1;
1172 #ifdef PCC_DEBUG
1173 if (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 
1184 static struct blocker *
blkget(struct symtab * sp,struct blocker * obl)1185 blkget(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 
1194 static int
blkix(struct blocker * obl)1195 blkix(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 
1205 static struct blocker *
mergeadd(struct blocker * bl,int m)1206 mergeadd(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 
1234 static void
storeblk(int l,struct iobuf * ob)1235 storeblk(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  */
1245 static usch *
unfname(void)1246 unfname(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  */
1266 static usch *
fstrnum(usch * s,struct iobuf * ob)1267 fstrnum(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  */
1289 static usch *
fstrstr(usch * s,struct iobuf * ob)1290 fstrstr(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  */
1312 static usch *
fcmnt(usch * s,struct iobuf * ob)1313 fcmnt(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 
1325 static int
getyp(usch * s)1326 getyp(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  */
1347 static struct symtab *
loopover(struct iobuf * ib)1348 loopover(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) {
1411 sstr:				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 				}
1429 newmac:				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  */
1458 int
kfind(struct symtab * sp)1459 kfind(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 */
1513 again:		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  */
1560 struct iobuf *
submac(struct symtab * sp,int lvl,struct iobuf * ib,struct blocker * obl)1561 submac(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 
1624 static int
isdir(void)1625 isdir(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  */
1641 static void
chkdir(void)1642 chkdir(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 
1662 static int
ra1_wsnl(int sp)1663 ra1_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  */
1682 int
readargs1(struct symtab * sp,const usch ** args)1683 readargs1(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 
1793 static usch *raptr;
1794 static int
raread(void)1795 raread(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  */
1812 int
readargs2(usch ** inp,struct symtab * sp,const usch ** args)1813 readargs2(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  */
1954 struct iobuf *
subarg(struct symtab * nl,const usch ** args,int lvl,struct blocker * bl)1955 subarg(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  */
2075 struct iobuf *
exparg(int lvl,struct iobuf * ib,struct iobuf * ob,struct blocker * bl)2076 exparg(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
2117 if (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
2139 if (dflag) { printf("!! ident2 "); prline(bp); printf("\n"); }
2140 #endif
2141 			if ((nl = lookup(bp, FIND)) == NULL) {
2142 sstr:				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 */
2178 sblk:				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 
2203 static void
prrep(const usch * s)2204 prrep(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 
2223 static void
prline(const usch * s)2224 prline(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 
2245 usch *
savstr(const usch * str)2246 savstr(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 
2258 void
putch(int ch)2259 putch(int ch)
2260 {
2261 	if (Mflag)
2262 		return;
2263 	fputc(ch, stdout);
2264 }
2265 
2266 void
putstr(const usch * s)2267 putstr(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  */
2278 static void
num2str(int num)2279 num2str(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  */
2301 static void
vsheap(const char * fmt,va_list ap)2302 vsheap(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 
2326 usch *
sheap(const char * fmt,...)2327 sheap(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 
2339 static void
usage(void)2340 usage(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  */
2362 struct 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 
2375 static struct tree *sympole;
2376 static int numsyms;
2377 
2378 static struct tree *
gtree(void)2379 gtree(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  */
2394 static struct symtab *
getsymtab(const usch * str)2395 getsymtab(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  */
2418 struct symtab *
lookup(const usch * key,int enterf)2419 lookup(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 
2519 static void *
xmalloc(int sz)2520 xmalloc(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 
2529 static void *
xrealloc(void * p,int sz)2530 xrealloc(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 
2539 static usch *
xstrdup(const usch * str)2540 xstrdup(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