xref: /titanic_50/usr/src/lib/libpp/common/ppinput.c (revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968)
1*da2e3ebdSchin /***********************************************************************
2*da2e3ebdSchin *                                                                      *
3*da2e3ebdSchin *               This software is part of the ast package               *
4*da2e3ebdSchin *           Copyright (c) 1986-2007 AT&T Knowledge Ventures            *
5*da2e3ebdSchin *                      and is licensed under the                       *
6*da2e3ebdSchin *                  Common Public License, Version 1.0                  *
7*da2e3ebdSchin *                      by AT&T Knowledge Ventures                      *
8*da2e3ebdSchin *                                                                      *
9*da2e3ebdSchin *                A copy of the License is available at                 *
10*da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*da2e3ebdSchin *                                                                      *
13*da2e3ebdSchin *              Information and Software Systems Research               *
14*da2e3ebdSchin *                            AT&T Research                             *
15*da2e3ebdSchin *                           Florham Park NJ                            *
16*da2e3ebdSchin *                                                                      *
17*da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18*da2e3ebdSchin *                                                                      *
19*da2e3ebdSchin ***********************************************************************/
20*da2e3ebdSchin #pragma prototyped
21*da2e3ebdSchin /*
22*da2e3ebdSchin  * Glenn Fowler
23*da2e3ebdSchin  * AT&T Research
24*da2e3ebdSchin  *
25*da2e3ebdSchin  * preprocessor stacked input stream support
26*da2e3ebdSchin  */
27*da2e3ebdSchin 
28*da2e3ebdSchin #include "pplib.h"
29*da2e3ebdSchin 
30*da2e3ebdSchin 
31*da2e3ebdSchin /*
32*da2e3ebdSchin  * convert path to native representation
33*da2e3ebdSchin  */
34*da2e3ebdSchin 
35*da2e3ebdSchin #if 0
36*da2e3ebdSchin #include "../../lib/libast/path/pathnative.c" /* drop in 2002 */
37*da2e3ebdSchin #else
38*da2e3ebdSchin /* Modified by gisburn 2006-08-18 for OpenSolaris ksh93-integration */
39*da2e3ebdSchin #include "../../libast/common/path/pathnative.c"
40*da2e3ebdSchin #endif
41*da2e3ebdSchin 
42*da2e3ebdSchin static char*
43*da2e3ebdSchin native(register const char* s)
44*da2e3ebdSchin {
45*da2e3ebdSchin 	register int		c;
46*da2e3ebdSchin 	register struct ppfile* xp;
47*da2e3ebdSchin 	int			m;
48*da2e3ebdSchin 	int			n;
49*da2e3ebdSchin 
50*da2e3ebdSchin 	static Sfio_t*		np;
51*da2e3ebdSchin 	static Sfio_t*		qp;
52*da2e3ebdSchin 
53*da2e3ebdSchin 	if (!s)
54*da2e3ebdSchin 		return 0;
55*da2e3ebdSchin 	if (!np && !(np = sfstropen()) || !qp && !(qp = sfstropen()))
56*da2e3ebdSchin 		return (char*)s;
57*da2e3ebdSchin 	n = PATH_MAX;
58*da2e3ebdSchin 	do
59*da2e3ebdSchin 	{
60*da2e3ebdSchin 		m = n;
61*da2e3ebdSchin 		n = pathnative(s, sfstrrsrv(np, m), m);
62*da2e3ebdSchin 	} while (n > m);
63*da2e3ebdSchin 	sfstrseek(np, n, SEEK_CUR);
64*da2e3ebdSchin 	s = (const char*)sfstruse(np);
65*da2e3ebdSchin 	for (;;)
66*da2e3ebdSchin 	{
67*da2e3ebdSchin 		switch (c = *s++)
68*da2e3ebdSchin 		{
69*da2e3ebdSchin 		case 0:
70*da2e3ebdSchin 			break;
71*da2e3ebdSchin 		case '\\':
72*da2e3ebdSchin 		case '"':
73*da2e3ebdSchin 			sfputc(qp, '\\');
74*da2e3ebdSchin 			/*FALLTHROUGH*/
75*da2e3ebdSchin 		default:
76*da2e3ebdSchin 			sfputc(qp, c);
77*da2e3ebdSchin 			continue;
78*da2e3ebdSchin 		}
79*da2e3ebdSchin 		break;
80*da2e3ebdSchin 	}
81*da2e3ebdSchin 	if (!(xp = ppsetfile(sfstruse(qp))))
82*da2e3ebdSchin 		return (char*)s;
83*da2e3ebdSchin 	return xp->name;
84*da2e3ebdSchin }
85*da2e3ebdSchin 
86*da2e3ebdSchin /*
87*da2e3ebdSchin  * push stream onto input stack
88*da2e3ebdSchin  * used by the PUSH_type macros
89*da2e3ebdSchin  */
90*da2e3ebdSchin 
91*da2e3ebdSchin void
92*da2e3ebdSchin pppush(register int t, register char* s, register char* p, int n)
93*da2e3ebdSchin {
94*da2e3ebdSchin 	register struct ppinstk*	cur;
95*da2e3ebdSchin 
96*da2e3ebdSchin 	PUSH(t, cur);
97*da2e3ebdSchin 	cur->line = error_info.line;
98*da2e3ebdSchin 	cur->file = error_info.file;
99*da2e3ebdSchin 	switch (t)
100*da2e3ebdSchin 	{
101*da2e3ebdSchin 	case IN_FILE:
102*da2e3ebdSchin 		if (pp.option & NATIVE)
103*da2e3ebdSchin 			s = native(s);
104*da2e3ebdSchin 		cur->flags |= IN_newline;
105*da2e3ebdSchin 		cur->fd = n;
106*da2e3ebdSchin 		cur->hide = ++pp.hide;
107*da2e3ebdSchin 		cur->symbol = 0;
108*da2e3ebdSchin #if CHECKPOINT
109*da2e3ebdSchin 		if ((pp.mode & (DUMP|INIT)) == DUMP)
110*da2e3ebdSchin 		{
111*da2e3ebdSchin 			cur->index = newof(0, struct ppindex, 1, 0);
112*da2e3ebdSchin 			if (pp.lastindex) pp.lastindex->next = cur->index;
113*da2e3ebdSchin 			else pp.firstindex = cur->index;
114*da2e3ebdSchin 			pp.lastindex = cur->index;
115*da2e3ebdSchin 			cur->index->file = pp.original;
116*da2e3ebdSchin 			cur->index->begin = ppoffset();
117*da2e3ebdSchin 		}
118*da2e3ebdSchin #endif
119*da2e3ebdSchin 		n = 1;
120*da2e3ebdSchin #if CHECKPOINT
121*da2e3ebdSchin 		if (!(pp.mode & DUMP))
122*da2e3ebdSchin #endif
123*da2e3ebdSchin 		if (!cur->prev->prev && !(pp.state & COMPILE) && isatty(0))
124*da2e3ebdSchin 			cur->flags |= IN_flush;
125*da2e3ebdSchin #if ARCHIVE
126*da2e3ebdSchin 		if (pp.member)
127*da2e3ebdSchin 		{
128*da2e3ebdSchin 			switch (pp.member->archive->type & (TYPE_BUFFER|TYPE_CHECKPOINT))
129*da2e3ebdSchin 			{
130*da2e3ebdSchin 			case 0:
131*da2e3ebdSchin #if CHECKPOINT
132*da2e3ebdSchin 				cur->buflen = pp.member->size;
133*da2e3ebdSchin #endif
134*da2e3ebdSchin 				p = (cur->buffer = oldof(0, char, 0, pp.member->size + PPBAKSIZ + 1)) + PPBAKSIZ;
135*da2e3ebdSchin 				if (sfseek(pp.member->archive->info.sp, pp.member->offset, SEEK_SET) != pp.member->offset)
136*da2e3ebdSchin 					error(3, "%s: archive seek error", pp.member->archive->name);
137*da2e3ebdSchin 				if (sfread(pp.member->archive->info.sp, p, pp.member->size) != pp.member->size)
138*da2e3ebdSchin 					error(3, "%s: archive read error", pp.member->archive->name);
139*da2e3ebdSchin 				pp.member = 0;
140*da2e3ebdSchin 				break;
141*da2e3ebdSchin 			case TYPE_BUFFER:
142*da2e3ebdSchin #if CHECKPOINT
143*da2e3ebdSchin 			case TYPE_CHECKPOINT|TYPE_BUFFER:
144*da2e3ebdSchin 				cur->buflen = pp.member->size;
145*da2e3ebdSchin #endif
146*da2e3ebdSchin 				p = cur->buffer = pp.member->archive->info.buffer + pp.member->offset;
147*da2e3ebdSchin 				cur->flags |= IN_static;
148*da2e3ebdSchin 				pp.member = 0;
149*da2e3ebdSchin 				break;
150*da2e3ebdSchin #if CHECKPOINT
151*da2e3ebdSchin 			case TYPE_CHECKPOINT:
152*da2e3ebdSchin 				p = cur->buffer = "";
153*da2e3ebdSchin 				cur->flags |= IN_static;
154*da2e3ebdSchin 				break;
155*da2e3ebdSchin #endif
156*da2e3ebdSchin 			}
157*da2e3ebdSchin 			cur->flags |= IN_eof|IN_newline;
158*da2e3ebdSchin 			cur->fd = -1;
159*da2e3ebdSchin 		}
160*da2e3ebdSchin 		else
161*da2e3ebdSchin #endif
162*da2e3ebdSchin 		{
163*da2e3ebdSchin 			if (lseek(cur->fd, 0L, SEEK_END) > 0 && !lseek(cur->fd, 0L, SEEK_SET))
164*da2e3ebdSchin 				cur->flags |= IN_regular;
165*da2e3ebdSchin 			errno = 0;
166*da2e3ebdSchin #if PROTOTYPE
167*da2e3ebdSchin 			if (!(pp.option & NOPROTO) && !(pp.test & TEST_noproto) && ((pp.state & (COMPATIBILITY|TRANSITION)) == COMPATIBILITY || (pp.option & PLUSPLUS) || (pp.mode & EXTERNALIZE)) && (cur->buffer = pppopen(NiL, cur->fd, NiL, NiL, NiL, NiL, (PROTO_HEADER|PROTO_RETAIN)|(((pp.mode & EXTERNALIZE) || (pp.option & PROTOTYPED)) ? PROTO_FORCE : PROTO_PASS)|((pp.mode & EXTERNALIZE) ? PROTO_EXTERNALIZE : 0)|((pp.mode & MARKC) ? PROTO_PLUSPLUS : 0))))
168*da2e3ebdSchin 			{
169*da2e3ebdSchin 				*(p = cur->buffer - 1) = 0;
170*da2e3ebdSchin 				cur->buffer -= PPBAKSIZ;
171*da2e3ebdSchin 				cur->flags |= IN_prototype;
172*da2e3ebdSchin 				cur->fd = -1;
173*da2e3ebdSchin 			}
174*da2e3ebdSchin 			else
175*da2e3ebdSchin #endif
176*da2e3ebdSchin 			*(p = (cur->buffer = oldof(0, char, 0, PPBUFSIZ + PPBAKSIZ + 1)) + PPBAKSIZ) = 0;
177*da2e3ebdSchin 		}
178*da2e3ebdSchin 		if (pp.incref && !(pp.mode & INIT))
179*da2e3ebdSchin 			(*pp.incref)(error_info.file, s, error_info.line - 1, PP_SYNC_PUSH);
180*da2e3ebdSchin 		if (pp.macref || (pp.option & IGNORELINE))
181*da2e3ebdSchin 			cur->flags |= IN_ignoreline;
182*da2e3ebdSchin 		cur->prefix = pp.prefix;
183*da2e3ebdSchin 		/*FALLTHROUGH*/
184*da2e3ebdSchin 	case IN_BUFFER:
185*da2e3ebdSchin 	case IN_INIT:
186*da2e3ebdSchin 	case IN_RESCAN:
187*da2e3ebdSchin 		pushcontrol();
188*da2e3ebdSchin 		cur->control = pp.control;
189*da2e3ebdSchin 		*pp.control = 0;
190*da2e3ebdSchin 		cur->vendor = pp.vendor;
191*da2e3ebdSchin 		if (cur->type != IN_RESCAN)
192*da2e3ebdSchin 		{
193*da2e3ebdSchin 			if (cur->type == IN_INIT)
194*da2e3ebdSchin 				pp.mode |= MARKHOSTED;
195*da2e3ebdSchin 			error_info.file = s;
196*da2e3ebdSchin 			error_info.line = n;
197*da2e3ebdSchin 		}
198*da2e3ebdSchin 		if (pp.state & HIDDEN)
199*da2e3ebdSchin 		{
200*da2e3ebdSchin 			pp.state &= ~HIDDEN;
201*da2e3ebdSchin 			pp.hidden = 0;
202*da2e3ebdSchin 			if (!(pp.state & NOTEXT) && pplastout() != '\n')
203*da2e3ebdSchin 				ppputchar('\n');
204*da2e3ebdSchin 		}
205*da2e3ebdSchin 		pp.state |= NEWLINE;
206*da2e3ebdSchin 		if (pp.mode & HOSTED) cur->flags |= IN_hosted;
207*da2e3ebdSchin 		else cur->flags &= ~IN_hosted;
208*da2e3ebdSchin 		if (pp.mode & (INIT|MARKHOSTED))
209*da2e3ebdSchin 		{
210*da2e3ebdSchin 			pp.mode |= HOSTED;
211*da2e3ebdSchin 			pp.flags |= PP_hosted;
212*da2e3ebdSchin 		}
213*da2e3ebdSchin 		switch (cur->type)
214*da2e3ebdSchin 		{
215*da2e3ebdSchin 		case IN_FILE:
216*da2e3ebdSchin 			if (!(pp.mode & (INIT|MARKHOSTED)))
217*da2e3ebdSchin 			{
218*da2e3ebdSchin 				pp.mode &= ~HOSTED;
219*da2e3ebdSchin 				pp.flags &= ~PP_hosted;
220*da2e3ebdSchin 			}
221*da2e3ebdSchin #if CATSTRINGS
222*da2e3ebdSchin 			if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
223*da2e3ebdSchin 			else
224*da2e3ebdSchin #endif
225*da2e3ebdSchin 			if (pp.linesync)
226*da2e3ebdSchin 				(*pp.linesync)(error_info.line, error_info.file);
227*da2e3ebdSchin #if ARCHIVE && CHECKPOINT
228*da2e3ebdSchin 			if (pp.member)
229*da2e3ebdSchin 				ppload(NiL);
230*da2e3ebdSchin #endif
231*da2e3ebdSchin 			if (pp.mode & MARKC)
232*da2e3ebdSchin 			{
233*da2e3ebdSchin 				cur->flags |= IN_c;
234*da2e3ebdSchin 				pp.mode &= ~MARKC;
235*da2e3ebdSchin 				if (!(cur->prev->flags & IN_c))
236*da2e3ebdSchin 				{
237*da2e3ebdSchin 					debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr));
238*da2e3ebdSchin 					PUSH_BUFFER("C", "extern \"C\" {\n", 1);
239*da2e3ebdSchin 					return;
240*da2e3ebdSchin 				}
241*da2e3ebdSchin 			}
242*da2e3ebdSchin 			else if (cur->prev->flags & IN_c)
243*da2e3ebdSchin 			{
244*da2e3ebdSchin 				debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr));
245*da2e3ebdSchin 				PUSH_BUFFER("C", "extern \"C++\" {\n", 1);
246*da2e3ebdSchin 				return;
247*da2e3ebdSchin 			}
248*da2e3ebdSchin 			break;
249*da2e3ebdSchin 		case IN_BUFFER:
250*da2e3ebdSchin 			cur->buffer = p = strdup(p);
251*da2e3ebdSchin 			break;
252*da2e3ebdSchin 		default:
253*da2e3ebdSchin 			cur->buffer = p;
254*da2e3ebdSchin 			break;
255*da2e3ebdSchin 		}
256*da2e3ebdSchin 		cur->nextchr = p;
257*da2e3ebdSchin 		break;
258*da2e3ebdSchin #if DEBUG
259*da2e3ebdSchin 	default:
260*da2e3ebdSchin 		error(PANIC, "use PUSH_<%d>(...) instead of pppush(IN_<%d>, ...)", cur->type, cur->type);
261*da2e3ebdSchin 		break;
262*da2e3ebdSchin #endif
263*da2e3ebdSchin 	}
264*da2e3ebdSchin 	debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr)));
265*da2e3ebdSchin }
266*da2e3ebdSchin 
267*da2e3ebdSchin /*
268*da2e3ebdSchin  * external buffer push
269*da2e3ebdSchin  */
270*da2e3ebdSchin 
271*da2e3ebdSchin void
272*da2e3ebdSchin ppinput(char* b, char* f, int n)
273*da2e3ebdSchin {
274*da2e3ebdSchin 	PUSH_BUFFER(f, b, n);
275*da2e3ebdSchin }
276*da2e3ebdSchin 
277*da2e3ebdSchin /*
278*da2e3ebdSchin  * return expanded value of buffer p
279*da2e3ebdSchin  */
280*da2e3ebdSchin 
281*da2e3ebdSchin char*
282*da2e3ebdSchin ppexpand(register char* p)
283*da2e3ebdSchin {
284*da2e3ebdSchin 	register char*		m;
285*da2e3ebdSchin 	register int		n;
286*da2e3ebdSchin 	register int		c;
287*da2e3ebdSchin 	long			restore;
288*da2e3ebdSchin 	char*			pptoken;
289*da2e3ebdSchin 	char*			ppmactop;
290*da2e3ebdSchin 	struct ppmacstk*	nextmacp;
291*da2e3ebdSchin 	struct ppinstk*		cur;
292*da2e3ebdSchin 
293*da2e3ebdSchin 	debug((-7, "before expand: %s", p));
294*da2e3ebdSchin 	if (ppmactop = pp.mactop)
295*da2e3ebdSchin 	{
296*da2e3ebdSchin 		nextmacp = pp.macp->next;
297*da2e3ebdSchin 		nextframe(pp.macp, pp.mactop);
298*da2e3ebdSchin 	}
299*da2e3ebdSchin 	restore = pp.state & (COLLECTING|DISABLE|STRIP);
300*da2e3ebdSchin 	pp.state &= ~restore;
301*da2e3ebdSchin 	pp.mode &= ~MARKMACRO;
302*da2e3ebdSchin 	PUSH_STRING(p);
303*da2e3ebdSchin 	cur = pp.in;
304*da2e3ebdSchin 	pp.in->flags |= IN_expand;
305*da2e3ebdSchin 	pptoken = pp.token;
306*da2e3ebdSchin 	n = 2 * MAXTOKEN;
307*da2e3ebdSchin 	pp.token = p = oldof(0, char, 0, n);
308*da2e3ebdSchin 	m = p + MAXTOKEN;
309*da2e3ebdSchin 	for (;;)
310*da2e3ebdSchin 	{
311*da2e3ebdSchin 		if (pplex())
312*da2e3ebdSchin 		{
313*da2e3ebdSchin 			if ((pp.token = pp.toknxt) > m)
314*da2e3ebdSchin 			{
315*da2e3ebdSchin 				c = pp.token - p;
316*da2e3ebdSchin 				p = newof(p, char, n += MAXTOKEN, 0);
317*da2e3ebdSchin 				m = p + n - MAXTOKEN;
318*da2e3ebdSchin 				pp.token = p + c;
319*da2e3ebdSchin 			}
320*da2e3ebdSchin 			if (pp.mode & MARKMACRO)
321*da2e3ebdSchin 			{
322*da2e3ebdSchin 				pp.mode &= ~MARKMACRO;
323*da2e3ebdSchin 				*pp.token++ = MARK;
324*da2e3ebdSchin 				*pp.token++ = 'X';
325*da2e3ebdSchin 			}
326*da2e3ebdSchin 		}
327*da2e3ebdSchin 		else if (pp.in == cur)
328*da2e3ebdSchin 			break;
329*da2e3ebdSchin 	}
330*da2e3ebdSchin 	*pp.token = 0;
331*da2e3ebdSchin 	if (ppmactop)
332*da2e3ebdSchin 		pp.macp->next = nextmacp;
333*da2e3ebdSchin 	debug((-7, "after expand: %s", p));
334*da2e3ebdSchin 	pp.token = pptoken;
335*da2e3ebdSchin 	pp.state |= restore;
336*da2e3ebdSchin 	pp.in = pp.in->prev;
337*da2e3ebdSchin 	return p;
338*da2e3ebdSchin }
339*da2e3ebdSchin 
340*da2e3ebdSchin #if CHECKPOINT
341*da2e3ebdSchin 
342*da2e3ebdSchin #define LOAD_FUNCTION	(1<<0)
343*da2e3ebdSchin #define LOAD_MULTILINE	(1<<1)
344*da2e3ebdSchin #define LOAD_NOEXPAND	(1<<2)
345*da2e3ebdSchin #define LOAD_PREDICATE	(1<<3)
346*da2e3ebdSchin #define LOAD_READONLY	(1<<4)
347*da2e3ebdSchin #define LOAD_VARIADIC	(1<<5)
348*da2e3ebdSchin 
349*da2e3ebdSchin /*
350*da2e3ebdSchin  * macro definition dump
351*da2e3ebdSchin  */
352*da2e3ebdSchin 
353*da2e3ebdSchin static int
354*da2e3ebdSchin dump(const char* name, char* v, void* handle)
355*da2e3ebdSchin {
356*da2e3ebdSchin 	register struct ppmacro*	mac;
357*da2e3ebdSchin 	register struct ppsymbol*	sym = (struct ppsymbol*)v;
358*da2e3ebdSchin 	register int			flags;
359*da2e3ebdSchin 
360*da2e3ebdSchin 	NoP(name);
361*da2e3ebdSchin 	NoP(handle);
362*da2e3ebdSchin 	if ((mac = sym->macro) && !(sym->flags & (SYM_BUILTIN|SYM_PREDEFINED)))
363*da2e3ebdSchin 	{
364*da2e3ebdSchin 		ppprintf("%s", sym->name);
365*da2e3ebdSchin 		ppputchar(0);
366*da2e3ebdSchin 		flags = 0;
367*da2e3ebdSchin 		if (sym->flags & SYM_FUNCTION) flags |= LOAD_FUNCTION;
368*da2e3ebdSchin 		if (sym->flags & SYM_MULTILINE) flags |= LOAD_MULTILINE;
369*da2e3ebdSchin 		if (sym->flags & SYM_NOEXPAND) flags |= LOAD_NOEXPAND;
370*da2e3ebdSchin 		if (sym->flags & SYM_PREDICATE) flags |= LOAD_PREDICATE;
371*da2e3ebdSchin 		if (sym->flags & SYM_READONLY) flags |= LOAD_READONLY;
372*da2e3ebdSchin 		if (sym->flags & SYM_VARIADIC) flags |= LOAD_VARIADIC;
373*da2e3ebdSchin 		ppputchar(flags);
374*da2e3ebdSchin 		if (sym->flags & SYM_FUNCTION)
375*da2e3ebdSchin 		{
376*da2e3ebdSchin 			ppprintf("%d", mac->arity);
377*da2e3ebdSchin 			ppputchar(0);
378*da2e3ebdSchin 			if (mac->arity)
379*da2e3ebdSchin 			{
380*da2e3ebdSchin 				ppprintf("%s", mac->formals);
381*da2e3ebdSchin 				ppputchar(0);
382*da2e3ebdSchin 			}
383*da2e3ebdSchin 		}
384*da2e3ebdSchin 		ppprintf("%s", mac->value);
385*da2e3ebdSchin 		ppputchar(0);
386*da2e3ebdSchin 	}
387*da2e3ebdSchin 	return(0);
388*da2e3ebdSchin }
389*da2e3ebdSchin 
390*da2e3ebdSchin /*
391*da2e3ebdSchin  * dump macro definitions for quick loading via ppload()
392*da2e3ebdSchin  */
393*da2e3ebdSchin 
394*da2e3ebdSchin void
395*da2e3ebdSchin ppdump(void)
396*da2e3ebdSchin {
397*da2e3ebdSchin 	register struct ppindex*	ip;
398*da2e3ebdSchin 	unsigned long			macro_offset;
399*da2e3ebdSchin 	unsigned long			index_offset;
400*da2e3ebdSchin 
401*da2e3ebdSchin 	/*
402*da2e3ebdSchin 	 * NOTE: we assume '\0' does not occur in valid preprocessed output
403*da2e3ebdSchin 	 */
404*da2e3ebdSchin 
405*da2e3ebdSchin 	ppputchar(0);
406*da2e3ebdSchin 
407*da2e3ebdSchin 	/*
408*da2e3ebdSchin 	 * output global flags
409*da2e3ebdSchin 	 */
410*da2e3ebdSchin 
411*da2e3ebdSchin 	macro_offset = ppoffset();
412*da2e3ebdSchin 	ppputchar(0);
413*da2e3ebdSchin 
414*da2e3ebdSchin 	/*
415*da2e3ebdSchin 	 * output macro definitions
416*da2e3ebdSchin 	 */
417*da2e3ebdSchin 
418*da2e3ebdSchin 	hashwalk(pp.symtab, 0, dump, NiL);
419*da2e3ebdSchin 	ppputchar(0);
420*da2e3ebdSchin 
421*da2e3ebdSchin 	/*
422*da2e3ebdSchin 	 * output include file index
423*da2e3ebdSchin 	 */
424*da2e3ebdSchin 
425*da2e3ebdSchin 	index_offset = ppoffset();
426*da2e3ebdSchin 	ip = pp.firstindex;
427*da2e3ebdSchin 	while (ip)
428*da2e3ebdSchin 	{
429*da2e3ebdSchin 		ppprintf("%s", ip->file->name);
430*da2e3ebdSchin 		ppputchar(0);
431*da2e3ebdSchin 		if (ip->file->guard != INC_CLEAR && ip->file->guard != INC_IGNORE && ip->file->guard != INC_TEST)
432*da2e3ebdSchin 			ppprintf("%s", ip->file->guard->name);
433*da2e3ebdSchin 		ppputchar(0);
434*da2e3ebdSchin 		ppprintf("%lu", ip->begin);
435*da2e3ebdSchin 		ppputchar(0);
436*da2e3ebdSchin 		ppprintf("%lu", ip->end);
437*da2e3ebdSchin 		ppputchar(0);
438*da2e3ebdSchin 		ip = ip->next;
439*da2e3ebdSchin 	}
440*da2e3ebdSchin 	ppputchar(0);
441*da2e3ebdSchin 
442*da2e3ebdSchin 	/*
443*da2e3ebdSchin 	 * output offset directory
444*da2e3ebdSchin 	 */
445*da2e3ebdSchin 
446*da2e3ebdSchin 	ppprintf("%010lu", macro_offset);
447*da2e3ebdSchin 	ppputchar(0);
448*da2e3ebdSchin 	ppprintf("%010lu", index_offset);
449*da2e3ebdSchin 	ppputchar(0);
450*da2e3ebdSchin 	ppflushout();
451*da2e3ebdSchin }
452*da2e3ebdSchin 
453*da2e3ebdSchin /*
454*da2e3ebdSchin  * load text and macro definitions from a previous ppdump()
455*da2e3ebdSchin  * s is the string argument from the pragma (including quotes)
456*da2e3ebdSchin  */
457*da2e3ebdSchin 
458*da2e3ebdSchin void
459*da2e3ebdSchin ppload(register char* s)
460*da2e3ebdSchin {
461*da2e3ebdSchin 	register char*		b;
462*da2e3ebdSchin 	register Sfio_t*	sp;
463*da2e3ebdSchin 	int			m;
464*da2e3ebdSchin 	char*			g;
465*da2e3ebdSchin 	char*			t;
466*da2e3ebdSchin 	unsigned long		n;
467*da2e3ebdSchin 	unsigned long		p;
468*da2e3ebdSchin 	unsigned long		macro_offset;
469*da2e3ebdSchin 	unsigned long		index_offset;
470*da2e3ebdSchin 	unsigned long		file_offset;
471*da2e3ebdSchin 	unsigned long		file_size;
472*da2e3ebdSchin 	unsigned long		keep_begin;
473*da2e3ebdSchin 	unsigned long		keep_end;
474*da2e3ebdSchin 	unsigned long		skip_end;
475*da2e3ebdSchin 	unsigned long		next_begin;
476*da2e3ebdSchin 	unsigned long		next_end;
477*da2e3ebdSchin 	struct ppfile*		fp;
478*da2e3ebdSchin 	struct ppsymbol*	sym;
479*da2e3ebdSchin 	struct ppmacro*		mac;
480*da2e3ebdSchin 
481*da2e3ebdSchin 	char*			ip = 0;
482*da2e3ebdSchin 
483*da2e3ebdSchin 	pp.mode |= LOADING;
484*da2e3ebdSchin 	if (!(pp.state & STANDALONE))
485*da2e3ebdSchin 		error(3, "checkpoint load in standalone mode only");
486*da2e3ebdSchin #if ARCHIVE
487*da2e3ebdSchin 	if (pp.member)
488*da2e3ebdSchin 	{
489*da2e3ebdSchin 		sp = pp.member->archive->info.sp;
490*da2e3ebdSchin 		file_offset = pp.member->offset;
491*da2e3ebdSchin 		file_size = pp.member->size;
492*da2e3ebdSchin 		if (sfseek(sp, file_offset + 22, SEEK_SET) != file_offset + 22 || !(s = sfgetr(sp, '\n', 1)))
493*da2e3ebdSchin 			error(3, "checkpoint magic error");
494*da2e3ebdSchin 	}
495*da2e3ebdSchin 	else
496*da2e3ebdSchin #endif
497*da2e3ebdSchin 	{
498*da2e3ebdSchin 		if (pp.in->type != IN_FILE)
499*da2e3ebdSchin 			error(3, "checkpoint load from files only");
500*da2e3ebdSchin 		if (pp.in->flags & IN_prototype)
501*da2e3ebdSchin 			pp.in->fd = pppdrop(pp.in->buffer + PPBAKSIZ);
502*da2e3ebdSchin 		file_offset = 0;
503*da2e3ebdSchin 		if (pp.in->fd >= 0)
504*da2e3ebdSchin 		{
505*da2e3ebdSchin 			if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, pp.in->fd, SF_READ)))
506*da2e3ebdSchin 				error(3, "checkpoint read error");
507*da2e3ebdSchin 			file_size = sfseek(sp, 0L, SEEK_END);
508*da2e3ebdSchin 		}
509*da2e3ebdSchin 		else
510*da2e3ebdSchin 		{
511*da2e3ebdSchin 			file_size = pp.in->buflen;
512*da2e3ebdSchin 			if (!(sp = sfnew(NiL, pp.in->buffer + ((pp.in->flags & IN_static) ? 0 : PPBAKSIZ), file_size, -1, SF_READ|SF_STRING)))
513*da2e3ebdSchin 				error(3, "checkpoint read error");
514*da2e3ebdSchin 		}
515*da2e3ebdSchin 	}
516*da2e3ebdSchin 	if (!streq(s, pp.checkpoint))
517*da2e3ebdSchin 		error(3, "checkpoint version %s does not match %s", s, pp.checkpoint);
518*da2e3ebdSchin 
519*da2e3ebdSchin 	/*
520*da2e3ebdSchin 	 * get the macro and index offsets
521*da2e3ebdSchin 	 */
522*da2e3ebdSchin 
523*da2e3ebdSchin 	p = file_offset + file_size - 22;
524*da2e3ebdSchin 	if ((n = sfseek(sp, p, SEEK_SET)) != p)
525*da2e3ebdSchin 		error(3, "checkpoint directory seek error");
526*da2e3ebdSchin 	if (!(t = sfreserve(sp, 22, 0)))
527*da2e3ebdSchin 		error(3, "checkpoint directory read error");
528*da2e3ebdSchin 	macro_offset = file_offset + strtol(t, &t, 10);
529*da2e3ebdSchin 	index_offset = file_offset + strtol(t + 1, NiL, 10);
530*da2e3ebdSchin 
531*da2e3ebdSchin 	/*
532*da2e3ebdSchin 	 * read the include index
533*da2e3ebdSchin 	 */
534*da2e3ebdSchin 
535*da2e3ebdSchin 	if (sfseek(sp, index_offset, SEEK_SET) != index_offset)
536*da2e3ebdSchin 		error(3, "checkpoint index seek error");
537*da2e3ebdSchin 	if (!(s = sfreserve(sp, n - index_offset, 0)))
538*da2e3ebdSchin 		error(3, "checkpoint index read error");
539*da2e3ebdSchin 	if (sfset(sp, 0, 0) & SF_STRING)
540*da2e3ebdSchin 		b = s;
541*da2e3ebdSchin 	else if (!(b = ip = memdup(s, n - index_offset)))
542*da2e3ebdSchin 		error(3, "checkpoint index alloc error");
543*da2e3ebdSchin 
544*da2e3ebdSchin 	/*
545*da2e3ebdSchin 	 * loop on the index and copy the non-ignored chunks to the output
546*da2e3ebdSchin 	 */
547*da2e3ebdSchin 
548*da2e3ebdSchin 	ppcheckout();
549*da2e3ebdSchin 	p = PPBUFSIZ - (pp.outp - pp.outbuf);
550*da2e3ebdSchin 	keep_begin = 0;
551*da2e3ebdSchin 	keep_end = 0;
552*da2e3ebdSchin 	skip_end = 0;
553*da2e3ebdSchin 	while (*b)
554*da2e3ebdSchin 	{
555*da2e3ebdSchin 		fp = ppsetfile(b);
556*da2e3ebdSchin 		while (*b++);
557*da2e3ebdSchin 		g = b;
558*da2e3ebdSchin 		while (*b++);
559*da2e3ebdSchin 		next_begin = strtol(b, &t, 10);
560*da2e3ebdSchin 		next_end = strtol(t + 1, &t, 10);
561*da2e3ebdSchin if (pp.test & 0x0200) error(2, "%s: %s p=%lu next=<%lu,%lu> keep=<%lu,%lu> skip=<-,%lu> guard=%s", keyname(X_CHECKPOINT), fp->name, p, next_begin, next_end, keep_begin, keep_end, skip_end, fp->guard == INC_CLEAR ? "[CLEAR]" : fp->guard == INC_TEST ? "[TEST]" : fp->guard == INC_IGNORE ? "[IGNORE]" : fp->guard->name);
562*da2e3ebdSchin 		b = t + 1;
563*da2e3ebdSchin 		if (next_begin >= skip_end)
564*da2e3ebdSchin 		{
565*da2e3ebdSchin 			if (!ppmultiple(fp, INC_TEST))
566*da2e3ebdSchin 			{
567*da2e3ebdSchin if (pp.test & 0x0100) error(2, "%s: %s IGNORE", keyname(X_CHECKPOINT), fp->name);
568*da2e3ebdSchin 				if (!keep_begin && skip_end < next_begin)
569*da2e3ebdSchin 					keep_begin = skip_end;
570*da2e3ebdSchin 				if (keep_begin)
571*da2e3ebdSchin 				{
572*da2e3ebdSchin 				flush:
573*da2e3ebdSchin 					if (sfseek(sp, file_offset + keep_begin, SEEK_SET) != file_offset + keep_begin)
574*da2e3ebdSchin 						error(3, "checkpoint data seek error");
575*da2e3ebdSchin 					n = next_begin - keep_begin;
576*da2e3ebdSchin if (pp.test & 0x0100) error(2, "%s: copy <%lu,%lu> n=%lu p=%lu", keyname(X_CHECKPOINT), keep_begin, next_begin - 1, n, p);
577*da2e3ebdSchin 					while (n > p)
578*da2e3ebdSchin 					{
579*da2e3ebdSchin 						if (sfread(sp, pp.outp, p) != p)
580*da2e3ebdSchin 							error(3, "checkpoint data read error");
581*da2e3ebdSchin 						PPWRITE(PPBUFSIZ);
582*da2e3ebdSchin 						pp.outp = pp.outbuf;
583*da2e3ebdSchin 						n -= p;
584*da2e3ebdSchin 						p = PPBUFSIZ;
585*da2e3ebdSchin 					}
586*da2e3ebdSchin 					if (n)
587*da2e3ebdSchin 					{
588*da2e3ebdSchin 						if (sfread(sp, pp.outp, n) != n)
589*da2e3ebdSchin 							error(3, "checkpoint data read error");
590*da2e3ebdSchin 						pp.outp += n;
591*da2e3ebdSchin 						p -= n;
592*da2e3ebdSchin 					}
593*da2e3ebdSchin 					keep_begin = 0;
594*da2e3ebdSchin 					if (keep_end <= next_end)
595*da2e3ebdSchin 						keep_end = 0;
596*da2e3ebdSchin 				}
597*da2e3ebdSchin 				skip_end = next_end;
598*da2e3ebdSchin 			}
599*da2e3ebdSchin 			else if (!keep_begin)
600*da2e3ebdSchin 			{
601*da2e3ebdSchin 				if (skip_end)
602*da2e3ebdSchin 				{
603*da2e3ebdSchin 					keep_begin = skip_end;
604*da2e3ebdSchin 					skip_end = 0;
605*da2e3ebdSchin 				}
606*da2e3ebdSchin 				else keep_begin = next_begin;
607*da2e3ebdSchin 				if (keep_end < next_end)
608*da2e3ebdSchin 					keep_end = next_end;
609*da2e3ebdSchin 			}
610*da2e3ebdSchin 		}
611*da2e3ebdSchin 		if (*g && fp->guard != INC_IGNORE)
612*da2e3ebdSchin 			fp->guard = ppsymset(pp.symtab, g);
613*da2e3ebdSchin 	}
614*da2e3ebdSchin 	if (keep_end)
615*da2e3ebdSchin 	{
616*da2e3ebdSchin 		if (!keep_begin)
617*da2e3ebdSchin 			keep_begin = skip_end > next_end ? skip_end : next_end;
618*da2e3ebdSchin 		next_begin = next_end = keep_end;
619*da2e3ebdSchin 		g = b;
620*da2e3ebdSchin 		goto flush;
621*da2e3ebdSchin 	}
622*da2e3ebdSchin if (pp.test & 0x0100) error(2, "%s: loop", keyname(X_CHECKPOINT));
623*da2e3ebdSchin 
624*da2e3ebdSchin 	/*
625*da2e3ebdSchin 	 * read the compacted definitions
626*da2e3ebdSchin 	 */
627*da2e3ebdSchin 
628*da2e3ebdSchin 	if (sfseek(sp, macro_offset, SEEK_SET) != macro_offset)
629*da2e3ebdSchin 		error(3, "checkpoint macro seek error");
630*da2e3ebdSchin 	if (!(s = sfreserve(sp, index_offset - macro_offset, 0)))
631*da2e3ebdSchin 		error(3, "checkpoint macro read error");
632*da2e3ebdSchin 
633*da2e3ebdSchin 	/*
634*da2e3ebdSchin 	 * read the flags
635*da2e3ebdSchin 	 */
636*da2e3ebdSchin 
637*da2e3ebdSchin 	while (*s)
638*da2e3ebdSchin 	{
639*da2e3ebdSchin #if _options_dumped_
640*da2e3ebdSchin 		if (streq(s, "OPTION")) /* ... */;
641*da2e3ebdSchin 		else
642*da2e3ebdSchin #endif
643*da2e3ebdSchin 		error(3, "%-.48s: unknown flags in checkpoint file", s);
644*da2e3ebdSchin 	}
645*da2e3ebdSchin 	s++;
646*da2e3ebdSchin 
647*da2e3ebdSchin 	/*
648*da2e3ebdSchin 	 * unpack and enter the definitions
649*da2e3ebdSchin 	 */
650*da2e3ebdSchin 
651*da2e3ebdSchin 	while (*s)
652*da2e3ebdSchin 	{
653*da2e3ebdSchin 		b = s;
654*da2e3ebdSchin 		while (*s++);
655*da2e3ebdSchin 		m = *s++;
656*da2e3ebdSchin 		sym = ppsymset(pp.symtab, b);
657*da2e3ebdSchin 		if (sym->macro)
658*da2e3ebdSchin 		{
659*da2e3ebdSchin 			if (m & LOAD_FUNCTION)
660*da2e3ebdSchin 			{
661*da2e3ebdSchin 				if (*s++ != '0')
662*da2e3ebdSchin 					while (*s++);
663*da2e3ebdSchin 				while (*s++);
664*da2e3ebdSchin 			}
665*da2e3ebdSchin if (pp.test & 0x1000) error(2, "checkpoint SKIP %s=%s [%s]", sym->name, s, sym->macro->value);
666*da2e3ebdSchin 			while (*s++);
667*da2e3ebdSchin 		}
668*da2e3ebdSchin 		else
669*da2e3ebdSchin 		{
670*da2e3ebdSchin 			ppfsm(FSM_MACRO, b);
671*da2e3ebdSchin 			sym->flags = 0;
672*da2e3ebdSchin 			if (m & LOAD_FUNCTION) sym->flags |= SYM_FUNCTION;
673*da2e3ebdSchin 			if (m & LOAD_MULTILINE) sym->flags |= SYM_MULTILINE;
674*da2e3ebdSchin 			if (m & LOAD_NOEXPAND) sym->flags |= SYM_NOEXPAND;
675*da2e3ebdSchin 			if (m & LOAD_PREDICATE) sym->flags |= SYM_PREDICATE;
676*da2e3ebdSchin 			if (m & LOAD_READONLY) sym->flags |= SYM_READONLY;
677*da2e3ebdSchin 			if (m & LOAD_VARIADIC) sym->flags |= SYM_VARIADIC;
678*da2e3ebdSchin 			mac = sym->macro = newof(0, struct ppmacro, 1, 0);
679*da2e3ebdSchin 			if (sym->flags & SYM_FUNCTION)
680*da2e3ebdSchin 			{
681*da2e3ebdSchin 				for (n = 0; *s >= '0' && *s <= '9'; n = n * 10 + *s++ - '0');
682*da2e3ebdSchin 				if (*s++) error(3, "%-.48: checkpoint macro arity botched", sym->name);
683*da2e3ebdSchin 				if (mac->arity = n)
684*da2e3ebdSchin 				{
685*da2e3ebdSchin 					b = s;
686*da2e3ebdSchin 					while (*s++);
687*da2e3ebdSchin 					mac->formals = (char*)memcpy(oldof(0, char, 0, s - b), b, s - b);
688*da2e3ebdSchin 				}
689*da2e3ebdSchin 			}
690*da2e3ebdSchin 			b = s;
691*da2e3ebdSchin 			while (*s++);
692*da2e3ebdSchin 			mac->size = s - b - 1;
693*da2e3ebdSchin 			mac->value = (char*)memcpy(oldof(0, char, 0, mac->size + 1), b, mac->size + 1);
694*da2e3ebdSchin if (pp.test & 0x1000) error(2, "checkpoint LOAD %s=%s", sym->name, mac->value);
695*da2e3ebdSchin 		}
696*da2e3ebdSchin 	}
697*da2e3ebdSchin 
698*da2e3ebdSchin 	/*
699*da2e3ebdSchin 	 * we are now at EOF
700*da2e3ebdSchin 	 */
701*da2e3ebdSchin 
702*da2e3ebdSchin 	if (ip)
703*da2e3ebdSchin 	{
704*da2e3ebdSchin 		pp.in->fd = -1;
705*da2e3ebdSchin 		free(ip);
706*da2e3ebdSchin 	}
707*da2e3ebdSchin #if ARCHIVE
708*da2e3ebdSchin 	if (pp.member) pp.member = 0;
709*da2e3ebdSchin 	else
710*da2e3ebdSchin #endif
711*da2e3ebdSchin 	{
712*da2e3ebdSchin 		sfclose(sp);
713*da2e3ebdSchin 		pp.in->flags |= IN_eof|IN_newline;
714*da2e3ebdSchin 		pp.in->nextchr = pp.in->buffer + PPBAKSIZ;
715*da2e3ebdSchin 		*pp.in->nextchr++ = 0;
716*da2e3ebdSchin 		*pp.in->nextchr = 0;
717*da2e3ebdSchin 	}
718*da2e3ebdSchin 	pp.mode &= ~LOADING;
719*da2e3ebdSchin }
720*da2e3ebdSchin 
721*da2e3ebdSchin #endif
722