1139804Simp/*	Id: cpp.c,v 1.252 2016/02/06 09:39:21 ragge Exp 	*/
2185435Sbz/*	$NetBSD: cpp.c,v 1.4 2016/02/09 20:37:32 plunky Exp $	*/
3185435Sbz
4191673Sjamie/*
5185435Sbz * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
6190466Sjamie * All rights reserved.
7185404Sbz *
8185404Sbz * Redistribution and use in source and binary forms, with or without
9185404Sbz * modification, are permitted provided that the following conditions
10185404Sbz * are met:
11185404Sbz * 1. Redistributions of source code must retain the above copyright
12185404Sbz *    notice, this list of conditions and the following disclaimer.
13185404Sbz * 2. Redistributions in binary form must reproduce the above copyright
14185404Sbz *    notice, this list of conditions and the following disclaimer in the
15185404Sbz *    documentation and/or other materials provided with the distribution.
16185404Sbz *
17185404Sbz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18185404Sbz * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19185404Sbz * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20185404Sbz * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21185404Sbz * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22185404Sbz * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23185404Sbz * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24185404Sbz * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25185404Sbz * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26185404Sbz * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2746197Sphk */
2846155Sphk
29116182Sobrien/*
30116182Sobrien * The C preprocessor.
31116182Sobrien * This code originates from the V6 preprocessor with some additions
32193066Sjamie * from V7 cpp, and at last ansi/c99 support.
33185435Sbz *
34185435Sbz * 	- kfind() expands the input buffer onto XXX
35185435Sbz *	- exparg() expand one buffer into another.
36131177Spjd *		Recurses into submac() for fun-like macros.
3746155Sphk *	- submac() replaces the given macro.
3846155Sphk *		Recurses into subarg() for fun-like macros.
3946155Sphk *	- subarg() expands fun-like macros.
4046155Sphk *		Create strings, concats args, recurses into exparg.
4146155Sphk */
4246155Sphk
4346155Sphk#include "config.h"
44192895Sjamie
45164032Srwatson#include <sys/stat.h>
4646155Sphk
47124882Srwatson#include <fcntl.h>
48177785Skib#ifdef HAVE_UNISTD_H
4946155Sphk#include <unistd.h>
5087275Srwatson#endif
5187275Srwatson#include <stdio.h>
52168401Spjd#include <stdarg.h>
53193066Sjamie#include <stdlib.h>
54113275Smike#include <string.h>
55147185Spjd#include <time.h>
56113275Smike
5746155Sphk#include "compat.h"
58113275Smike#include "cpp.h"
5957163Srwatson
60113275Smike#ifndef S_ISDIR
61196019Srwatson#define S_ISDIR(m)	(((m) & S_IFMT) == S_IFDIR)
6246155Sphk#endif
63196019Srwatson
64196019Srwatson#define	SBSIZE	1000000
6546155Sphk
66196019Srwatsonstatic usch	sbf[SBSIZE];
67185435Sbzstatic int	counter;
68185435Sbz/* C command */
69185435Sbz
70185435Sbzint tflag;	/* traditional cpp syntax */
71185435Sbz#ifdef PCC_DEBUG
72185435Sbzint dflag;	/* debug printouts */
7346155Sphk//static void imp(const char *);
74163606Srwatsonstatic void prline(const usch *s);
75163606Srwatsonstatic void prrep(const usch *s);
76195944Sjamie#define	DPRINT(x) if (dflag) printf x
77195944Sjamie#define	DDPRINT(x) if (dflag > 1) printf x
7846155Sphk#define	IMP(x) if (dflag > 1) imp(x)
7946155Sphk#else
80192895Sjamie#define DPRINT(x)
81192895Sjamie#define DDPRINT(x)
82192895Sjamie#define IMP(x)
83192895Sjamie#endif
84192895Sjamie
85192895Sjamieint Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag;
86192895Sjamiechar *Mfile, *MPfile;
87192895Sjamiestruct initar *initar;
88194762Sjamiechar *Mxfile;
89195944Sjamieint warnings, Mxlen;
90201145SantoineFILE *of;
91196176Sbz
92196176Sbz/* include dirs */
93196176Sbzstruct incs {
94193066Sjamie	struct incs *next;
95196176Sbz	usch *dir;
96192895Sjamie	dev_t dev;
97192895Sjamie	ino_t ino;
98192895Sjamie} *incdir[2];
9957163Srwatson
100192895Sjamiestatic struct symtab *filloc;
101168401Spjdstatic struct symtab *linloc;
102191673Sjamiestatic struct symtab *pragloc;
103191673Sjamiestatic struct symtab *defloc;
104179881Sdelphijstatic struct symtab *ctrloc;
105113275Smikeint	trulvl;
106191673Sjamieint	flslvl;
107190466Sjamieint	elflvl;
108191673Sjamieint	elslvl;
109192895Sjamieusch *stringbuf = sbf;
110192895Sjamie
111185435Sbz/*
112190466Sjamie * Macro replacement list syntax:
113192895Sjamie * - For object-type macros, replacement strings are stored as-is.
114185435Sbz * - For function-type macros, macro args are substituted for the
115185435Sbz *   character WARN followed by the argument number.
116190466Sjamie * - The value element points to the beginning of the string.
117192895Sjamie *
118185435Sbz * The first character in the replacement list is the number of arguments:
119113275Smike *   VARG  - ends with ellipsis, next char is argcount without ellips.
120191673Sjamie *   OBJCT - object-type macro
121191673Sjamie *   0	   - empty parenthesis, foo()
122191673Sjamie *   1->   - number of args.
123191673Sjamie *
124191673Sjamie * WARN is used:
125191673Sjamie *	- in stored replacement lists to tell that an argument comes
126113275Smike *	- When expanding replacement lists to tell that the list ended.
127192895Sjamie *
128192895Sjamie * To ensure that an already expanded identifier won't get expanded
129192895Sjamie * again a EBLOCK char + its number is stored directly before any
130192895Sjamie * expanded identifier.
131192895Sjamie */
132192895Sjamie
133192895Sjamie/* args for lookup() */
134192895Sjamie#define	FIND	0
135192895Sjamie#define	ENTER	1
136195870Sjamie
137195870Sjamie/*
138195870Sjamie * No-replacement array.  If a macro is found and exists in this array
139195870Sjamie * then no replacement shall occur.
140195870Sjamie */
141195870Sjamiestruct blocker {
142195870Sjamie	struct blocker *next;
143195870Sjamie	struct symtab *sp;
144195870Sjamie};
145195870Sjamiestruct blocker *blkidx[RECMAX];
146195870Sjamieint blkidp;
147192895Sjamie
148195870Sjamiestatic int readargs2(usch **, struct symtab *sp, const usch **args);
149192895Sjamiestatic int readargs1(struct symtab *sp, const usch **args);
150192895Sjamiestatic struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *);
151195870Sjamiestatic struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *);
152192895Sjamiestatic void usage(void);
153192895Sjamiestatic usch *xstrdup(const usch *str);
154192895Sjamiestatic void addidir(char *idir, struct incs **ww);
155192895Sjamiestatic void vsheap(const char *, va_list);
156192895Sjamiestatic int skipws(struct iobuf *ib);
157192895Sjamiestatic int getyp(usch *s);
158192895Sjamiestatic void *xrealloc(void *p, int sz);
159192895Sjamiestatic void *xmalloc(int sz);
160192895Sjamie
161192895Sjamieusch locs[] =
162192895Sjamie	{ FILLOC, LINLOC, PRAGLOC, DEFLOC,
163192895Sjamie	    'd','e','f','i','n','e','d',0, CTRLOC };
164192895Sjamie
165192895Sjamieint
166192895Sjamiemain(int argc, char **argv)
167192895Sjamie{
168192895Sjamie	struct initar *it;
169192895Sjamie	register int ch;
170192895Sjamie	const usch *fn1, *fn2;
171192895Sjamie
172192895Sjamie#ifdef TIMING
173192895Sjamie	struct timeval t1, t2;
174192895Sjamie
175196002Sjamie	(void)gettimeofday(&t1, NULL);
176196002Sjamie#endif
177192895Sjamie
178196002Sjamie	while ((ch = getopt(argc, argv, "ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
179192895Sjamie		switch (ch) {
180193865Sjamie		case 'A': /* assembler input */
181192895Sjamie			Aflag++;
182192895Sjamie			break;
183192895Sjamie
184185435Sbz		case 'C': /* Do not discard comments */
185185435Sbz			Cflag++;
186185435Sbz			break;
187185435Sbz
188185435Sbz		case 'E': /* treat warnings as errors */
189185435Sbz			Eflag++;
190185435Sbz			break;
191185435Sbz
192185435Sbz		case 'D': /* define something */
193185435Sbz		case 'i': /* include */
194185435Sbz		case 'U': /* undef */
195185435Sbz			/* XXX should not need malloc() here */
196185435Sbz			if ((it = xmalloc(sizeof(struct initar))) == NULL)
197185435Sbz				error("couldn't apply -%c %s", ch, optarg);
198185435Sbz			it->type = ch;
199185435Sbz			it->str = optarg;
200185435Sbz			it->next = initar;
201185435Sbz			initar = it;
202185435Sbz			break;
203185435Sbz
204185435Sbz		case 'd':
205185435Sbz			while (*optarg) {
206185435Sbz				switch(*optarg) {
207185435Sbz				case 'M': /* display macro definitions */
208185435Sbz					dMflag = 1;
209185435Sbz					Mflag = 1;
210185435Sbz					break;
211185435Sbz
212185435Sbz				default: /* ignore others */
213185435Sbz					break;
214185435Sbz				}
215185435Sbz				optarg++;
216185435Sbz			}
217185435Sbz			break;
218185435Sbz
219185435Sbz		case 'I':
220185435Sbz		case 'S':
221190466Sjamie			addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
222185435Sbz			break;
223185435Sbz
224185435Sbz		case 'M': /* Generate dependencies for make */
225185435Sbz			Mflag++;
226185435Sbz			break;
227185435Sbz
228185435Sbz		case 'P': /* Inhibit generation of line numbers */
229185435Sbz			Pflag++;
230185435Sbz			break;
231191673Sjamie
232191673Sjamie		case 't':
233191673Sjamie			tflag = 1;
234191673Sjamie			break;
235191673Sjamie
236191673Sjamie#ifdef PCC_DEBUG
237191673Sjamie		case 'V':
238185435Sbz			dflag++;
239191673Sjamie			break;
240191673Sjamie#endif
241192895Sjamie		case 'v':
242185435Sbz			fprintf(stderr, "PCC preprocessor version "VERSSTR"\n");
243191673Sjamie			break;
244191673Sjamie
245191673Sjamie		case 'x':
246185435Sbz			if (strcmp(optarg, "MMD") == 0) {
247191673Sjamie				MMDflag++;
248191673Sjamie			} else if (strcmp(optarg, "MP") == 0) {
249191673Sjamie				MPflag++;
250191673Sjamie			} else if (strncmp(optarg, "MT,", 3) == 0 ||
251185435Sbz			    strncmp(optarg, "MQ,", 3) == 0) {
252192895Sjamie				int l = strlen(optarg+3) + 2;
253192895Sjamie				char *cp, *up;
254191673Sjamie
255191673Sjamie				if (optarg[1] == 'Q')
256191673Sjamie					for (cp = optarg+3; *cp; cp++)
257192895Sjamie						if (*cp == '$')
258192895Sjamie							l++;
259192895Sjamie				Mxlen += l;
260192895Sjamie				Mxfile = cp = realloc(Mxfile, Mxlen);
261191673Sjamie				for (up = Mxfile; *up; up++)
262191673Sjamie					;
263191673Sjamie				if (up != Mxfile)
264191673Sjamie					*up++ = ' ';
265185435Sbz				for (cp = optarg+3; *cp; cp++) {
266191673Sjamie					*up++ = *cp;
267191673Sjamie					if (optarg[1] == 'Q' && *cp == '$')
268185435Sbz						*up++ = *cp;
269191673Sjamie				}
270185435Sbz				*up = 0;
271191673Sjamie			} else
272191673Sjamie				usage();
273191673Sjamie			break;
274191673Sjamie
275191673Sjamie		case '?':
276192895Sjamie		default:
277192895Sjamie			usage();
278192895Sjamie		}
279192895Sjamie	}
280192895Sjamie
281192895Sjamie	argc -= optind;
282192895Sjamie	argv += optind;
283192895Sjamie
284192895Sjamie	filloc = lookup((const usch *)"__FILE__", ENTER);
285192895Sjamie	linloc = lookup((const usch *)"__LINE__", ENTER);
286192895Sjamie	pragloc = lookup((const usch *)"_Pragma", ENTER);
287192895Sjamie	defloc = lookup((const usch *)"defined", ENTER);
288193865Sjamie	ctrloc = lookup((const usch *)"__COUNTER__", ENTER);
289193865Sjamie	filloc->value = locs;
290193865Sjamie	linloc->value = locs+1;
291193865Sjamie	pragloc->value = locs+2;
292193865Sjamie	defloc->value = locs+3; /* also have macro name here */
293193865Sjamie	ctrloc->value = locs+12;
294193865Sjamie
295193865Sjamie	if (Mflag && !dMflag) {
296193865Sjamie		char *c;
297192895Sjamie
298192895Sjamie		if (argc < 1)
299185435Sbz			error("-M and no infile");
300193865Sjamie		if ((c = strrchr(argv[0], '/')) == NULL)
301192895Sjamie			c = argv[0];
302192895Sjamie		else
303192895Sjamie			c++;
304192895Sjamie		Mfile = (char *)xstrdup((usch *)c);
305192895Sjamie		if (MPflag)
306192895Sjamie			MPfile = (char *)xstrdup((usch *)c);
307192895Sjamie		if (Mxfile)
308192895Sjamie			Mfile = Mxfile;
309192895Sjamie		if ((c = strrchr(Mfile, '.')) == NULL)
310192895Sjamie			error("-M and no extension: ");
311192895Sjamie		c[1] = 'o';
312192895Sjamie		c[2] = 0;
313192895Sjamie	}
314192895Sjamie
315192895Sjamie	if (argc == 2) {
316192895Sjamie		if ((of = freopen(argv[1], "w", stdout)) == NULL)
317192895Sjamie			error("Can't creat %s", argv[1]);
318192895Sjamie	} else
319192895Sjamie		of = stdout;
320192895Sjamie
321192895Sjamie	if (argc && strcmp(argv[0], "-")) {
322192895Sjamie		fn1 = fn2 = (usch *)argv[0];
323192895Sjamie	} else {
324192895Sjamie		fn1 = NULL;
325192895Sjamie		fn2 = (const usch *)"";
326192895Sjamie	}
327192895Sjamie	if (pushfile(fn1, fn2, 0, NULL))
328192895Sjamie		error("cannot open %s", argv[0]);
329192895Sjamie
330192895Sjamie	fclose(of);
331192895Sjamie#ifdef TIMING
332192895Sjamie	(void)gettimeofday(&t2, NULL);
333192895Sjamie	t2.tv_sec -= t1.tv_sec;
334192895Sjamie	t2.tv_usec -= t1.tv_usec;
335192895Sjamie	if (t2.tv_usec < 0) {
336192895Sjamie		t2.tv_usec += 1000000;
337192895Sjamie		t2.tv_sec -= 1;
338192895Sjamie	}
339192895Sjamie	fprintf(stderr, "cpp total time: %ld s %ld us\n",
340192895Sjamie	     (long)t2.tv_sec, (long)t2.tv_usec);
341192895Sjamie#endif
342192895Sjamie	if (Eflag && warnings > 0)
343192895Sjamie		return 2;
344191673Sjamie
345192895Sjamie	return 0;
346192895Sjamie}
347191673Sjamie
348191673Sjamie/*
349192895Sjamie * Write a character to an out buffer.
350192895Sjamie */
351192895Sjamiestatic void
352191673Sjamieputob(struct iobuf *ob, int ch)
353192895Sjamie{
354192895Sjamie	if (ob->cptr == ob->bsz) {
355191673Sjamie		int sz = ob->bsz - ob->buf;
356192895Sjamie		ob->buf = xrealloc(ob->buf, sz + BUFSIZ);
357192895Sjamie		ob->cptr = ob->buf + sz;
358192895Sjamie		ob->bsz = ob->buf + sz + BUFSIZ;
359191673Sjamie	}
360192895Sjamie//	DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch));
361191673Sjamie	*ob->cptr++ = ch;
362191673Sjamie}
363191673Sjamie
364192895Sjamiestatic int nbufused;
365191673Sjamie/*
366192895Sjamie * Write a character to an out buffer.
367191673Sjamie */
368191673Sjamiestatic struct iobuf *
369192895Sjamiegetobuf(void)
370192895Sjamie{
371192895Sjamie	struct iobuf *iob = xmalloc(sizeof(struct iobuf));
372192895Sjamie
373192895Sjamie	nbufused++;
374192895Sjamie	iob->buf = iob->cptr = xmalloc(BUFSIZ);
375192895Sjamie	iob->bsz = iob->buf + BUFSIZ;
376192895Sjamie	iob->ro = 0;
377192895Sjamie	return iob;
378192895Sjamie}
379192895Sjamie
380192895Sjamie/*
381192895Sjamie * Create a read-only input buffer.
382192895Sjamie */
383192895Sjamiestatic struct iobuf *
384192895Sjamiemkrobuf(const usch *s)
385192895Sjamie{
386192895Sjamie	struct iobuf *iob = xmalloc(sizeof(struct iobuf));
387192895Sjamie
388192895Sjamie	nbufused++;
389192895Sjamie	DPRINT(("mkrobuf %s\n", s));
390192895Sjamie	iob->buf = iob->cptr = (usch *)s;
391192895Sjamie	iob->bsz = iob->buf + strlen((char *)iob->buf);
392192895Sjamie	iob->ro = 1;
393192895Sjamie	return iob;
394192895Sjamie}
395192895Sjamie
396192895Sjamie/*
397192895Sjamie * Copy a string to a buffer.
398191673Sjamie */
399191673Sjamiestatic struct iobuf *
400191673Sjamiestrtobuf(usch *str, struct iobuf *iob)
401191673Sjamie{
402192895Sjamie	DPRINT(("strtobuf iob %p buf %p str %s\n", iob, iob->buf, str));
403192895Sjamie	if (iob == NULL)
404191673Sjamie		iob = getobuf();
405192895Sjamie	do {
406192895Sjamie		putob(iob, *str);
407192895Sjamie	} while (*str++);
408192895Sjamie	iob->cptr--;
409192895Sjamie	return iob;
410192895Sjamie}
411192895Sjamie
412192895Sjamiestatic void
413192895Sjamiebufree(struct iobuf *iob)
414191673Sjamie{
415191673Sjamie	nbufused--;
416191673Sjamie	if (iob->ro == 0)
417191673Sjamie		free(iob->buf);
418192895Sjamie	free(iob);
419192895Sjamie}
420185435Sbz
421185435Sbzstatic void
422192895Sjamieaddidir(char *idir, struct incs **ww)
423192895Sjamie{
424192895Sjamie	struct incs *w;
425192895Sjamie	struct stat st;
426192895Sjamie
427192895Sjamie	if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
428192895Sjamie		return; /* ignore */
429192895Sjamie	if (*ww != NULL) {
430192895Sjamie		for (w = *ww; w->next; w = w->next) {
431192895Sjamie#ifdef _WIN32
432192895Sjamie			if (strcmp(w->dir, idir) == 0)
433185435Sbz				return;
434192895Sjamie#else
435192895Sjamie			if (w->dev == st.st_dev && w->ino == st.st_ino)
436191673Sjamie				return;
437191673Sjamie#endif
438191673Sjamie		}
439185435Sbz#ifdef _WIN32
440185435Sbz		if (strcmp(w->dir, idir) == 0)
441192895Sjamie			return;
442191673Sjamie#else
443191673Sjamie		if (w->dev == st.st_dev && w->ino == st.st_ino)
444191673Sjamie			return;
445191673Sjamie#endif
446191673Sjamie		ww = &w->next;
447191673Sjamie	}
448191673Sjamie	if ((w = calloc(sizeof(struct incs), 1)) == NULL)
449191673Sjamie		error("couldn't add path %s", idir);
450191673Sjamie	w->dir = (usch *)idir;
451185435Sbz	w->dev = st.st_dev;
452191673Sjamie	w->ino = st.st_ino;
453191673Sjamie	*ww = w;
454191673Sjamie}
455191673Sjamie
456191673Sjamievoid
457191673Sjamieline(void)
458191673Sjamie{
459191673Sjamie	struct symtab *nl;
460191673Sjamie	int c, n, ln;
461191673Sjamie	usch *cp;
462191673Sjamie
463191673Sjamie	cp = stringbuf;
464191673Sjamie	c = skipws(0);
465191673Sjamie	if (ISID0(c)) { /* expand macro */
466191673Sjamie		heapid(c);
467191673Sjamie		stringbuf = cp;
468191673Sjamie		if ((nl = lookup(cp, FIND)) == 0 || kfind(nl) == 0)
469191673Sjamie			goto bad;
470191673Sjamie	} else {
471185435Sbz		do {
472190466Sjamie			savch(c);
473185435Sbz		} while (ISDIGIT(c = cinput()));
474185435Sbz		cunput(c);
475185435Sbz		savch(0);
476185435Sbz	}
477191673Sjamie
478191673Sjamie	stringbuf = cp;
479196135Sbz	n = 0;
480191673Sjamie	while (ISDIGIT(*cp))
481196835Sjamie		n = n * 10 + *cp++ - '0';
482192895Sjamie	if (*cp != 0)
483196135Sbz		goto bad;
484191673Sjamie
485192895Sjamie	/* Can only be decimal number here between 1-2147483647 */
486193066Sjamie	if (n < 1 || n > 2147483647)
487192895Sjamie		goto bad;
488192895Sjamie
489195870Sjamie	ln = n;
490195870Sjamie	ifiles->escln = 0;
491194762Sjamie	if ((c = skipws(NULL)) != '\n') {
492191673Sjamie		if (c == 'L' || c == 'U' || c == 'u') {
493192895Sjamie			n = c, c = cinput();
494191673Sjamie			if (n == 'u' && c == '8')
495191673Sjamie				c = cinput();
496195974Sjamie			if (c == '\"')
497191673Sjamie				warning("#line only allows character literals");
498191673Sjamie		}
499195974Sjamie		if (c != '\"')
500191673Sjamie			goto bad;
501191673Sjamie		/* loses space on heap... does it matter? */
502192895Sjamie		ifiles->fname = stringbuf+1;
503191673Sjamie		faststr(c, savch);
504185435Sbz		stringbuf--;
505191673Sjamie		savch(0);
506191673Sjamie
507191673Sjamie		c = skipws(0);
508191673Sjamie	}
509191673Sjamie	if (c != '\n')
510192895Sjamie		goto bad;
511194762Sjamie
512192895Sjamie	ifiles->lineno = ln;
513191673Sjamie	prtline(1);
514191673Sjamie	ifiles->lineno--;
515191673Sjamie	cunput('\n');
516185435Sbz	return;
517191673Sjamie
518191673Sjamiebad:	error("bad #line");
519191673Sjamie}
520191673Sjamie
521185435Sbz#ifdef MACHOABI
522191673Sjamie
523191673Sjamie/*
524191673Sjamie * Search for framework header file.
525185435Sbz * Return 1 on success.
526191673Sjamie */
527191673Sjamie
528191673Sjamiestatic int
529185435Sbzfsrch_macos_framework(const usch *fn, const usch *dir)
530185435Sbz{
531185435Sbz	usch *saved_stringbuf = stringbuf;
532185435Sbz	usch *s = (usch *)strchr((const char*)fn, '/');
533185435Sbz	usch *nm;
534185435Sbz	usch *p;
535191673Sjamie	int len  = s - fn;
536191673Sjamie
537191673Sjamie	if (s == NULL)
538191673Sjamie		return 0;
539191673Sjamie
540191673Sjamie//	fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir);
541191673Sjamie
542191673Sjamie	nm = savstr(dir);
543191673Sjamie	savch(0);
544191673Sjamie	p = savstr(fn);
545191673Sjamie	stringbuf = p + len;
546191673Sjamie	savch(0);
547191673Sjamie//	fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn);
548191673Sjamie	p = (usch *)strstr((const char *)nm, (const char *)p);
549191673Sjamie//	fprintf(stderr, "p = %s\n", (const char *)p);
550194762Sjamie	if (p != NULL) {
551194762Sjamie		stringbuf = p;
552194762Sjamie		savch(0);
553194762Sjamie		return fsrch_macos_framework(fn, nm);
554194762Sjamie	}
555194762Sjamie
556194762Sjamie	p = nm + strlen((char *)nm) - 1;
557194762Sjamie	while (*p == '/')
558194762Sjamie		p--;
559192895Sjamie	while (*p != '/')
560192895Sjamie		p--;
561192895Sjamie	stringbuf = ++p;
562192895Sjamie	savstr((const usch *)"Frameworks/");
563192895Sjamie	stringbuf = savstr(fn) + len;
564192895Sjamie	savstr((const usch*)".framework/Headers");
565192895Sjamie	savstr(s);
566192895Sjamie	savch(0);
567191673Sjamie
568192895Sjamie//	fprintf(stderr, "nm: %s\n", nm);
569192895Sjamie
570192895Sjamie	if (pushfile(nm, fn, SYSINC, NULL) == 0)
571192895Sjamie		return 1;
572192895Sjamie//	fprintf(stderr, "not found %s, continuing...\n", nm);
573192895Sjamie
574192895Sjamie	stringbuf = saved_stringbuf;
575191673Sjamie
576195870Sjamie	return 0;
577195870Sjamie}
578195870Sjamie
579195870Sjamie#endif
580195870Sjamie
581195870Sjamie/*
582195870Sjamie * Search for and include next file.
583195870Sjamie * Return 1 on success.
584195870Sjamie */
585195870Sjamiestatic int
586195870Sjamiefsrch(const usch *fn, int idx, struct incs *w)
587195870Sjamie{
588195870Sjamie	int i;
589195870Sjamie
590195870Sjamie	for (i = idx; i < 2; i++) {
591195870Sjamie		if (i > idx)
592195870Sjamie			w = incdir[i];
593195870Sjamie		for (; w; w = w->next) {
594195870Sjamie			usch *nm = stringbuf;
595195870Sjamie
596195870Sjamie			savstr(w->dir); savch('/');
597195870Sjamie			savstr(fn); savch(0);
598195870Sjamie			if (pushfile(nm, fn, i, w->next) == 0)
599195870Sjamie				return 1;
600195870Sjamie			stringbuf = nm;
601195870Sjamie		}
602195870Sjamie	}
603195870Sjamie
604191673Sjamie#ifdef MACHOABI
605191673Sjamie	/*
606191673Sjamie	 * On MacOS, we may have to do some clever stuff
607191673Sjamie	 * to resolve framework headers.
608191673Sjamie	 */
609191673Sjamie	{
610194251Sjamie		usch *dir = stringbuf;
611194251Sjamie		savstr(ifiles->orgfn);
612194251Sjamie		stringbuf = (usch *)strrchr((char *)dir, '/');
613194251Sjamie		if (stringbuf != NULL) {
614194251Sjamie			stringbuf++;
615194251Sjamie			savch(0);
616194251Sjamie			if (fsrch_macos_framework(fn, dir) == 1)
617195974Sjamie				return 1;
618195974Sjamie		}
619195974Sjamie		stringbuf = dir;
620195974Sjamie
621195974Sjamie		if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1)
622195974Sjamie			return 1;
623195974Sjamie
624195974Sjamie		if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1)
625195974Sjamie			return 1;
626195974Sjamie	}
627195974Sjamie#endif
628195974Sjamie
629195974Sjamie	return 0;
630195974Sjamie}
631191673Sjamie
632192895Sjamiestatic void
633192895Sjamieprem(void)
634192895Sjamie{
635192895Sjamie	error("premature EOF");
636192895Sjamie}
637192895Sjamie
638192895Sjamiestatic struct iobuf *
639192895Sjamieincfn(void)
640191673Sjamie{
641191673Sjamie	struct iobuf *ob;
642191673Sjamie	struct symtab *nl;
643191673Sjamie	usch *sb;
644191673Sjamie	int c;
645191673Sjamie
646191673Sjamie	sb = stringbuf;
647191673Sjamie	if (spechr[c = skipws(NULL)] & C_ID0) {
648191673Sjamie		heapid(c);
649191673Sjamie		if ((nl = lookup(sb, FIND)) == NULL)
650191673Sjamie			return NULL;
651191673Sjamie
652191673Sjamie		stringbuf = sb;
653191673Sjamie		if (kfind(nl) == 0)
654191673Sjamie			return NULL;
655191673Sjamie		ob = strtobuf(sb, NULL);
656191673Sjamie	} else {
657191673Sjamie		ob = getobuf();
658191673Sjamie		putob(ob, c);
659191673Sjamie		while ((c = cinput()) && c != '\n')
660191673Sjamie			putob(ob, c);
661191673Sjamie		if (c != '\n')
662193066Sjamie			return NULL;
663193066Sjamie		cunput(c);
664191673Sjamie	}
665191673Sjamie	putob(ob, 0);
666191673Sjamie	ob->cptr--;
667191673Sjamie
668191673Sjamie	/* now we have an (expanded?) filename in obuf */
669191673Sjamie	while (ob->buf < ob->cptr && ISWS(ob->cptr[-1]))
670191673Sjamie		ob->cptr--;
671191673Sjamie
672191673Sjamie	if (ob->buf[0] != '\"' && ob->buf[0] != '<')
673191673Sjamie		return NULL;
674193066Sjamie	if (ob->cptr[-1] != '\"' && ob->cptr[-1] != '>')
675193066Sjamie		return NULL;
676193066Sjamie	ob->cptr[-1] = 0;
677193066Sjamie	return ob;
678193066Sjamie}
679193066Sjamie
680193066Sjamie/*
681193066Sjamie * Include a file. Include order:
682193066Sjamie * - For <...> files, first search -I directories, then system directories.
683193066Sjamie * - For "..." files, first search "current" dir, then as <...> files.
684193066Sjamie */
685193066Sjamievoid
686193066Sjamieinclude(void)
687193066Sjamie{
688193066Sjamie	struct iobuf *ob;
689193066Sjamie	usch *fn, *nm = NULL;
690193066Sjamie
691193066Sjamie	if (flslvl)
692193066Sjamie		return;
693193066Sjamie
694193066Sjamie	if ((ob = incfn()) == NULL) /* get include file name in obuf */
695193066Sjamie		error("bad #include");
696193066Sjamie
697193066Sjamie	fn = xstrdup(ob->buf) + 1;	/* Save on string heap? */
698193066Sjamie	bufree(ob);
699193066Sjamie	/* test absolute path first */
700193066Sjamie	if (fn[0] == '/' && pushfile(fn, fn, 0, NULL) == 0)
701193066Sjamie		goto okret;
702193066Sjamie	if (fn[-1] == '\"') {
703193066Sjamie		/* nope, failed, try to create a path for it */
704193066Sjamie		if ((nm = (usch *)strrchr((char *)ifiles->orgfn, '/'))) {
705193066Sjamie			ob = strtobuf((usch *)ifiles->orgfn, NULL);
706193066Sjamie			ob->cptr = ob->buf + (nm - ifiles->orgfn) + 1;
707193066Sjamie			strtobuf(fn, ob);
708193066Sjamie			putob(ob, 0);
709193066Sjamie			nm = xstrdup(ob->buf);
710193066Sjamie			bufree(ob);
711193066Sjamie		} else {
712193066Sjamie			nm = xstrdup(fn);
713193066Sjamie		}
714193066Sjamie		if (pushfile(nm, nm, 0, NULL) == 0) {
715193066Sjamie			free(fn-1);
716193066Sjamie			goto okret;
717193066Sjamie		}
718193066Sjamie	}
719193066Sjamie	if (fsrch(fn, 0, incdir[0]))
720193066Sjamie		goto okret;
721193066Sjamie
722193066Sjamie	error("cannot find '%s'", fn);
723193066Sjamie	/* error() do not return */
724193066Sjamie
725193066Sjamieokret:
726193066Sjamie	if (nm)
727193066Sjamie		free(nm);
728193066Sjamie	prtline(1);
729185435Sbz}
730191673Sjamie
731191673Sjamievoid
732195870Sjamieinclude_next(void)
733191673Sjamie{
734191673Sjamie	struct iobuf *ob;
735191673Sjamie	usch *nm;
736191673Sjamie
737191673Sjamie	if (flslvl)
738192895Sjamie		return;
739195870Sjamie
740195870Sjamie	if ((ob = incfn()) == NULL) /* get include file name in obuf */
741195870Sjamie		error("bad #include_next");
742195870Sjamie
743195870Sjamie	nm = xstrdup(ob->buf+1);
744192895Sjamie	bufree(ob);
745192895Sjamie
746185435Sbz	if (fsrch(nm, ifiles->idx, ifiles->incs) == 0)
747192895Sjamie		error("cannot find '%s'", nm);
748192895Sjamie	prtline(1);
749185435Sbz}
750195974Sjamie
751192895Sjamie/*
752192895Sjamie * Compare two replacement lists, taking in account comments etc.
753192895Sjamie */
754192895Sjamiestatic int
755192895Sjamiecmprepl(const usch *o, const usch *n)
756202116Sbz{
757202116Sbz	for (; *o; o++, n++) {
758202116Sbz		/* comment skip */
759192895Sjamie		if (*o == '/' && o[1] == '*') {
760192895Sjamie			while (*o != '*' || o[1] != '/')
761192895Sjamie				o++;
762192895Sjamie			o += 2;
763192895Sjamie		}
764192895Sjamie		if (*n == '/' && n[1] == '*') {
765192895Sjamie			while (*n != '*' || n[1] != '/')
766192895Sjamie				n++;
767192895Sjamie			n += 2;
768192895Sjamie		}
769192895Sjamie		while (*o == ' ' || *o == '\t')
770192895Sjamie			o++;
771192895Sjamie		while (*n == ' ' || *n == '\t')
772192895Sjamie			n++;
773192895Sjamie		if (*o != *n)
774192895Sjamie			return 1;
775192895Sjamie	}
776192895Sjamie	return 0;
777192895Sjamie}
778192895Sjamie
779192895Sjamiestatic int
780192895Sjamieisell(void)
781192895Sjamie{
782192895Sjamie	if (cinput() != '.' || cinput() != '.')
783185435Sbz		return 0;
784191673Sjamie	return 1;
785191673Sjamie}
786185435Sbz
787185435Sbzstatic int
788191673Sjamieskipwscmnt(struct iobuf *ib)
789191673Sjamie{
790195870Sjamie	/* XXX comment */
791191673Sjamie	return skipws(ib);
792191673Sjamie}
793191673Sjamie
794191673Sjamiestatic int
795191673Sjamiefindarg(usch *s, usch **args, int narg)
796192895Sjamie{
797195870Sjamie	int i;
798195870Sjamie
799195870Sjamie	for (i = 0; i < narg; i++)
800195870Sjamie		if (strcmp((char *)s, (char *)args[i]) == 0)
801195870Sjamie			return i;
802192895Sjamie	return -1;
803192895Sjamie}
804185435Sbz
805192895Sjamie/*
806192895Sjamie * gcc extensions:
807185435Sbz * #define e(a...) f(s, a) ->  a works as __VA_ARGS__
808195974Sjamie * #define e(fmt, ...) f(s, fmt , ##__VA_ARGS__) -> remove , if no args
809192895Sjamie */
810192895Sjamievoid
811192895Sjamiedefine(void)
812192895Sjamie{
813192895Sjamie	struct symtab *np;
814192895Sjamie	usch *args[MAXARGS+1], *sbeg, *bp, cc[2], *vararg;
815192895Sjamie	int c, i, redef, oCflag, t;
816192895Sjamie	int narg = -1;
817192895Sjamie	int wascon;
818192895Sjamie
819192895Sjamie	if (flslvl)
820192895Sjamie		return;
821192895Sjamie
822192895Sjamie	oCflag = Cflag, Cflag = 0; /* Ignore comments here */
823192895Sjamie	if (!ISID0(c = skipws(0)))
824192895Sjamie		goto bad;
825185435Sbz
826191673Sjamie	bp = heapid(c);
827185435Sbz	np = lookup(bp, ENTER);
828185435Sbz	if (np->value) {
829195945Sjamie		stringbuf = bp;
830195945Sjamie		redef = 1;
831195945Sjamie	} else
832195945Sjamie		redef = 0;
833195945Sjamie
834195945Sjamie	vararg = NULL;
835195945Sjamie	sbeg = stringbuf++;
836195945Sjamie	if ((c = cinput()) == '(') {
837195945Sjamie		narg = 0;
838191673Sjamie		/* function-like macros, deal with identifiers */
839191673Sjamie		c = skipws(0);
840191673Sjamie		for (;;) {
841191673Sjamie			switch (c) {
842191673Sjamie			case ')':
843191673Sjamie				break;
844191673Sjamie			case '.':
845191673Sjamie				if (isell() == 0 || (c = skipws(0)) != ')')
846191673Sjamie					goto bad;
847191673Sjamie				vararg = (usch *)"__VA_ARGS__";
848191673Sjamie				break;
849191673Sjamie			default:
850191673Sjamie				if (!ISID0(c))
851191673Sjamie					goto bad;
852191673Sjamie
853191673Sjamie				bp = heapid(c);
854191673Sjamie				/* make sure there is no arg of same name */
855191673Sjamie				if (findarg(bp, args, narg) >= 0)
856191673Sjamie					error("Duplicate parameter \"%s\"", bp);
857191673Sjamie				if (narg == MAXARGS)
858192895Sjamie					error("Too many macro args");
859192895Sjamie				args[narg++] = xstrdup(bp);
860192895Sjamie				stringbuf = bp;
861192895Sjamie				switch ((c = skipws(0))) {
862192895Sjamie				case ',': break;
863192895Sjamie				case ')': continue;
864191673Sjamie				case '.':
865191673Sjamie					if (isell() == 0 || skipws(0) != ')')
866191673Sjamie						goto bad;
867191673Sjamie					vararg = args[--narg];
868191673Sjamie					c = ')';
869191673Sjamie					continue;
870191673Sjamie				default:
871191673Sjamie					goto bad;
872191673Sjamie				}
873191673Sjamie				c = skipws(0);
874191673Sjamie			}
875191673Sjamie			if (c == ')')
876191673Sjamie				break;
877191673Sjamie		}
878191673Sjamie		c = skipws(0);
879191673Sjamie	} else if (c == '\n') {
880191673Sjamie		/* #define foo */
881185435Sbz		;
882191673Sjamie	} else if (c == 0) {
883191673Sjamie		prem();
884191673Sjamie	} else if (!ISWS(c))
885191673Sjamie		goto bad;
886191673Sjamie
887191673Sjamie	Cflag = oCflag; /* Enable comments again */
888191673Sjamie
889191673Sjamie	if (vararg)
890191673Sjamie		stringbuf++;
891185435Sbz
892191673Sjamie	if (ISWS(c))
893191673Sjamie		c = skipwscmnt(0);
894191673Sjamie
895191673Sjamie#define	DELEWS() while (stringbuf > sbeg+1+(vararg!=NULL) && ISWS(stringbuf[-1])) stringbuf--
896191673Sjamie
897191673Sjamie	/* parse replacement-list, substituting arguments */
898191673Sjamie	wascon = 0;
899191673Sjamie	while (c != '\n') {
900191673Sjamie		cc[0] = c, cc[1] = inc2();
901185435Sbz		t = getyp(cc);
902191673Sjamie		cunput(cc[1]);
903191673Sjamie
904185435Sbz		switch (t) {
905191673Sjamie		case ' ':
906191673Sjamie		case '\t':
907191673Sjamie			savch(' '); /* save only one space */
908191673Sjamie			while ((c = cinput()) == ' ' || c == '\t')
909191673Sjamie				;
910191673Sjamie			continue;
911191673Sjamie
912196835Sjamie		case '#':
913196835Sjamie			if (cc[1] == '#') {
914196835Sjamie				/* concat op */
915196835Sjamie				(void)cinput(); /* eat # */
916196835Sjamie				DELEWS();
917196835Sjamie				savch(CONC);
918196835Sjamie				if (ISID0(c = skipws(0)) && narg >= 0)
919191673Sjamie					wascon = 1;
920192895Sjamie				if (c == '\n')
921192895Sjamie					goto bad; /* 6.10.3.3 p1 */
922192895Sjamie				continue;
923192895Sjamie			}
924192895Sjamie
925192895Sjamie			if (narg < 0) {
926192895Sjamie				/* no meaning in object-type macro */
927191673Sjamie				savch('#');
928191673Sjamie				break;
929191673Sjamie			}
930191673Sjamie
931191673Sjamie			/* remove spaces between # and arg */
932191673Sjamie			savch(SNUFF);
933191673Sjamie			c = skipws(0); /* whitespace, ignore */
934192895Sjamie			if (!ISID0(c))
935191673Sjamie				goto bad;
936191673Sjamie			bp = heapid(c);
937191673Sjamie			if (vararg && strcmp((char *)bp, (char *)vararg) == 0) {
938191673Sjamie				stringbuf = bp;
939191673Sjamie				savch(WARN);
940191673Sjamie				savch(VARG);
941191673Sjamie				savch(SNUFF);
942191673Sjamie				break;
943192895Sjamie
944192895Sjamie			}
945192895Sjamie			if ((i = findarg(bp, args, narg)) < 0)
946192895Sjamie				goto bad;
947191673Sjamie			stringbuf = bp;
948191673Sjamie			savch(WARN);
949191673Sjamie			savch(i);
950191673Sjamie			savch(SNUFF);
951191673Sjamie			break;
952191673Sjamie
953191673Sjamie		case NUMBER:
954191673Sjamie			c = fastnum(c, savch);
955191673Sjamie			continue;
956191673Sjamie
957191673Sjamie		case STRING:
958191673Sjamie			if (c == 'L' || c == 'u' || c == 'U') {
959191673Sjamie				savch(c);
960191673Sjamie				if ((c = cinput()) == '8') {
961191673Sjamie					savch(c);
962191673Sjamie					c = cinput();
963191673Sjamie				}
964192895Sjamie			}
965191673Sjamie			if (tflag)
966191673Sjamie				savch(c);
967191673Sjamie			else
968191673Sjamie				faststr(c, savch);
969191673Sjamie			break;
970191673Sjamie
971191673Sjamie		case IDENT:
972191673Sjamie			bp = heapid(c);
973191673Sjamie			stringbuf--; /* remove \0 */
974191673Sjamie			if (narg < 0)
975191673Sjamie				break; /* keep on heap */
976191673Sjamie			if (vararg && strcmp((char *)bp, (char *)vararg) == 0) {
977191673Sjamie				stringbuf = bp;
978191673Sjamie				savch(WARN);
979191673Sjamie				savch(wascon ? GCCARG : VARG);
980191673Sjamie				break;
981191673Sjamie			}
982191673Sjamie
983191673Sjamie			/* check if its an argument */
984191673Sjamie			if ((i = findarg(bp, args, narg)) < 0)
985196835Sjamie				break;
986196835Sjamie			stringbuf = bp;
987196835Sjamie			savch(WARN);
988196835Sjamie			savch(i);
989192895Sjamie			break;
990192895Sjamie
991192895Sjamie		case 0:
992192895Sjamie			goto bad;
993192895Sjamie
994196835Sjamie		default:
995192895Sjamie			savch(c);
996196835Sjamie			break;
997196835Sjamie		}
998192895Sjamie		wascon = 0;
999192895Sjamie		c = cinput();
1000192895Sjamie	}
1001192895Sjamie	cunput(c);
1002192895Sjamie	/* remove trailing whitespace */
1003192895Sjamie	DELEWS();
1004192895Sjamie
1005192895Sjamie	if (sbeg[1+(vararg != 0)] == CONC)
1006192895Sjamie		goto bad; /* 6.10.3.3 p1 */
1007192895Sjamie
1008192895Sjamie	if (vararg) {
1009192895Sjamie		sbeg[0] = VARG;
1010192895Sjamie		sbeg[1] = narg;
1011192895Sjamie	} else
1012192895Sjamie		sbeg[0] = (narg < 0 ? OBJCT : narg);
1013192895Sjamie	savch(0);
1014196835Sjamie
1015192895Sjamie	if (redef && ifiles->idx != SYSINC) {
1016191673Sjamie		if (cmprepl(np->value, sbeg)) { /* not equal */
1017192895Sjamie			np->value = sbeg;
1018192895Sjamie			warning("%s redefined (previously defined at \"%s\" line %d)",
1019192895Sjamie			    np->namep, np->file, np->line);
1020191673Sjamie		} else
1021192895Sjamie			stringbuf = sbeg;  /* forget this space */
1022191673Sjamie	} else
1023192895Sjamie		np->value = sbeg;
1024191673Sjamie
1025191673Sjamie#ifdef PCC_DEBUG
1026191673Sjamie	if (dflag) {
1027191673Sjamie		const usch *w = np->value;
1028191673Sjamie
1029191673Sjamie		printf("!define %s: ", np->namep);
1030191673Sjamie		if (*w == OBJCT)
1031191673Sjamie			printf("[object]");
1032191673Sjamie		else if (*w == VARG)
1033191673Sjamie			printf("[VARG%d]", *++w);
1034191673Sjamie		else
1035191673Sjamie			printf("[%d]", *w);
1036191673Sjamie		putchar('\'');
1037191673Sjamie		prrep(++w);
1038191673Sjamie		printf("\'\n");
1039191673Sjamie	}
1040191673Sjamie#endif
1041191673Sjamie	for (i = 0; i < narg; i++)
1042191673Sjamie		free(args[i]);
1043192895Sjamie	return;
1044191673Sjamie
1045191673Sjamiebad:	error("bad #define");
1046191673Sjamie}
1047191673Sjamie
1048191673Sjamievoid
1049191673Sjamiewarning(const char *fmt, ...)
1050191673Sjamie{
1051191673Sjamie	va_list ap;
1052191673Sjamie
1053191673Sjamie	if (ifiles != NULL)
1054191673Sjamie		fprintf(stderr, "%s:%d: warning: ",
1055191673Sjamie		    ifiles->fname, ifiles->lineno);
1056191673Sjamie
1057191673Sjamie	va_start(ap,fmt);
1058191673Sjamie	vfprintf(stderr, fmt, ap);
1059191673Sjamie	va_end(ap);
1060191673Sjamie	fputc('\n', stderr);
1061191673Sjamie
1062191673Sjamie	warnings++;
1063191673Sjamie}
1064191673Sjamie
1065191673Sjamievoid
1066191673Sjamieerror(const char *fmt, ...)
1067191673Sjamie{
1068191673Sjamie	va_list ap;
1069191673Sjamie
1070191673Sjamie	if (ifiles != NULL)
1071191673Sjamie		fprintf(stderr, "%s:%d: error: ",
1072191673Sjamie		    ifiles->fname, ifiles->lineno);
1073191673Sjamie
1074191673Sjamie	va_start(ap, fmt);
1075191673Sjamie	vfprintf(stderr, fmt, ap);
1076191673Sjamie	va_end(ap);
1077191673Sjamie	fputc('\n', stderr);
1078191673Sjamie	exit(1);
1079191673Sjamie}
1080191673Sjamie
1081191673Sjamie/*
1082191673Sjamie * store a character into the "define" buffer.
1083191673Sjamie */
1084191673Sjamievoid
1085191673Sjamiesavch(int c)
1086185435Sbz{
1087191673Sjamie	if (stringbuf >= &sbf[SBSIZE])
1088191673Sjamie		error("out of macro space!");
1089194762Sjamie
1090194762Sjamie	*stringbuf++ = (usch)c;
1091194762Sjamie}
1092194762Sjamie
1093194762Sjamiestatic int
1094194762Sjamiepragwin(struct iobuf *ib)
1095191673Sjamie{
1096192895Sjamie	return ib ? *ib->cptr++ : cinput();
1097192895Sjamie}
1098192895Sjamie
1099192895Sjamiestatic int
1100192895Sjamieskipws(struct iobuf *ib)
1101192895Sjamie{
1102192895Sjamie	int t;
1103192895Sjamie
1104192895Sjamie	while ((t = pragwin(ib)) == ' ' || t == '\t')
1105192895Sjamie		;
1106191673Sjamie	return t;
1107191673Sjamie}
1108191673Sjamie
1109191673Sjamie/*
1110191673Sjamie * convert _Pragma() to #pragma for output.
1111191673Sjamie * Syntax is already correct.
1112191673Sjamie */
1113191673Sjamiestatic void
1114191673Sjamiepragoper(struct iobuf *ib)
1115191673Sjamie{
1116191673Sjamie	int t;
1117191673Sjamie	usch *bp = stringbuf;
1118191673Sjamie
1119191673Sjamie	if (skipws(ib) != '(' || ((t = skipws(ib)) != '\"' && t != 'L'))
1120191673Sjamie		goto err;
1121191673Sjamie	if (t == 'L' && (t = pragwin(ib)) != '\"')
1122191673Sjamie		goto err;
1123191673Sjamie	savstr((const usch *)"\n#pragma ");
1124191673Sjamie	while ((t = pragwin(ib)) != '\"') {
1125192895Sjamie		if (t == BLKID) {
1126192895Sjamie			pragwin(ib);
1127192895Sjamie			continue;
1128191673Sjamie		}
1129191673Sjamie		if (t == '\"')
1130191673Sjamie			continue;
1131191673Sjamie		if (t == '\\') {
1132191673Sjamie			if ((t = pragwin(ib)) != '\"' && t != '\\')
1133191673Sjamie				savch('\\');
1134191673Sjamie		}
1135191673Sjamie		savch(t);
1136191673Sjamie	}
1137191673Sjamie	sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
1138191673Sjamie	putstr(bp);
1139191673Sjamie	stringbuf = bp;
1140191673Sjamie	if (skipws(ib) == ')')
1141191673Sjamie		return;
1142191673Sjamie
1143191673Sjamieerr:	error("_Pragma() syntax error");
1144191673Sjamie}
1145191673Sjamie
1146192895Sjamiestatic int
1147192895Sjamieexpok(struct symtab *sp, int l)
1148194762Sjamie{
1149185435Sbz	struct blocker *w;
1150192895Sjamie
1151191673Sjamie	if (l == 0)
1152192895Sjamie		return 1;
1153192895Sjamie#ifdef PCC_DEBUG
1154191673Sjamieif (dflag) { printf("expok blocked: "); for (w = blkidx[l]; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
1155191673Sjamie#endif
1156191673Sjamie	w = blkidx[l];
1157191673Sjamie	while (w) {
1158192895Sjamie		if (w->sp == sp)
1159191673Sjamie			return 0;
1160191673Sjamie		w = w->next;
1161195944Sjamie	}
1162195944Sjamie	return 1;
1163195945Sjamie}
1164195945Sjamie
1165195945Sjamiestatic int
1166195945Sjamieexpokb(struct symtab *sp, struct blocker *bl)
1167195945Sjamie{
1168192895Sjamie	struct blocker *w;
1169195974Sjamie
1170195974Sjamie	if (bl == 0)
1171195974Sjamie		return 1;
1172195974Sjamie#ifdef PCC_DEBUG
1173195974Sjamieif (dflag) { printf("expokb blocked: "); for (w = bl; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
1174195974Sjamie#endif
1175195974Sjamie	w = bl;
1176195974Sjamie	while (w) {
1177195974Sjamie		if (w->sp == sp)
1178195974Sjamie			return 0;
1179195974Sjamie		w = w->next;
1180195974Sjamie	}
1181195974Sjamie	return 1;
1182195974Sjamie}
1183192895Sjamie
1184192895Sjamiestatic struct blocker *
1185195974Sjamieblkget(struct symtab *sp, struct blocker *obl)
1186195974Sjamie{
1187195974Sjamie	struct blocker *bl = calloc(sizeof(*obl), 1);
1188195974Sjamie
1189195974Sjamie	bl->sp = sp;
1190195974Sjamie	bl->next = obl;
1191195974Sjamie	return bl;
1192195974Sjamie}
1193195974Sjamie
1194195974Sjamiestatic int
1195195974Sjamieblkix(struct blocker *obl)
1196195974Sjamie{
1197195974Sjamie	if (blkidp > 1 && blkidx[blkidp-1] == obl)
1198195974Sjamie		return blkidp-1;
1199192895Sjamie	if (blkidp == RECMAX)
1200195945Sjamie		error("blkix");
1201195945Sjamie	blkidx[blkidp] = obl;
1202192895Sjamie	return blkidp++;
1203192895Sjamie}
1204196002Sjamie
1205191673Sjamiestatic struct blocker *
1206192895Sjamiemergeadd(struct blocker *bl, int m)
1207192895Sjamie{
1208191673Sjamie	struct blocker *w, *ww;
1209194251Sjamie
1210194251Sjamie	DPRINT(("mergeadd: %p %d\n", bl, m));
1211194251Sjamie	if (bl == 0)
1212194251Sjamie		return blkidx[m];
1213194251Sjamie	if (m == 0)
1214185435Sbz		return bl;
1215191673Sjamie
1216191673Sjamie	blkidx[blkidp] = bl;
1217185435Sbz	for (w = blkidx[m]; w; w = w->next) {
1218192895Sjamie		ww = calloc(sizeof(*w), 1);
1219191673Sjamie		ww->sp = w->sp;
1220191673Sjamie		ww->next = blkidx[blkidp];
1221191673Sjamie		blkidx[blkidp] = ww;
1222191673Sjamie	}
1223185435Sbz	DPRINT(("mergeadd return: %d ", blkidp));
1224191673Sjamie#ifdef PCC_DEBUG
1225185435Sbz	if (dflag) {
1226191673Sjamie		for (w = blkidx[blkidp]; w; w = w->next)
1227191673Sjamie			printf("%s ", w->sp->namep);
1228191673Sjamie		printf("\n");
1229185435Sbz	}
1230191673Sjamie#endif
1231191673Sjamie	return blkidx[blkidp++];
1232195974Sjamie}
1233195974Sjamie
1234195974Sjamiestatic void
1235195974Sjamiestoreblk(int l, struct iobuf *ob)
1236195974Sjamie{
1237195945Sjamie	DPRINT(("storeblk: %d\n", l));
1238195945Sjamie	putob(ob, BLKID);
1239195945Sjamie	putob(ob, l);
1240195945Sjamie}
1241195945Sjamie
1242195945Sjamie/*
1243195945Sjamie * Save filename on heap (with escaped chars).
1244195945Sjamie */
1245195945Sjamiestatic usch *
1246195974Sjamieunfname(void)
1247195974Sjamie{
1248195974Sjamie	usch *sb = stringbuf;
1249195974Sjamie	const usch *bp = ifiles->fname;
1250195974Sjamie
1251195974Sjamie	savch('\"');
1252195974Sjamie	for (; *bp; bp++) {
1253195974Sjamie		if (*bp == '\"' || *bp == '\'' || *bp == '\\')
1254195974Sjamie			savch('\\');
1255195974Sjamie		savch(*bp);
1256195974Sjamie	}
1257195974Sjamie	savch('\"');
1258195974Sjamie	*stringbuf = 0;
1259195974Sjamie	return sb;
1260195974Sjamie}
1261195974Sjamie
1262191673Sjamie/*
1263185435Sbz * Version of fastnum that reads from a string and saves in ob.
1264191673Sjamie * We know that it is a number before calling this routine.
1265192895Sjamie */
1266192895Sjamiestatic usch *
1267192895Sjamiefstrnum(usch *s, struct iobuf *ob)
1268192895Sjamie{
1269192895Sjamie	if (*s == '.') {
1270192895Sjamie		/* not digit, dot.  Next will be digit */
1271194762Sjamie		putob(ob, *s++);
1272194762Sjamie	}
1273194762Sjamie	for (;;) {
1274194762Sjamie		putob(ob, *s++);
1275194762Sjamie		if ((spechr[*s] & C_EP)) {
1276194762Sjamie			if (s[1] != '-' && s[1] != '+')
1277192895Sjamie				break;
1278192895Sjamie			putob(ob, *s++);
1279192895Sjamie		} else if ((*s != '.') && ((spechr[*s] & C_ID) == 0))
1280192895Sjamie			break;
1281192895Sjamie	}
1282192895Sjamie        return s;
1283185435Sbz}
1284195974Sjamie
1285192895Sjamie/*
1286195974Sjamie * get a string or character constant.
1287195974Sjamie * similar to faststr.
1288195974Sjamie */
1289195974Sjamiestatic usch *
1290195974Sjamiefstrstr(usch *s, struct iobuf *ob)
1291195974Sjamie{
1292195974Sjamie	int ch;
1293195974Sjamie
1294195974Sjamie	if (*s == 'L' || *s == 'U' || *s == 'u')
1295195974Sjamie		putob(ob, *s++);
1296195974Sjamie	if (*s == '8')
1297195974Sjamie		putob(ob, *s++);
1298195974Sjamie	ch = *s;
1299195974Sjamie	putob(ob, *s++);
1300195974Sjamie	while (*s != ch) {
1301195974Sjamie		if (*s == '\\')
1302195974Sjamie			putob(ob, *s++);
1303195974Sjamie		putob(ob, *s++);
1304195974Sjamie	}
1305195974Sjamie	putob(ob, *s++);
1306195974Sjamie	return s;
1307195974Sjamie}
1308195974Sjamie
1309195974Sjamie/*
1310192895Sjamie * Save standard comments if found.
1311192895Sjamie */
1312192895Sjamiestatic usch *
1313192895Sjamiefcmnt(usch *s, struct iobuf *ob)
1314192895Sjamie{
1315192895Sjamie	putob(ob, *s++); /* / */
1316192895Sjamie	putob(ob, *s++); /* * */
1317195974Sjamie	for (;;s++) {
1318195974Sjamie		putob(ob, *s);
1319195974Sjamie		if (s[-1] == '*' && *s == '/')
1320195974Sjamie			break;
1321195974Sjamie	}
1322195974Sjamie	return s+1;
1323195974Sjamie}
1324195945Sjamie
1325195974Sjamiestatic int
1326195974Sjamiegetyp(usch *s)
1327195974Sjamie{
1328195945Sjamie
1329195974Sjamie	if (ISID0(*s)) return IDENT;
1330195974Sjamie	if ((*s == 'L' || *s == 'U' || *s == 'u') &&
1331195945Sjamie	    (s[1] == '\'' || s[1] == '\"')) return STRING;
1332195974Sjamie	if (s[0] == 'u' && s[1] == 'U' && s[2] == '\"') return STRING;
1333195945Sjamie	if (s[0] == '\'' || s[0] == '\"') return STRING;
1334195974Sjamie	if (spechr[*s] & C_DIGIT) return NUMBER;
1335192895Sjamie	if (*s == '.' && (spechr[s[1]] & C_DIGIT)) return NUMBER;
1336195974Sjamie	if (*s == '/' && (s[1] == '/' || s[1] == '*')) return CMNT;
1337195974Sjamie	return *s;
1338195974Sjamie
1339195974Sjamie}
1340195974Sjamie
1341195974Sjamie/*
1342195974Sjamie * Check ib and print out the symbols there.
1343195974Sjamie * If expandable symbols found recurse and expand them.
1344195974Sjamie * If last identifier on the input list is expandable return it.
1345195974Sjamie * Expect ib to be zero-terminated.
1346195974Sjamie */
1347195974Sjamiestatic struct symtab *
1348195974Sjamieloopover(struct iobuf *ib)
1349195974Sjamie{
1350192895Sjamie	struct iobuf *xb, *xob;
1351192895Sjamie	struct symtab *sp;
1352192895Sjamie	usch *cp;
1353192895Sjamie	int l, c, t;
1354185435Sbz
1355191673Sjamie	ib->cptr = ib->buf; /* start from beginning */
1356195974Sjamie#ifdef PCC_DEBUG
1357192895Sjamie	if (dflag) {
1358195974Sjamie		printf("loopover: '");
1359195974Sjamie		prline(ib->cptr);
1360195974Sjamie		printf("'\n");
1361195974Sjamie	}
1362195974Sjamie#endif
1363195974Sjamie
1364195974Sjamie	xb = getobuf();
1365195974Sjamie	while ((c = *ib->cptr)) {
1366195974Sjamie		switch (t = getyp(ib->cptr)) {
1367195974Sjamie		case CMNT:
1368195974Sjamie			xb->cptr = xb->buf;
1369195974Sjamie			ib->cptr = fcmnt(ib->cptr, xb);
1370195974Sjamie			*xb->cptr = 0;
1371195974Sjamie			savstr(xb->buf);
1372195974Sjamie			continue;
1373195974Sjamie		case NUMBER:
1374195974Sjamie			xb->cptr = xb->buf;
1375195974Sjamie			ib->cptr = fstrnum(ib->cptr, xb);
1376195974Sjamie			*xb->cptr = 0;
1377195974Sjamie			savstr(xb->buf);
1378195974Sjamie			continue;
1379195974Sjamie		case STRING:
1380195974Sjamie			xb->cptr = xb->buf;
1381192895Sjamie			ib->cptr = fstrstr(ib->cptr,xb);
1382192895Sjamie			*xb->cptr = 0;
1383192895Sjamie			for (cp = xb->buf; *cp; cp++) {
1384192895Sjamie				if (*cp <= BLKID) {
1385192895Sjamie					if (*cp == BLKID)
1386192895Sjamie						cp++;
1387192895Sjamie					continue;
1388195974Sjamie				}
1389195974Sjamie				savch(*cp);
1390195945Sjamie			}
1391195974Sjamie			continue;
1392195974Sjamie		case BLKID:
1393195974Sjamie			l = ib->cptr[1];
1394195945Sjamie			ib->cptr+=2;
1395195974Sjamie			/* FALLTHROUGH */
1396195974Sjamie		case IDENT:
1397195945Sjamie			if (t != BLKID)
1398195974Sjamie				l = 0;
1399195945Sjamie			/*
1400195974Sjamie			 * Tricky: if this is the last identifier
1401192895Sjamie			 * in the expanded list, and it is defined
1402195974Sjamie			 * as a function-like macro, then push it
1403195974Sjamie			 * back on the input stream and let fastscan
1404195974Sjamie			 * handle it as a new macro.
1405195974Sjamie			 * BUT: if this macro is blocked then this
1406195974Sjamie			 * should not be done.
1407195974Sjamie			 */
1408195974Sjamie			for (cp = ib->cptr; ISID(*ib->cptr); ib->cptr++)
1409195974Sjamie				;
1410195974Sjamie			if ((sp = lookup(cp, FIND)) == NULL) {
1411195974Sjamiesstr:				for (; cp < ib->cptr; cp++)
1412195974Sjamie					savch(*cp);
1413195974Sjamie				continue;
1414195974Sjamie			}
1415195974Sjamie			if (expok(sp, l) == 0) {
1416192895Sjamie				/* blocked */
1417192895Sjamie				goto sstr;
1418191673Sjamie			} else {
1419192895Sjamie				if (*sp->value != OBJCT) {
1420191673Sjamie					cp = ib->cptr;
1421192895Sjamie					while (ISWS(*ib->cptr))
1422192895Sjamie						ib->cptr++;
1423191673Sjamie					if (*ib->cptr == 0) {
1424191673Sjamie						bufree(xb);
1425191673Sjamie						return sp;
1426196835Sjamie					}
1427196835Sjamie					ib->cptr = cp;
1428191673Sjamie				}
1429196835Sjamienewmac:				if ((xob = submac(sp, 1, ib, NULL)) == NULL) {
1430196835Sjamie					savstr(sp->namep);
1431192895Sjamie				} else {
1432191673Sjamie					sp = loopover(xob);
1433191673Sjamie					bufree(xob);
1434192895Sjamie					if (sp != NULL)
1435192895Sjamie						goto newmac;
1436191673Sjamie				}
1437192895Sjamie			}
1438192895Sjamie			continue;
1439192895Sjamie		default:
1440192895Sjamie			savch(c);
1441192895Sjamie		}
1442192895Sjamie
1443192895Sjamie		ib->cptr++;
1444192895Sjamie	}
1445192895Sjamie
1446192895Sjamie	bufree(xb);
1447192895Sjamie	DPRINT(("loopover return 0\n"));
1448192895Sjamie	return 0;
1449192895Sjamie}
1450191673Sjamie
1451192895Sjamie/*
1452192895Sjamie * Handle defined macro keywords found on input stream.
1453192895Sjamie * When finished print out the full expanded line.
1454192895Sjamie * Input here is from the lex buffer.
1455185435Sbz * Return 1 if success, 0 otherwise.  fastscan restores stringbuf.
1456191673Sjamie * Scanned data is stored on heap.  Last scan prints out the buffer.
1457191673Sjamie */
1458192895Sjamieint
1459195974Sjamiekfind(struct symtab *sp)
1460195974Sjamie{
1461195974Sjamie	extern int inexpr;
1462195974Sjamie	struct blocker *bl;
1463195974Sjamie	struct iobuf *ib, *ob;
1464195974Sjamie	const usch *argary[MAXARGS+1], *sbp;
1465192895Sjamie	int c, n = 0;
1466195945Sjamie
1467195945Sjamie	blkidp = 1;
1468195945Sjamie	sbp = stringbuf;
1469195945Sjamie	DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
1470195945Sjamie	switch (*sp->value) {
1471195945Sjamie	case FILLOC:
1472192895Sjamie		unfname();
1473192895Sjamie		return 1;
1474192895Sjamie
1475192895Sjamie	case LINLOC:
1476192895Sjamie		sheap("%d", ifiles->lineno);
1477185435Sbz		return 1;
1478191673Sjamie
1479191673Sjamie	case PRAGLOC:
1480192895Sjamie		pragoper(NULL);
1481195974Sjamie		return 1;
1482195974Sjamie
1483195974Sjamie	case DEFLOC:
1484195974Sjamie	case OBJCT:
1485195974Sjamie		bl = blkget(sp, NULL);
1486195974Sjamie		ib = mkrobuf(sp->value+1);
1487192895Sjamie		ob = getobuf();
1488195945Sjamie		ob = exparg(1, ib, ob, bl);
1489195945Sjamie		bufree(ib);
1490195945Sjamie		break;
1491195945Sjamie
1492195945Sjamie	case CTRLOC:
1493195945Sjamie		sheap("%d", counter++);
1494192895Sjamie		return 1;
1495192895Sjamie
1496192895Sjamie	default:
1497192895Sjamie		/* Search for '(' */
1498192895Sjamie		while (ISWSNL(c = cinput()))
1499191673Sjamie			if (c == '\n')
1500191673Sjamie				n++;
1501192895Sjamie		if (c != '(') {
1502191673Sjamie			if (inexpr == 0)
1503192895Sjamie				putstr(sp->namep);
1504192895Sjamie			if (n == 0)
1505192895Sjamie				putch(' ');
1506192895Sjamie			else for (ifiles->lineno += n; n; n--)
1507192895Sjamie				putch('\n');
1508194762Sjamie			cunput(c);
1509194762Sjamie			return 0; /* Failed */
1510194762Sjamie		}
1511194762Sjamie
1512194762Sjamie		/* fetch arguments */
1513194762Sjamieagain:		if (readargs1(sp, argary))
1514194762Sjamie			error("readargs");
1515194762Sjamie
1516192895Sjamie		bl = blkget(sp, NULL);
1517192895Sjamie		ib = subarg(sp, argary, 1, bl);
1518192895Sjamie		ob = getobuf();
1519192895Sjamie		ob = exparg(1, ib, ob, bl);
1520192895Sjamie		bufree(ib);
1521192895Sjamie		break;
1522192895Sjamie	}
1523192895Sjamie
1524192895Sjamie	/*
1525192895Sjamie	 * Loop over stringbuf, output the data and remove remaining
1526192895Sjamie	 * directives.  Start with extracting the last keyword (if any).
1527192895Sjamie	 */
1528192895Sjamie	putob(ob, 0); /* XXX needed? */
1529192895Sjamie
1530192895Sjamie	stringbuf = (usch *)sbp; /* XXX should check cleanup */
1531192895Sjamie	if ((sp = loopover(ob))) {
1532192895Sjamie		/* Search for '(' */
1533192895Sjamie		while (ISWSNL(c = cinput()))
1534192895Sjamie			if (c == '\n')
1535192895Sjamie				n++;
1536191673Sjamie		if (c == '(') {
1537192895Sjamie			bufree(ob);
1538192895Sjamie			goto again;
1539192895Sjamie		}
1540192895Sjamie		cunput(c);
1541192895Sjamie		savstr(sp->namep);
1542192895Sjamie	}
1543191673Sjamie	bufree(ob);
1544191673Sjamie
1545193066Sjamie	for (ifiles->lineno += n; n; n--)
1546193066Sjamie		savch('\n');
1547193066Sjamie	savch(0);
1548193066Sjamie	stringbuf = (usch *)sbp;
1549193066Sjamie	if (nbufused)
1550193066Sjamie		error("lost buffer");
1551193066Sjamie	return 1;
1552193066Sjamie}
1553194118Sjamie
1554194118Sjamie/*
1555194118Sjamie * Replace and push-back on input stream the eventual replaced macro.
1556194118Sjamie * The check for whether it can expand or not should already have been done.
1557194118Sjamie * Blocks for this identifier will be added via insblock() after expansion.
1558194118Sjamie * The same as kfind but read a string.
1559193066Sjamie */
1560193066Sjamiestruct iobuf *
1561193066Sjamiesubmac(struct symtab *sp, int lvl, struct iobuf *ib, struct blocker *obl)
1562193066Sjamie{
1563193066Sjamie	struct blocker *bl;
1564194118Sjamie	struct iobuf *ob;
1565193066Sjamie	const usch *argary[MAXARGS+1];
1566194118Sjamie	usch *cp, *pr;
1567194118Sjamie
1568193066Sjamie	DPRINT(("%d:submac: trying '%s'\n", lvl, sp->namep));
1569194118Sjamie	switch (*sp->value) {
1570193066Sjamie	case FILLOC:
1571193066Sjamie		ob = strtobuf(unfname(), NULL);
1572193066Sjamie		break;
1573193066Sjamie	case LINLOC:
1574193066Sjamie		ob = strtobuf(sheap("%d", ifiles->lineno), NULL);
1575193066Sjamie		break;
1576193066Sjamie	case PRAGLOC:
1577194118Sjamie		pragoper(ib);
1578194118Sjamie		ob = strtobuf((usch *)"", NULL);
1579194118Sjamie		break;
1580193066Sjamie	case OBJCT:
1581194118Sjamie		bl = blkget(sp, obl);
1582194118Sjamie		ib = mkrobuf(sp->value+1);
1583194118Sjamie		ob = getobuf();
1584193066Sjamie		DPRINT(("%d:submac: calling exparg\n", lvl));
1585194118Sjamie		ob = exparg(lvl+1, ib, ob, bl);
1586194118Sjamie		bufree(ib);
1587194118Sjamie		DPRINT(("%d:submac: return exparg\n", lvl));
1588193066Sjamie		break;
1589193066Sjamie	case CTRLOC:
1590193066Sjamie		ob = strtobuf(sheap("%d", counter++), NULL);
1591193066Sjamie		break;
1592193066Sjamie	default:
1593192895Sjamie		cp = ib->cptr;
1594192895Sjamie		while (ISWSNL(*ib->cptr))
1595192895Sjamie			ib->cptr++;
1596192895Sjamie		if (*ib->cptr != '(') {
1597192895Sjamie			ib->cptr = cp;
1598192895Sjamie			return 0;
1599191673Sjamie		}
1600191673Sjamie		cp = ib->cptr++;
1601191673Sjamie		pr = stringbuf;
1602191673Sjamie		if (readargs2(&ib->cptr, sp, argary)) {
1603191673Sjamie			/* Bailed out in the middle of arg list */
1604191673Sjamie			ib->cptr = cp; /* XXX */
1605191673Sjamie			return 0;
1606191673Sjamie		}
1607191673Sjamie		bl = blkget(sp, obl);
1608191673Sjamie		ib = subarg(sp, argary, lvl+1, bl);
1609191673Sjamie		stringbuf = pr;
1610191673Sjamie
1611191673Sjamie		ob = getobuf();
1612191673Sjamie		DPRINT(("%d:submac(: calling exparg\n", lvl));
1613191673Sjamie		ob = exparg(lvl+1, ib, ob, bl);
1614191673Sjamie		bufree(ib);
1615191673Sjamie		DPRINT(("%d:submac(: return exparg\n", lvl));
1616185435Sbz		break;
1617192895Sjamie	}
1618192895Sjamie	putob(ob, 0);
1619192895Sjamie	ob->cptr--;
1620192895Sjamie
1621192895Sjamie	return ob;
1622192895Sjamie}
1623192895Sjamie
1624192895Sjamiestatic int
1625192895Sjamieisdir(void)
1626192895Sjamie{
1627195945Sjamie	usch ch;
1628195945Sjamie
1629195945Sjamie	while ((ch = cinput()) == ' ' || ch == '\t')
1630195945Sjamie		;
1631195945Sjamie	if (ch == '#')
1632195945Sjamie		return 1;
1633192895Sjamie	cunput(ch);
1634192895Sjamie	return 0;
1635192895Sjamie}
1636192895Sjamie
1637192895Sjamie/*
1638192895Sjamie * Deal with directives inside a macro.
1639192895Sjamie * Doing so is really ugly but gcc allows it, so...
1640192895Sjamie */
1641192895Sjamiestatic void
1642192895Sjamiechkdir(void)
1643192895Sjamie{
1644192895Sjamie	usch ch;
1645192895Sjamie
1646192895Sjamie	for (;;) {
1647192895Sjamie		if (isdir()) {
1648192895Sjamie#ifndef GCC_COMPAT
1649192895Sjamie			warning("conditionals inside macro arg list");
1650195945Sjamie#endif
1651195945Sjamie			ppdir();
1652195945Sjamie		}
1653195945Sjamie		if (flslvl == 0)
1654195945Sjamie			return;
1655195945Sjamie		while ((ch = cinput()) != '\n')
1656192895Sjamie			;
1657192895Sjamie		ifiles->lineno++;
1658192895Sjamie		putch('\n');
1659192895Sjamie	}
1660192895Sjamie}
1661192895Sjamie
1662192895Sjamiestatic int
1663192895Sjamiera1_wsnl(int sp)
1664192895Sjamie{
1665192895Sjamie	int c;
1666192895Sjamie
1667191673Sjamie	while (ISWSNL(c = cinput())) {
1668191673Sjamie		if (c == '\n') {
1669191673Sjamie			putch('\n');
1670191673Sjamie			chkdir();
1671191673Sjamie			ifiles->lineno++;
1672191673Sjamie			if (sp) savch(' ');
1673191673Sjamie		}
1674191673Sjamie	}
1675191673Sjamie	return c;
1676191673Sjamie}
1677191673Sjamie
1678191673Sjamie/*
1679191673Sjamie * Read arguments and put in argument array.
1680191673Sjamie * If EOF is encountered return 1, otherwise 0.
1681191673Sjamie */
1682191673Sjamieint
1683191673Sjamiereadargs1(struct symtab *sp, const usch **args)
1684191673Sjamie{
1685191673Sjamie	const usch *vp = sp->value;
1686191673Sjamie	int c, i, plev, narg, ellips = 0;
1687191673Sjamie
1688191673Sjamie	DPRINT(("readargs1\n"));
1689191673Sjamie	narg = *vp++;
1690191673Sjamie	if (narg == VARG) {
1691191673Sjamie		narg = *vp++;
1692191673Sjamie		ellips = 1;
1693191673Sjamie	}
1694191673Sjamie#ifdef PCC_DEBUG
1695191673Sjamie	if (dflag > 1) {
1696191673Sjamie		printf("narg %d varg %d: ", narg, ellips);
1697191673Sjamie		prrep(vp);
1698191673Sjamie		printf("\n");
1699191673Sjamie	}
1700191673Sjamie#endif
1701191673Sjamie
1702191673Sjamie	/*
1703191673Sjamie	 * read arguments and store them on heap.
1704191673Sjamie	 */
1705191673Sjamie	c = '(';
1706191673Sjamie	for (i = 0; i < narg && c != ')'; i++) {
1707191673Sjamie		args[i] = stringbuf;
1708191673Sjamie		plev = 0;
1709191673Sjamie
1710191673Sjamie		c = ra1_wsnl(0);
1711191673Sjamie		for (;;) {
1712191673Sjamie			if (plev == 0 && (c == ')' || c == ','))
1713191673Sjamie				break;
1714191673Sjamie			if (c == '(') plev++;
1715191673Sjamie			if (c == ')') plev--;
1716191673Sjamie			if (c == 0)
1717191673Sjamie				error("eof in macro");
1718191673Sjamie			else if (c == '/') Ccmnt(savch);
1719192895Sjamie			else if (c == '\"' || c == '\'') faststr(c, savch);
1720192895Sjamie			else if (ISID0(c)) {
1721192895Sjamie				usch *bp = stringbuf;
1722192895Sjamie				do {
1723192895Sjamie					savch(c);
1724191673Sjamie				} while ((spechr[c = cinput()] & C_ID));
1725191673Sjamie				if ((sp = lookup(bp, FIND)) != NULL) {
1726191673Sjamie					if (sp == linloc) {
1727191673Sjamie						stringbuf = bp;
1728191673Sjamie						sheap("%d", ifiles->lineno);
1729191673Sjamie					} else if (sp == ctrloc) {
1730191673Sjamie						stringbuf = bp;
1731191673Sjamie						sheap("%d", counter++);
1732191673Sjamie					}
1733191673Sjamie				}
1734191673Sjamie				cunput(c);
1735191673Sjamie			} else
1736191673Sjamie				savch(c);
1737191673Sjamie			if ((c = cinput()) == '\n') {
1738191673Sjamie				chkdir();
1739191673Sjamie				ifiles->lineno++, putch(c), c = ' ';
1740191673Sjamie			}
1741191673Sjamie		}
1742191673Sjamie
1743191673Sjamie		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1744191673Sjamie			stringbuf--;
1745191673Sjamie		savch('\0');
1746191673Sjamie#ifdef PCC_DEBUG
1747191673Sjamie		if (dflag) {
1748191673Sjamie			printf("readargs: save arg %d '", i);
1749191673Sjamie			prline(args[i]);
1750191673Sjamie			printf("'\n");
1751191673Sjamie		}
1752191673Sjamie#endif
1753191673Sjamie	}
1754191673Sjamie
1755191673Sjamie	/* Handle varargs readin */
1756191673Sjamie	if (ellips)
1757191673Sjamie		args[i] = (const usch *)"";
1758191673Sjamie	if (ellips && c != ')') {
1759191673Sjamie		args[i] = stringbuf;
1760191673Sjamie		plev = 0;
176182710Sdillon		c = ra1_wsnl(0);
1762191673Sjamie		for (;;) {
1763191673Sjamie			if (plev == 0 && c == ')')
1764191673Sjamie				break;
1765191673Sjamie			if (c == '(') plev++;
1766114168Smike			if (c == ')') plev--;
176782710Sdillon			if (c == '\"' || c == '\'') faststr(c, savch);
176846155Sphk			else
1769191673Sjamie				savch(c);
177046155Sphk			if ((c = cinput()) == '\n')
1771191673Sjamie				ifiles->lineno++, c = ' ';
1772185435Sbz		}
1773185435Sbz		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1774191673Sjamie			stringbuf--;
1775191673Sjamie		savch('\0');
1776191673Sjamie#ifdef PCC_DEBUG
1777191673Sjamie		if (dflag) {
1778191673Sjamie			printf("readargs: vararg arg %d '", i);
1779185435Sbz			prline(args[i]);
1780185435Sbz			printf("'\n");
1781191673Sjamie		}
1782191673Sjamie#endif
1783191673Sjamie
1784191673Sjamie	}
1785191673Sjamie	if (narg == 0 && ellips == 0)
1786191673Sjamie		c = ra1_wsnl(0);
1787191673Sjamie
1788185435Sbz	if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1789191673Sjamie		error("wrong arg count");
1790191673Sjamie	return 0;
1791191673Sjamie}
1792192895Sjamie
1793191673Sjamiestatic usch *raptr;
1794191673Sjamiestatic int
1795191673Sjamieraread(void)
1796192895Sjamie{
1797185435Sbz	int rv;
1798191673Sjamie
1799191673Sjamie	if (raptr) {
1800185435Sbz		if ((rv = *raptr))
1801191673Sjamie			raptr++;
1802191673Sjamie	} else
1803191673Sjamie		rv = cinput();
1804191673Sjamie	return rv;
1805191673Sjamie}
1806192895Sjamie
1807185435Sbz
1808191673Sjamie/*
1809191673Sjamie * Read arguments and put in argument array.
1810191673Sjamie * If EOF is encountered return 1, otherwise 0.
1811191673Sjamie */
1812191673Sjamieint
1813191673Sjamiereadargs2(usch **inp, struct symtab *sp, const usch **args)
1814191673Sjamie{
1815192895Sjamie	const usch *vp = sp->value;
1816191673Sjamie	usch *bp;
1817191673Sjamie	int c, i, plev, narg, ellips = 0;
1818191673Sjamie
1819191673Sjamie	DPRINT(("readargs2 %s '", sp->namep));
1820191673Sjamie#ifdef PCC_DEBUG
1821191673Sjamie	if (dflag && inp) {
1822191673Sjamie		prline(*inp);
1823191673Sjamie		printf("'\n");
1824191673Sjamie	}
1825191673Sjamie#endif
1826191673Sjamie	raptr = inp ? *inp : 0;
1827191673Sjamie	narg = *vp++;
1828191673Sjamie	if (narg == VARG) {
1829191673Sjamie		narg = *vp++;
1830185435Sbz		ellips = 1;
1831191673Sjamie	}
1832191673Sjamie#ifdef PCC_DEBUG
1833191673Sjamie	if (dflag > 1) {
1834192895Sjamie		prrep(vp);
1835191673Sjamie		printf("\n");
1836191673Sjamie	}
1837191673Sjamie#endif
1838191673Sjamie
1839191673Sjamie
1840191673Sjamie	/*
1841191673Sjamie	 * read arguments and store them on heap.
1842191673Sjamie	 */
1843191673Sjamie	c = '(';
1844191673Sjamie	for (i = 0; i < narg && c != ')'; i++) {
1845191673Sjamie		args[i] = stringbuf;
1846191673Sjamie		plev = 0;
1847191673Sjamie
1848191673Sjamie		while ((c = raread()) == ' ' || c == '\t')
1849191673Sjamie			;
1850191673Sjamie		for (;;) {
185146155Sphk			if (plev == 0 && (c == ')' || c == ','))
1852191673Sjamie				break;
1853191673Sjamie			if (c == '(') plev++;
1854191673Sjamie			if (c == ')') plev--;
1855191673Sjamie			if (c == 0) {
1856191673Sjamie				if (raptr) {
1857191673Sjamie					*inp = raptr;
1858192895Sjamie					raptr = 0;
1859191673Sjamie				} else
1860191673Sjamie					error("eof in macro");
1861191673Sjamie			} else if (c == BLKID) {
1862191673Sjamie				savch(c), savch(raread());
1863191673Sjamie			} else if (c == '/') {
1864191673Sjamie				if ((c = raread()) == '*')
1865191673Sjamie					error("FIXME ccmnt");
1866191673Sjamie				savch('/');
1867191673Sjamie				continue;
1868191673Sjamie			} else if (c == '\"' || c == '\'') {
1869191673Sjamie				if (raptr) {
1870191673Sjamie					struct iobuf *xob = getobuf();
1871191673Sjamie					raptr = fstrstr(raptr-1, xob);
1872191673Sjamie					*xob->cptr = 0;
1873191673Sjamie					savstr(xob->buf);
1874185435Sbz					bufree(xob);
1875191673Sjamie				} else
1876191673Sjamie					faststr(c, savch);
1877191673Sjamie			} else if (ISID0(c)) {
1878191673Sjamie				bp = stringbuf;
1879191673Sjamie				do {
1880191673Sjamie					savch(c);
1881191673Sjamie				} while (ISID(c = raread()));
1882191673Sjamie				*stringbuf = 0;
1883191673Sjamie				if ((sp = lookup(bp, FIND)) && (sp == linloc)) {
1884191673Sjamie					stringbuf = bp;
1885191673Sjamie					sheap("%d", ifiles->lineno);
1886191673Sjamie				}
1887192895Sjamie				continue;
1888192895Sjamie			} else
1889191673Sjamie				savch(c);
1890191673Sjamie			c = raread();
1891192895Sjamie		}
1892192895Sjamie
1893192895Sjamie		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1894192895Sjamie			stringbuf--;
1895191673Sjamie		savch('\0');
1896191673Sjamie#ifdef PCC_DEBUG
1897191673Sjamie		if (dflag) {
1898192895Sjamie			printf("readargs2: save arg %d '", i);
1899191673Sjamie			prline(args[i]);
1900191673Sjamie			printf("'\n");
1901191673Sjamie		}
1902191673Sjamie#endif
1903191673Sjamie	}
1904191673Sjamie
1905191673Sjamie	/* Handle varargs readin */
1906191673Sjamie	if (ellips)
1907191673Sjamie		args[i] = (const usch *)"";
1908191673Sjamie	if (ellips && c != ')') {
1909191673Sjamie		args[i] = stringbuf;
1910191673Sjamie		plev = 0;
1911191673Sjamie		while ((c = raread()) == ' ' || c == '\t')
1912191673Sjamie			;
1913191673Sjamie		for (;;) {
1914191673Sjamie			if (plev == 0 && c == ')')
1915191673Sjamie				break;
1916191673Sjamie			if (c == '(') plev++;
1917194762Sjamie			if (c == ')') plev--;
1918194762Sjamie			if (c == '\"' || c == '\'') {
1919194762Sjamie				if (raptr) {
1920194762Sjamie					struct iobuf *xob = getobuf();
1921194762Sjamie					raptr = fstrstr(raptr-1, xob);
1922194762Sjamie					*xob->cptr = 0;
1923194762Sjamie					savstr(xob->buf);
1924194762Sjamie					bufree(xob);
1925194118Sjamie				} else
1926191673Sjamie					faststr(c, savch);
1927191673Sjamie			} else
1928194118Sjamie				savch(c);
1929193066Sjamie			c = raread();
1930193066Sjamie		}
1931194118Sjamie		while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1932193066Sjamie			stringbuf--;
1933193066Sjamie		savch('\0');
1934193066Sjamie
1935193066Sjamie	}
1936193066Sjamie	if (narg == 0 && ellips == 0) {
1937193066Sjamie		while ((c = raread()) == ' ' || c == '\t')
1938193066Sjamie			;
1939193066Sjamie	}
1940193066Sjamie
1941193066Sjamie	if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1942193066Sjamie		error("wrong arg count");
1943193066Sjamie	if (raptr)
1944193066Sjamie		*inp = raptr;
1945192895Sjamie	return 0;
1946192895Sjamie}
1947191673Sjamie
1948191673Sjamie/*
1949192895Sjamie * expand a function-like macro.
1950192895Sjamie * vp points to end of replacement-list
1951192895Sjamie * reads function arguments from input stream.
1952192895Sjamie * result is pushed-back for more scanning.
1953192895Sjamie */
1954192895Sjamiestruct iobuf *
1955192895Sjamiesubarg(struct symtab *nl, const usch **args, int lvl, struct blocker *bl)
1956192895Sjamie{
1957192895Sjamie	struct blocker *w;
1958192895Sjamie	struct iobuf *ob, *cb, *nb;
1959192895Sjamie	int narg, instr, snuff;
1960192895Sjamie	const usch *sp, *bp, *ap, *vp, *tp;
1961192895Sjamie
1962195870Sjamie	DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
1963195870Sjamie	ob = getobuf();
1964195870Sjamie	vp = nl->value;
1965195870Sjamie	narg = *vp++;
1966195870Sjamie	if (narg == VARG)
1967195870Sjamie		narg = *vp++;
1968195870Sjamie
1969195870Sjamie	sp = vp;
1970195870Sjamie	instr = snuff = 0;
1971195870Sjamie#ifdef PCC_DEBUG
1972195870Sjamie	if (dflag>1) {
1973195870Sjamie		printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
1974195870Sjamie		prrep(vp);
1975192895Sjamie		printf("' ");
1976192895Sjamie		for (w = bl; w; w = w->next)
1977192895Sjamie			printf("%s ", w->sp->namep);
1978192895Sjamie		printf("\n");
1979192895Sjamie	}
1980192895Sjamie#endif
1981192895Sjamie
1982192895Sjamie	/*
1983192895Sjamie	 * walk forward over replacement-list while replacing
1984192895Sjamie	 * arguments.  Arguments are macro-expanded if required.
1985192895Sjamie	 */
1986192895Sjamie	while (*sp) {
1987192895Sjamie		if (*sp == SNUFF)
1988191673Sjamie			putob(ob, '\"'), snuff ^= 1;
1989191673Sjamie		else if (*sp == CONC)
1990191673Sjamie			;
1991191673Sjamie		else if (*sp == WARN) {
1992191673Sjamie
1993191673Sjamie			if (sp[1] == VARG) {
1994191673Sjamie				bp = ap = args[narg];
1995191673Sjamie				sp++;
1996191673Sjamie#ifdef GCC_COMPAT
1997191673Sjamie			} else if (sp[1] == GCCARG) {
1998191673Sjamie				/* XXX remove last , not add 0 */
1999191673Sjamie				ap = args[narg];
2000191673Sjamie				if (ap[0] == 0)
200146155Sphk					ap = (const usch *)"0";
2002191673Sjamie				bp = ap;
2003191673Sjamie				sp++;
200484828Sjhb#endif
2005191673Sjamie			} else
2006191673Sjamie				bp = ap = args[(int)*++sp];
2007191673Sjamie#ifdef PCC_DEBUG
2008191673Sjamie			if (dflag>1){
2009191673Sjamie				printf("%d:subarg GOTwarn; arglist '", lvl);
2010191673Sjamie				prline(bp);
2011191673Sjamie				printf("'\n");
2012185435Sbz			}
2013191673Sjamie#endif
2014191673Sjamie			if (sp[-2] != CONC && !snuff && sp[1] != CONC) {
2015191673Sjamie				/*
2016191673Sjamie				 * Expand an argument; 6.10.3.1:
2017191673Sjamie				 * "A parameter in the replacement list,
2018191673Sjamie				 *  is replaced by the corresponding argument
2019191673Sjamie				 *  after all macros contained therein have
2020191673Sjamie				 *  been expanded.".
2021191673Sjamie				 */
2022191673Sjamie				w = bl ? bl->next : NULL;
2023191673Sjamie				cb = mkrobuf(bp);
2024191673Sjamie				nb = getobuf();
2025191673Sjamie				DPRINT(("%d:subarg: calling exparg\n", lvl));
2026191673Sjamie				nb = exparg(lvl+1, cb, nb, w);
2027191673Sjamie				DPRINT(("%d:subarg: return exparg\n", lvl));
2028191673Sjamie				bufree(cb);
2029191673Sjamie				strtobuf(nb->buf, ob);
2030191673Sjamie				bufree(nb);
2031191673Sjamie			} else {
2032191673Sjamie				while (*bp) {
2033191673Sjamie					if (snuff && !instr && ISWS(*bp)) {
2034185435Sbz						while (ISWS(*bp))
2035191673Sjamie							bp++;
2036191673Sjamie						putob(ob, ' ');
2037191673Sjamie					}
2038191673Sjamie
2039191673Sjamie					if (snuff &&
2040191673Sjamie					    (*bp == '\'' || *bp == '"')) {
2041191673Sjamie						instr ^= 1;
2042191673Sjamie						for (tp = bp - 1; *tp == '\\'; tp--)
2043191673Sjamie							instr ^= 1;
2044191673Sjamie						if (*bp == '"')
2045191673Sjamie							putob(ob, '\\');
2046191673Sjamie					}
2047191673Sjamie					if (snuff && instr && *bp == '\\')
2048191673Sjamie						putob(ob, '\\');
2049191673Sjamie					putob(ob, *bp);
2050191673Sjamie					bp++;
2051191673Sjamie				}
2052191673Sjamie			}
2053191673Sjamie		} else if (ISID0(*sp)) {
2054191673Sjamie			if (lookup(sp, FIND))
2055191673Sjamie				storeblk(blkix(bl), ob);
2056191673Sjamie			while (ISID(*sp))
2057185435Sbz				putob(ob, *sp++);
2058191673Sjamie			sp--;
2059191673Sjamie		} else
2060191673Sjamie			putob(ob, *sp);
2061113275Smike		sp++;
2062192895Sjamie	}
2063191673Sjamie	putob(ob, 0);
2064191673Sjamie	ob->cptr = ob->buf;
2065191673Sjamie	DPRINT(("%d:subarg retline %s\n", lvl, ob->buf));
2066191673Sjamie	return ob;
2067191673Sjamie}
2068191673Sjamie
2069191673Sjamie/*
2070191673Sjamie * Do a (correct) expansion of a WARN-terminated buffer of tokens.
2071192895Sjamie * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
2072192895Sjamie * Expansion blocking is not altered here unless when tokens are
2073185435Sbz * concatenated, in which case they are removed.
2074191673Sjamie */
2075185435Sbzstruct iobuf *
2076191673Sjamieexparg(int lvl, struct iobuf *ib, struct iobuf *ob, struct blocker *bl)
2077185435Sbz{
2078185435Sbz	extern int inexpr;
2079192895Sjamie	struct iobuf *nob;
2080191673Sjamie	struct symtab *nl;
2081185435Sbz	int c, m;
2082191673Sjamie	usch *cp, *bp, *sbp;
2083185435Sbz
2084185435Sbz	DPRINT(("%d:exparg: entry ib %s\n", lvl, ib->cptr));
2085192895Sjamie#ifdef PCC_DEBUG
2086192895Sjamie	if (dflag > 1) {
2087192895Sjamie		printf("exparg entry: full ");
2088192895Sjamie		prline(ib->cptr);
2089192895Sjamie		printf("\n");
2090192895Sjamie	}
2091192895Sjamie#endif
2092192895Sjamie
2093192895Sjamie	while ((c = getyp(ib->cptr)) != 0) {
2094192895Sjamie		ib->cptr++;
2095192895Sjamie
2096192895Sjamie		switch (c) {
2097192895Sjamie
2098192895Sjamie		case CMNT:
2099192895Sjamie			ib->cptr = fcmnt(ib->cptr-1, ob);
2100192895Sjamie			break;
2101192895Sjamie		case NUMBER:
2102192895Sjamie			ib->cptr = fstrnum(ib->cptr-1, ob);
2103192895Sjamie			break;
2104192895Sjamie		case STRING:
2105192895Sjamie			ib->cptr = fstrstr(ib->cptr-1, ob);
2106192895Sjamie			break;
2107192895Sjamie		case BLKID:
2108192895Sjamie			m = *ib->cptr++;
2109192895Sjamie			ib->cptr++;
2110192895Sjamie			/* FALLTHROUGH */
2111192895Sjamie		case IDENT:
2112192895Sjamie			if (c != BLKID)
2113192895Sjamie				m = 0;
2114192895Sjamie			for (cp = ib->cptr-1; ISID(*cp); cp++)
2115192895Sjamie				;
2116192895Sjamie#ifdef PCC_DEBUG
2117192895Sjamieif (dflag) { printf("!! ident "); prline(ib->cptr-1); printf("\n"); }
2118192895Sjamie#endif
2119192895Sjamie			sbp = stringbuf;
2120192895Sjamie			if (*cp == BLKID) {
2121192895Sjamie				/* concatenation */
2122192895Sjamie				bp = stringbuf;
2123192895Sjamie				for (cp = ib->cptr-1;
2124192895Sjamie				    ISID(*cp) || *cp == BLKID; cp++) {
2125192895Sjamie					if (*cp == BLKID) {
2126191673Sjamie						/* XXX add to block list */
2127191673Sjamie						cp++;
2128191673Sjamie					} else
2129191673Sjamie						savch(*cp);
2130191673Sjamie				}
2131191673Sjamie				ib->cptr = cp;
2132179881Sdelphij				cp = stringbuf;
2133113275Smike				savch(0);
2134192895Sjamie			} else {
2135192895Sjamie				bp = ib->cptr-1;
2136192895Sjamie				ib->cptr = cp;
2137192895Sjamie			}
2138192895Sjamie#ifdef PCC_DEBUG
2139192895Sjamieif (dflag) { printf("!! ident2 "); prline(bp); printf("\n"); }
2140192895Sjamie#endif
2141191673Sjamie			if ((nl = lookup(bp, FIND)) == NULL) {
2142191673Sjamiesstr:				for (; bp < cp; bp++)
2143192895Sjamie					putob(ob, *bp);
2144191673Sjamie				stringbuf = sbp;
2145191673Sjamie				break;
2146113275Smike			} else if (inexpr && *nl->value == DEFLOC) {
2147191673Sjamie				int gotlp = 0;
2148191673Sjamie				while (ISWS(*ib->cptr)) ib->cptr++;
2149191673Sjamie				if (*ib->cptr == '(')
2150191673Sjamie					gotlp++, ib->cptr++;
2151191673Sjamie				while (ISWS(*ib->cptr)) ib->cptr++;
2152191673Sjamie				if (!ISID0(*ib->cptr))
2153191673Sjamie					error("bad defined");
2154191673Sjamie				putob(ob, lookup(ib->cptr, FIND) ? '1' : '0');
2155191673Sjamie				while (ISID(*ib->cptr)) ib->cptr++;
2156191673Sjamie				while (ISWS(*ib->cptr)) ib->cptr++;
2157191673Sjamie				if (gotlp && *ib->cptr != ')')
2158191673Sjamie					error("bad defined");
2159191673Sjamie				ib->cptr++;
2160192895Sjamie				break;
2161191673Sjamie			}
2162113275Smike			stringbuf = sbp;
2163113275Smike			if (expokb(nl, bl) && expok(nl, m)) {
2164190466Sjamie				if ((nob = submac(nl, lvl+1, ib, bl))) {
2165113275Smike					if (nob->buf[0] == '-' ||
2166114168Smike					    nob->buf[0] == '+')
2167114168Smike						putob(ob, ' ');
2168114168Smike					strtobuf(nob->buf, ob);
2169113275Smike					if (ob->cptr[-1] == '-' ||
2170113275Smike					    ob->cptr[-1] == '+')
2171114168Smike						putob(ob, ' ');
2172113275Smike					bufree(nob);
2173113275Smike				} else {
2174191673Sjamie					goto sblk;
2175167309Spjd				}
2176164032Srwatson			} else {
2177126023Snectar				/* blocked */
2178126023Snectarsblk:				storeblk(blkix(mergeadd(bl, m)), ob);
2179126023Snectar				goto sstr;
2180168401Spjd			}
2181192895Sjamie			break;
2182113275Smike
2183168401Spjd		default:
2184113275Smike			putob(ob, c);
2185113275Smike			break;
2186185435Sbz		}
2187185435Sbz	}
2188185435Sbz	putob(ob, 0);
2189191673Sjamie	ob->cptr--;
2190185435Sbz	DPRINT(("%d:exparg return: ob %s\n", lvl, ob->buf));
2191191673Sjamie#ifdef PCC_DEBUG
2192185435Sbz	if (dflag > 1) {
2193185435Sbz		printf("%d:exparg: full ", lvl);
2194185435Sbz		prline(ob->buf);
2195185435Sbz		printf("\n");
2196191673Sjamie	}
2197191673Sjamie#endif
2198191673Sjamie	return ob;
2199191673Sjamie}
2200191673Sjamie
2201191673Sjamie#ifdef PCC_DEBUG
2202191673Sjamie
2203192895Sjamiestatic void
2204191673Sjamieprrep(const usch *s)
2205191673Sjamie{
2206191673Sjamie	while (*s) {
2207191673Sjamie		switch (*s) {
2208191673Sjamie		case WARN:
2209191673Sjamie			if (s[1] == VARG) printf("<VARG>");
2210191673Sjamie			else if (s[1] == GCCARG) printf("<GCCARG>");
2211191673Sjamie			else printf("<ARG(%d)>", s[1]);
2212191673Sjamie			s++;
2213191673Sjamie			break;
2214191673Sjamie		case CONC: printf("<CONC>"); break;
2215191673Sjamie		case SNUFF: printf("<SNUFF>"); break;
2216113275Smike		case BLKID: printf("<BLKID(%d)>",s[1]); s++; break;
2217191673Sjamie		default: printf("%c", *s); break;
2218113275Smike		}
2219191673Sjamie		s++;
2220191673Sjamie	}
2221191673Sjamie}
2222191673Sjamie
2223191673Sjamiestatic void
2224191673Sjamieprline(const usch *s)
2225191673Sjamie{
2226168401Spjd	while (*s) {
2227113275Smike		switch (*s) {
2228185435Sbz		case BLKID: printf("<BLKID(%d)>", *++s); break;
2229185435Sbz		case WARN: printf("<WARN>"); break;
2230185435Sbz		case CONC: printf("<CONC>"); break;
2231192895Sjamie		case SNUFF: printf("<SNUFF>"); break;
2232191673Sjamie		case '\n': printf("<NL>"); break;
2233185435Sbz		default:
2234185435Sbz			if (*s > 0x7f)
2235191673Sjamie				printf("<0x%x>", *s);
2236185435Sbz			else
2237150652Scsjp				printf("%c", *s);
2238175202Sattilio			break;
2239113275Smike		}
2240113275Smike		s++;
2241113275Smike	}
2242172930Srwatson}
2243113275Smike#endif
2244113275Smike
2245175294Sattiliousch *
2246191673Sjamiesavstr(const usch *str)
2247191673Sjamie{
2248150652Scsjp	usch *rv = stringbuf;
2249113275Smike
225084828Sjhb	do {
225184828Sjhb		if (stringbuf >= &sbf[SBSIZE])
225284828Sjhb			error("out of macro space!");
2253113275Smike	} while ((*stringbuf++ = *str++));
225484828Sjhb	stringbuf--;
2255113630Sjhb	return rv;
225684828Sjhb}
225784828Sjhb
225884828Sjhbvoid
2259192895Sjamieputch(int ch)
226046155Sphk{
2261191673Sjamie	if (Mflag)
2262175294Sattilio		return;
2263191673Sjamie	fputc(ch, stdout);
2264150652Scsjp}
2265191673Sjamie
2266191673Sjamievoid
2267192895Sjamieputstr(const usch *s)
2268191673Sjamie{
226946155Sphk	for (; *s; s++) {
227046155Sphk		if (Mflag == 0)
227146155Sphk			fputc(*s, stdout);
2272192895Sjamie	}
2273113275Smike}
2274113275Smike
2275113275Smike/*
2276168399Spjd * convert a number to an ascii string. Store it on the heap.
2277113275Smike */
2278113275Smikestatic void
2279113275Smikenum2str(int num)
2280113275Smike{
2281168401Spjd	static usch buf[12];
2282191673Sjamie	usch *b = buf;
2283113275Smike	int m = 0;
2284113275Smike
2285191673Sjamie	if (num < 0)
2286191673Sjamie		num = -num, m = 1;
2287191673Sjamie	do {
2288113275Smike		*b++ = (usch)(num % 10 + '0');
2289113275Smike		num /= 10;
2290113275Smike	} while (num);
2291113275Smike	if (m)
2292113275Smike		*b++ = '-';
2293191673Sjamie	while (b > buf)
2294192895Sjamie		savch(*--b);
2295191673Sjamie}
2296191673Sjamie
2297192895Sjamie/*
2298191673Sjamie * similar to sprintf, but only handles %c, %s and %d.
2299192895Sjamie * saves result on heap.
2300192895Sjamie */
2301192895Sjamiestatic void
2302192895Sjamievsheap(const char *fmt, va_list ap)
2303192895Sjamie{
2304192895Sjamie	for (; *fmt; fmt++) {
2305192895Sjamie		if (*fmt == '%') {
2306192895Sjamie			fmt++;
2307192895Sjamie			switch (*fmt) {
2308192895Sjamie			case 's':
2309192895Sjamie				savstr(va_arg(ap, usch *));
2310192895Sjamie				break;
2311192895Sjamie			case 'd':
2312192895Sjamie				num2str(va_arg(ap, int));
2313192895Sjamie				break;
2314192895Sjamie			case 'c':
2315192895Sjamie				savch(va_arg(ap, int));
2316192895Sjamie				break;
2317192895Sjamie			default:
2318192895Sjamie				error("bad sheap");
2319192895Sjamie			}
2320191673Sjamie		} else
2321192895Sjamie			savch(*fmt);
2322192895Sjamie	}
2323191673Sjamie	*stringbuf = 0;
2324191673Sjamie}
2325192895Sjamie
2326191673Sjamieusch *
2327191673Sjamiesheap(const char *fmt, ...)
2328192895Sjamie{
2329192895Sjamie	va_list ap;
2330191673Sjamie	usch *op = stringbuf;
2331191673Sjamie
2332191673Sjamie	va_start(ap, fmt);
2333191673Sjamie	vsheap(fmt, ap);
2334191673Sjamie	va_end(ap);
2335191673Sjamie
2336191673Sjamie	return op;
2337191673Sjamie}
2338191673Sjamie
2339192895Sjamiestatic void
2340191673Sjamieusage(void)
2341191673Sjamie{
2342191673Sjamie	error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
2343191673Sjamie}
2344191673Sjamie
2345191673Sjamie#ifdef notyet
2346191673Sjamie/*
2347191673Sjamie * Symbol table stuff.
2348191673Sjamie * The data structure used is a patricia tree implementation using only
2349191673Sjamie * bytes to store offsets.
2350191673Sjamie * The information stored is (lower address to higher):
2351192895Sjamie *
2352192895Sjamie *	unsigned char bitno[2]; bit number in the string
2353192895Sjamie *	unsigned char left[3];	offset from base to left element
2354192895Sjamie *	unsigned char right[3];	offset from base to right element
2355192895Sjamie */
2356192895Sjamie#endif
2357192895Sjamie
2358192895Sjamie/*
2359192895Sjamie * This patricia implementation is more-or-less the same as
2360192895Sjamie * used in ccom for string matching.
2361192895Sjamie */
2362192895Sjamiestruct tree {
2363192895Sjamie	int bitno;
2364192895Sjamie	struct tree *lr[2];
2365192895Sjamie};
2366192895Sjamie
2367192895Sjamie#define BITNO(x)		((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
2368192895Sjamie#define LEFT_IS_LEAF		0x80000000
2369192895Sjamie#define RIGHT_IS_LEAF		0x40000000
2370191673Sjamie#define IS_LEFT_LEAF(x)		(((x) & LEFT_IS_LEAF) != 0)
2371191673Sjamie#define IS_RIGHT_LEAF(x)	(((x) & RIGHT_IS_LEAF) != 0)
2372191673Sjamie#define P_BIT(key, bit)		(key[bit >> 3] >> (bit & 7)) & 1
237372786Srwatson#define CHECKBITS		8
2374185029Spjd
237572786Srwatsonstatic struct tree *sympole;
237672786Srwatsonstatic int numsyms;
2377185029Spjd
237872786Srwatsonstatic struct tree *
237972786Srwatsongtree(void)
2380168483Spjd{
2381124882Srwatson	static int ntrees;
2382144660Sjeff	static struct tree *tp;
238387275Srwatson
238472786Srwatson	if (ntrees == 0) {
238587275Srwatson		tp = xmalloc(BUFSIZ);
238672786Srwatson		ntrees = BUFSIZ/sizeof(*tp);
238772786Srwatson	}
2388185029Spjd	return &tp[--ntrees];
2389185029Spjd}
2390185029Spjd
2391185029Spjd/*
2392185029Spjd * Allocate a symtab struct and store the string.
2393185029Spjd */
2394185029Spjdstatic struct symtab *
2395185029Spjdgetsymtab(const usch *str)
2396124882Srwatson{
2397124882Srwatson	static int nsyms;
2398124882Srwatson	static struct symtab *spp;
2399191673Sjamie	struct symtab *sp;
2400191673Sjamie
2401191673Sjamie	if (nsyms == 0) {
2402191673Sjamie		spp = xmalloc(BUFSIZ);
2403191673Sjamie		nsyms = BUFSIZ/sizeof(*sp);
2404191673Sjamie	}
2405191673Sjamie	sp = &spp[--nsyms];
2406191673Sjamie
2407191673Sjamie	sp->namep = str;
2408191673Sjamie	sp->value = NULL;
2409191673Sjamie	sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
2410191673Sjamie	sp->line = ifiles ? ifiles->lineno : 0;
2411191673Sjamie	return sp;
2412192895Sjamie}
2413150652Scsjp
2414124882Srwatson/*
2415191673Sjamie * Do symbol lookup in a patricia tree.
2416191673Sjamie * Only do full string matching, no pointer optimisations.
2417192895Sjamie */
2418191673Sjamiestruct symtab *
2419192895Sjamielookup(const usch *key, int enterf)
2420192895Sjamie{
2421192895Sjamie	struct symtab *sp;
2422192895Sjamie	struct tree *w, *new, *last;
2423192895Sjamie	int len, cix, bit, fbit, svbit, ix, bitno;
2424192895Sjamie	const usch *k, *m;
2425192895Sjamie
2426192895Sjamie	/* Count full string length */
2427191673Sjamie	for (k = key, len = 0; ISID(*k) & C_ID; k++, len++)
2428191673Sjamie		;
2429192895Sjamie
2430191673Sjamie	switch (numsyms) {
2431191673Sjamie	case 0: /* no symbols yet */
2432191673Sjamie		if (enterf != ENTER)
2433191673Sjamie			return NULL;
2434191673Sjamie		sympole = (struct tree *)getsymtab(key);
2435191673Sjamie		numsyms++;
2436192895Sjamie		return (struct symtab *)sympole;
2437192895Sjamie
2438192895Sjamie	case 1:
2439192895Sjamie		w = sympole;
2440191673Sjamie		svbit = 0; /* XXX gcc */
2441124882Srwatson		break;
2442192895Sjamie
2443192895Sjamie	default:
2444192895Sjamie		w = sympole;
2445192895Sjamie		bitno = len * CHECKBITS;
2446192895Sjamie		for (;;) {
2447192895Sjamie			bit = BITNO(w->bitno);
2448192895Sjamie			fbit = bit >= bitno ? 0 : P_BIT(key, bit);
2449192895Sjamie			svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
2450192895Sjamie			    IS_LEFT_LEAF(w->bitno);
2451192895Sjamie			w = w->lr[fbit];
2452192895Sjamie			if (svbit)
2453191673Sjamie				break;
2454191673Sjamie		}
2455192895Sjamie	}
2456192895Sjamie
2457192895Sjamie	sp = (struct symtab *)w;
2458192895Sjamie
2459192895Sjamie	m = sp->namep;
2460192895Sjamie	k = key;
2461192895Sjamie
2462192895Sjamie	/* Check for correct string and return */
2463168489Spjd	for (cix = 0; *m && ISID(*k) && *m == *k; m++, k++, cix += CHECKBITS)
2464192895Sjamie		;
2465192895Sjamie	if (*m == 0 && ISID(*k) == 0) {
2466192895Sjamie		if (enterf != ENTER && sp->value == NULL)
2467192895Sjamie			return NULL;
2468194762Sjamie		return sp;
2469196592Sjamie	}
2470192895Sjamie
2471194251Sjamie	if (enterf != ENTER)
2472196505Szec		return NULL; /* no string found and do not enter */
2473194251Sjamie
2474194251Sjamie	ix = *m ^ *k;
2475192895Sjamie	while ((ix & 1) == 0)
2476192895Sjamie		ix >>= 1, cix++;
2477192895Sjamie
2478192895Sjamie	/* Create new node */
2479192895Sjamie	new = gtree();
2480192895Sjamie	bit = P_BIT(key, cix);
2481191673Sjamie	new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
2482192895Sjamie	new->lr[bit] = (struct tree *)getsymtab(key);
2483191673Sjamie
2484185435Sbz	if (numsyms++ == 1) {
2485192895Sjamie		new->lr[!bit] = sympole;
2486185435Sbz		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
2487192895Sjamie		sympole = new;
2488192895Sjamie		return (struct symtab *)new->lr[bit];
2489192895Sjamie	}
2490192895Sjamie
2491192895Sjamie	w = sympole;
2492192895Sjamie	last = NULL;
2493192895Sjamie	for (;;) {
2494192895Sjamie		fbit = w->bitno;
2495196592Sjamie		bitno = BITNO(w->bitno);
2496192895Sjamie		if (bitno == cix)
2497124882Srwatson			error("bitno == cix");
2498124882Srwatson		if (bitno > cix)
249972786Srwatson			break;
2500185029Spjd		svbit = P_BIT(key, bitno);
250172786Srwatson		last = w;
250272786Srwatson		w = w->lr[svbit];
2503185029Spjd		if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
2504168489Spjd			break;
2505191671Sjamie	}
250672786Srwatson
2507185029Spjd	new->lr[!bit] = w;
2508185029Spjd	if (last == NULL) {
2509185029Spjd		sympole = new;
2510185029Spjd	} else {
2511185029Spjd		last->lr[svbit] = new;
2512185029Spjd		last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
2513185029Spjd	}
2514185029Spjd	if (bitno < cix)
251587275Srwatson		new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
251672786Srwatson	return (struct symtab *)new->lr[bit];
251772786Srwatson}
2518185435Sbz
2519185435Sbzstatic void *
252087275Srwatsonxmalloc(int sz)
252187275Srwatson{
2522185435Sbz	usch *rv;
2523191673Sjamie
2524191673Sjamie	if ((rv = (void *)malloc(sz)) == NULL)
2525191673Sjamie		error("xmalloc: out of mem");
2526185435Sbz	return rv;
252787275Srwatson}
252887275Srwatson
2529185435Sbzstatic void *
2530185435Sbzxrealloc(void *p, int sz)
2531185435Sbz{
2532185435Sbz	usch *rv;
2533185435Sbz
2534191673Sjamie	if ((rv = (void *)realloc(p, sz)) == NULL)
2535191673Sjamie		error("xrealloc: out of mem");
2536191673Sjamie	return rv;
2537185435Sbz}
2538185435Sbz
2539185435Sbzstatic usch *
2540185435Sbzxstrdup(const usch *str)
2541185435Sbz{
2542192895Sjamie	usch *rv;
2543192895Sjamie
2544192895Sjamie	if ((rv = (usch *)strdup((const char *)str)) == NULL)
2545192895Sjamie		error("xstrdup: out of mem");
2546192895Sjamie	return rv;
2547192895Sjamie}
2548192895Sjamie