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