14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1986-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * Glenn Fowler
234887Schin  * AT&T Research
244887Schin  *
254887Schin  * preprocessor stacked input stream support
264887Schin  */
274887Schin 
284887Schin #include "pplib.h"
294887Schin 
304887Schin 
314887Schin /*
324887Schin  * convert path to native representation
334887Schin  */
344887Schin 
354887Schin #if 0
364887Schin #include "../../lib/libast/path/pathnative.c" /* drop in 2002 */
374887Schin #else
384887Schin /* Modified by gisburn 2006-08-18 for OpenSolaris ksh93-integration */
394887Schin #include "../../libast/common/path/pathnative.c"
404887Schin #endif
414887Schin 
424887Schin static char*
434887Schin native(register const char* s)
444887Schin {
454887Schin 	register int		c;
464887Schin 	register struct ppfile* xp;
474887Schin 	int			m;
484887Schin 	int			n;
494887Schin 
504887Schin 	static Sfio_t*		np;
514887Schin 	static Sfio_t*		qp;
524887Schin 
534887Schin 	if (!s)
544887Schin 		return 0;
554887Schin 	if (!np && !(np = sfstropen()) || !qp && !(qp = sfstropen()))
564887Schin 		return (char*)s;
574887Schin 	n = PATH_MAX;
584887Schin 	do
594887Schin 	{
604887Schin 		m = n;
614887Schin 		n = pathnative(s, sfstrrsrv(np, m), m);
624887Schin 	} while (n > m);
634887Schin 	sfstrseek(np, n, SEEK_CUR);
644887Schin 	s = (const char*)sfstruse(np);
654887Schin 	for (;;)
664887Schin 	{
674887Schin 		switch (c = *s++)
684887Schin 		{
694887Schin 		case 0:
704887Schin 			break;
714887Schin 		case '\\':
724887Schin 		case '"':
734887Schin 			sfputc(qp, '\\');
744887Schin 			/*FALLTHROUGH*/
754887Schin 		default:
764887Schin 			sfputc(qp, c);
774887Schin 			continue;
784887Schin 		}
794887Schin 		break;
804887Schin 	}
814887Schin 	if (!(xp = ppsetfile(sfstruse(qp))))
824887Schin 		return (char*)s;
834887Schin 	return xp->name;
844887Schin }
854887Schin 
864887Schin /*
874887Schin  * push stream onto input stack
884887Schin  * used by the PUSH_type macros
894887Schin  */
904887Schin 
914887Schin void
924887Schin pppush(register int t, register char* s, register char* p, int n)
934887Schin {
944887Schin 	register struct ppinstk*	cur;
954887Schin 
964887Schin 	PUSH(t, cur);
974887Schin 	cur->line = error_info.line;
984887Schin 	cur->file = error_info.file;
994887Schin 	switch (t)
1004887Schin 	{
1014887Schin 	case IN_FILE:
1024887Schin 		if (pp.option & NATIVE)
1034887Schin 			s = native(s);
1044887Schin 		cur->flags |= IN_newline;
1054887Schin 		cur->fd = n;
1064887Schin 		cur->hide = ++pp.hide;
1074887Schin 		cur->symbol = 0;
1084887Schin #if CHECKPOINT
1094887Schin 		if ((pp.mode & (DUMP|INIT)) == DUMP)
1104887Schin 		{
1114887Schin 			cur->index = newof(0, struct ppindex, 1, 0);
1124887Schin 			if (pp.lastindex) pp.lastindex->next = cur->index;
1134887Schin 			else pp.firstindex = cur->index;
1144887Schin 			pp.lastindex = cur->index;
1154887Schin 			cur->index->file = pp.original;
1164887Schin 			cur->index->begin = ppoffset();
1174887Schin 		}
1184887Schin #endif
1194887Schin 		n = 1;
1204887Schin #if CHECKPOINT
1214887Schin 		if (!(pp.mode & DUMP))
1224887Schin #endif
1234887Schin 		if (!cur->prev->prev && !(pp.state & COMPILE) && isatty(0))
1244887Schin 			cur->flags |= IN_flush;
1254887Schin #if ARCHIVE
1264887Schin 		if (pp.member)
1274887Schin 		{
1284887Schin 			switch (pp.member->archive->type & (TYPE_BUFFER|TYPE_CHECKPOINT))
1294887Schin 			{
1304887Schin 			case 0:
1314887Schin #if CHECKPOINT
1324887Schin 				cur->buflen = pp.member->size;
1334887Schin #endif
1344887Schin 				p = (cur->buffer = oldof(0, char, 0, pp.member->size + PPBAKSIZ + 1)) + PPBAKSIZ;
1354887Schin 				if (sfseek(pp.member->archive->info.sp, pp.member->offset, SEEK_SET) != pp.member->offset)
1364887Schin 					error(3, "%s: archive seek error", pp.member->archive->name);
1374887Schin 				if (sfread(pp.member->archive->info.sp, p, pp.member->size) != pp.member->size)
1384887Schin 					error(3, "%s: archive read error", pp.member->archive->name);
1394887Schin 				pp.member = 0;
1404887Schin 				break;
1414887Schin 			case TYPE_BUFFER:
1424887Schin #if CHECKPOINT
1434887Schin 			case TYPE_CHECKPOINT|TYPE_BUFFER:
1444887Schin 				cur->buflen = pp.member->size;
1454887Schin #endif
1464887Schin 				p = cur->buffer = pp.member->archive->info.buffer + pp.member->offset;
1474887Schin 				cur->flags |= IN_static;
1484887Schin 				pp.member = 0;
1494887Schin 				break;
1504887Schin #if CHECKPOINT
1514887Schin 			case TYPE_CHECKPOINT:
1524887Schin 				p = cur->buffer = "";
1534887Schin 				cur->flags |= IN_static;
1544887Schin 				break;
1554887Schin #endif
1564887Schin 			}
1574887Schin 			cur->flags |= IN_eof|IN_newline;
1584887Schin 			cur->fd = -1;
1594887Schin 		}
1604887Schin 		else
1614887Schin #endif
1624887Schin 		{
1634887Schin 			if (lseek(cur->fd, 0L, SEEK_END) > 0 && !lseek(cur->fd, 0L, SEEK_SET))
1644887Schin 				cur->flags |= IN_regular;
1654887Schin 			errno = 0;
1664887Schin #if PROTOTYPE
1674887Schin 			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))))
1684887Schin 			{
1694887Schin 				*(p = cur->buffer - 1) = 0;
1704887Schin 				cur->buffer -= PPBAKSIZ;
1714887Schin 				cur->flags |= IN_prototype;
1724887Schin 				cur->fd = -1;
1734887Schin 			}
1744887Schin 			else
1754887Schin #endif
1764887Schin 			*(p = (cur->buffer = oldof(0, char, 0, PPBUFSIZ + PPBAKSIZ + 1)) + PPBAKSIZ) = 0;
1774887Schin 		}
1784887Schin 		if (pp.incref && !(pp.mode & INIT))
1794887Schin 			(*pp.incref)(error_info.file, s, error_info.line - 1, PP_SYNC_PUSH);
1804887Schin 		if (pp.macref || (pp.option & IGNORELINE))
1814887Schin 			cur->flags |= IN_ignoreline;
1824887Schin 		cur->prefix = pp.prefix;
1834887Schin 		/*FALLTHROUGH*/
1844887Schin 	case IN_BUFFER:
1854887Schin 	case IN_INIT:
1864887Schin 	case IN_RESCAN:
1874887Schin 		pushcontrol();
1884887Schin 		cur->control = pp.control;
1894887Schin 		*pp.control = 0;
1904887Schin 		cur->vendor = pp.vendor;
1914887Schin 		if (cur->type != IN_RESCAN)
1924887Schin 		{
1934887Schin 			if (cur->type == IN_INIT)
1944887Schin 				pp.mode |= MARKHOSTED;
1954887Schin 			error_info.file = s;
1964887Schin 			error_info.line = n;
1974887Schin 		}
1984887Schin 		if (pp.state & HIDDEN)
1994887Schin 		{
2004887Schin 			pp.state &= ~HIDDEN;
2014887Schin 			pp.hidden = 0;
2024887Schin 			if (!(pp.state & NOTEXT) && pplastout() != '\n')
2034887Schin 				ppputchar('\n');
2044887Schin 		}
2054887Schin 		pp.state |= NEWLINE;
2064887Schin 		if (pp.mode & HOSTED) cur->flags |= IN_hosted;
2074887Schin 		else cur->flags &= ~IN_hosted;
2084887Schin 		if (pp.mode & (INIT|MARKHOSTED))
2094887Schin 		{
2104887Schin 			pp.mode |= HOSTED;
2114887Schin 			pp.flags |= PP_hosted;
2124887Schin 		}
2134887Schin 		switch (cur->type)
2144887Schin 		{
2154887Schin 		case IN_FILE:
2164887Schin 			if (!(pp.mode & (INIT|MARKHOSTED)))
2174887Schin 			{
2184887Schin 				pp.mode &= ~HOSTED;
2194887Schin 				pp.flags &= ~PP_hosted;
2204887Schin 			}
2214887Schin #if CATSTRINGS
2224887Schin 			if (pp.state & JOINING) pp.state |= HIDDEN|SYNCLINE;
2234887Schin 			else
2244887Schin #endif
2254887Schin 			if (pp.linesync)
2264887Schin 				(*pp.linesync)(error_info.line, error_info.file);
2274887Schin #if ARCHIVE && CHECKPOINT
2284887Schin 			if (pp.member)
2294887Schin 				ppload(NiL);
2304887Schin #endif
2314887Schin 			if (pp.mode & MARKC)
2324887Schin 			{
2334887Schin 				cur->flags |= IN_c;
2344887Schin 				pp.mode &= ~MARKC;
2354887Schin 				if (!(cur->prev->flags & IN_c))
2364887Schin 				{
2374887Schin 					debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr));
2384887Schin 					PUSH_BUFFER("C", "extern \"C\" {\n", 1);
2394887Schin 					return;
2404887Schin 				}
2414887Schin 			}
2424887Schin 			else if (cur->prev->flags & IN_c)
2434887Schin 			{
2444887Schin 				debug((-7, "PUSH in=%s next=%s [%s]", ppinstr(pp.in), pptokchr(*pp.in->nextchr), pp.in->nextchr));
2454887Schin 				PUSH_BUFFER("C", "extern \"C++\" {\n", 1);
2464887Schin 				return;
2474887Schin 			}
2484887Schin 			break;
2494887Schin 		case IN_BUFFER:
2504887Schin 			cur->buffer = p = strdup(p);
2514887Schin 			break;
2524887Schin 		default:
2534887Schin 			cur->buffer = p;
2544887Schin 			break;
2554887Schin 		}
2564887Schin 		cur->nextchr = p;
2574887Schin 		break;
2584887Schin #if DEBUG
2594887Schin 	default:
2604887Schin 		error(PANIC, "use PUSH_<%d>(...) instead of pppush(IN_<%d>, ...)", cur->type, cur->type);
2614887Schin 		break;
2624887Schin #endif
2634887Schin 	}
2644887Schin 	debug((-7, "PUSH in=%s next=%s", ppinstr(pp.in), pptokchr(*pp.in->nextchr)));
2654887Schin }
2664887Schin 
2674887Schin /*
2684887Schin  * external buffer push
2694887Schin  */
2704887Schin 
2714887Schin void
2724887Schin ppinput(char* b, char* f, int n)
2734887Schin {
2744887Schin 	PUSH_BUFFER(f, b, n);
2754887Schin }
2764887Schin 
2774887Schin /*
2784887Schin  * return expanded value of buffer p
2794887Schin  */
2804887Schin 
2814887Schin char*
2824887Schin ppexpand(register char* p)
2834887Schin {
2844887Schin 	register char*		m;
2854887Schin 	register int		n;
2864887Schin 	register int		c;
2874887Schin 	long			restore;
2884887Schin 	char*			pptoken;
2894887Schin 	char*			ppmactop;
2904887Schin 	struct ppmacstk*	nextmacp;
2914887Schin 	struct ppinstk*		cur;
2924887Schin 
2934887Schin 	debug((-7, "before expand: %s", p));
2944887Schin 	if (ppmactop = pp.mactop)
2954887Schin 	{
2964887Schin 		nextmacp = pp.macp->next;
2974887Schin 		nextframe(pp.macp, pp.mactop);
2984887Schin 	}
2994887Schin 	restore = pp.state & (COLLECTING|DISABLE|STRIP);
3004887Schin 	pp.state &= ~restore;
3014887Schin 	pp.mode &= ~MARKMACRO;
3024887Schin 	PUSH_STRING(p);
3034887Schin 	cur = pp.in;
3044887Schin 	pp.in->flags |= IN_expand;
3054887Schin 	pptoken = pp.token;
3064887Schin 	n = 2 * MAXTOKEN;
3074887Schin 	pp.token = p = oldof(0, char, 0, n);
3084887Schin 	m = p + MAXTOKEN;
3094887Schin 	for (;;)
3104887Schin 	{
3114887Schin 		if (pplex())
3124887Schin 		{
3134887Schin 			if ((pp.token = pp.toknxt) > m)
3144887Schin 			{
3154887Schin 				c = pp.token - p;
3164887Schin 				p = newof(p, char, n += MAXTOKEN, 0);
3174887Schin 				m = p + n - MAXTOKEN;
3184887Schin 				pp.token = p + c;
3194887Schin 			}
3204887Schin 			if (pp.mode & MARKMACRO)
3214887Schin 			{
3224887Schin 				pp.mode &= ~MARKMACRO;
3234887Schin 				*pp.token++ = MARK;
3244887Schin 				*pp.token++ = 'X';
3254887Schin 			}
3264887Schin 		}
3274887Schin 		else if (pp.in == cur)
3284887Schin 			break;
3294887Schin 	}
3304887Schin 	*pp.token = 0;
3314887Schin 	if (ppmactop)
3324887Schin 		pp.macp->next = nextmacp;
3334887Schin 	debug((-7, "after expand: %s", p));
3344887Schin 	pp.token = pptoken;
3354887Schin 	pp.state |= restore;
3364887Schin 	pp.in = pp.in->prev;
3374887Schin 	return p;
3384887Schin }
3394887Schin 
3404887Schin #if CHECKPOINT
3414887Schin 
3424887Schin #define LOAD_FUNCTION	(1<<0)
3434887Schin #define LOAD_MULTILINE	(1<<1)
3444887Schin #define LOAD_NOEXPAND	(1<<2)
3454887Schin #define LOAD_PREDICATE	(1<<3)
3464887Schin #define LOAD_READONLY	(1<<4)
3474887Schin #define LOAD_VARIADIC	(1<<5)
3484887Schin 
3494887Schin /*
3504887Schin  * macro definition dump
3514887Schin  */
3524887Schin 
3534887Schin static int
3544887Schin dump(const char* name, char* v, void* handle)
3554887Schin {
3564887Schin 	register struct ppmacro*	mac;
3574887Schin 	register struct ppsymbol*	sym = (struct ppsymbol*)v;
3584887Schin 	register int			flags;
3594887Schin 
3604887Schin 	NoP(name);
3614887Schin 	NoP(handle);
3624887Schin 	if ((mac = sym->macro) && !(sym->flags & (SYM_BUILTIN|SYM_PREDEFINED)))
3634887Schin 	{
3644887Schin 		ppprintf("%s", sym->name);
3654887Schin 		ppputchar(0);
3664887Schin 		flags = 0;
3674887Schin 		if (sym->flags & SYM_FUNCTION) flags |= LOAD_FUNCTION;
3684887Schin 		if (sym->flags & SYM_MULTILINE) flags |= LOAD_MULTILINE;
3694887Schin 		if (sym->flags & SYM_NOEXPAND) flags |= LOAD_NOEXPAND;
3704887Schin 		if (sym->flags & SYM_PREDICATE) flags |= LOAD_PREDICATE;
3714887Schin 		if (sym->flags & SYM_READONLY) flags |= LOAD_READONLY;
3724887Schin 		if (sym->flags & SYM_VARIADIC) flags |= LOAD_VARIADIC;
3734887Schin 		ppputchar(flags);
3744887Schin 		if (sym->flags & SYM_FUNCTION)
3754887Schin 		{
3764887Schin 			ppprintf("%d", mac->arity);
3774887Schin 			ppputchar(0);
3784887Schin 			if (mac->arity)
3794887Schin 			{
3804887Schin 				ppprintf("%s", mac->formals);
3814887Schin 				ppputchar(0);
3824887Schin 			}
3834887Schin 		}
3844887Schin 		ppprintf("%s", mac->value);
3854887Schin 		ppputchar(0);
3864887Schin 	}
3874887Schin 	return(0);
3884887Schin }
3894887Schin 
3904887Schin /*
3914887Schin  * dump macro definitions for quick loading via ppload()
3924887Schin  */
3934887Schin 
3944887Schin void
3954887Schin ppdump(void)
3964887Schin {
3974887Schin 	register struct ppindex*	ip;
3984887Schin 	unsigned long			macro_offset;
3994887Schin 	unsigned long			index_offset;
4004887Schin 
4014887Schin 	/*
4024887Schin 	 * NOTE: we assume '\0' does not occur in valid preprocessed output
4034887Schin 	 */
4044887Schin 
4054887Schin 	ppputchar(0);
4064887Schin 
4074887Schin 	/*
4084887Schin 	 * output global flags
4094887Schin 	 */
4104887Schin 
4114887Schin 	macro_offset = ppoffset();
4124887Schin 	ppputchar(0);
4134887Schin 
4144887Schin 	/*
4154887Schin 	 * output macro definitions
4164887Schin 	 */
4174887Schin 
4184887Schin 	hashwalk(pp.symtab, 0, dump, NiL);
4194887Schin 	ppputchar(0);
4204887Schin 
4214887Schin 	/*
4224887Schin 	 * output include file index
4234887Schin 	 */
4244887Schin 
4254887Schin 	index_offset = ppoffset();
4264887Schin 	ip = pp.firstindex;
4274887Schin 	while (ip)
4284887Schin 	{
4294887Schin 		ppprintf("%s", ip->file->name);
4304887Schin 		ppputchar(0);
4314887Schin 		if (ip->file->guard != INC_CLEAR && ip->file->guard != INC_IGNORE && ip->file->guard != INC_TEST)
4324887Schin 			ppprintf("%s", ip->file->guard->name);
4334887Schin 		ppputchar(0);
4344887Schin 		ppprintf("%lu", ip->begin);
4354887Schin 		ppputchar(0);
4364887Schin 		ppprintf("%lu", ip->end);
4374887Schin 		ppputchar(0);
4384887Schin 		ip = ip->next;
4394887Schin 	}
4404887Schin 	ppputchar(0);
4414887Schin 
4424887Schin 	/*
4434887Schin 	 * output offset directory
4444887Schin 	 */
4454887Schin 
4464887Schin 	ppprintf("%010lu", macro_offset);
4474887Schin 	ppputchar(0);
4484887Schin 	ppprintf("%010lu", index_offset);
4494887Schin 	ppputchar(0);
4504887Schin 	ppflushout();
4514887Schin }
4524887Schin 
4534887Schin /*
4544887Schin  * load text and macro definitions from a previous ppdump()
4554887Schin  * s is the string argument from the pragma (including quotes)
4564887Schin  */
4574887Schin 
4584887Schin void
4594887Schin ppload(register char* s)
4604887Schin {
4614887Schin 	register char*		b;
4624887Schin 	register Sfio_t*	sp;
4634887Schin 	int			m;
4644887Schin 	char*			g;
4654887Schin 	char*			t;
4664887Schin 	unsigned long		n;
4674887Schin 	unsigned long		p;
4684887Schin 	unsigned long		macro_offset;
4694887Schin 	unsigned long		index_offset;
4704887Schin 	unsigned long		file_offset;
4714887Schin 	unsigned long		file_size;
4724887Schin 	unsigned long		keep_begin;
4734887Schin 	unsigned long		keep_end;
4744887Schin 	unsigned long		skip_end;
4754887Schin 	unsigned long		next_begin;
4764887Schin 	unsigned long		next_end;
4774887Schin 	struct ppfile*		fp;
4784887Schin 	struct ppsymbol*	sym;
4794887Schin 	struct ppmacro*		mac;
4804887Schin 
4814887Schin 	char*			ip = 0;
4824887Schin 
4834887Schin 	pp.mode |= LOADING;
4844887Schin 	if (!(pp.state & STANDALONE))
4854887Schin 		error(3, "checkpoint load in standalone mode only");
4864887Schin #if ARCHIVE
4874887Schin 	if (pp.member)
4884887Schin 	{
4894887Schin 		sp = pp.member->archive->info.sp;
4904887Schin 		file_offset = pp.member->offset;
4914887Schin 		file_size = pp.member->size;
4924887Schin 		if (sfseek(sp, file_offset + 22, SEEK_SET) != file_offset + 22 || !(s = sfgetr(sp, '\n', 1)))
4934887Schin 			error(3, "checkpoint magic error");
4944887Schin 	}
4954887Schin 	else
4964887Schin #endif
4974887Schin 	{
4984887Schin 		if (pp.in->type != IN_FILE)
4994887Schin 			error(3, "checkpoint load from files only");
5004887Schin 		if (pp.in->flags & IN_prototype)
5014887Schin 			pp.in->fd = pppdrop(pp.in->buffer + PPBAKSIZ);
5024887Schin 		file_offset = 0;
5034887Schin 		if (pp.in->fd >= 0)
5044887Schin 		{
5054887Schin 			if (!(sp = sfnew(NiL, NiL, SF_UNBOUND, pp.in->fd, SF_READ)))
5064887Schin 				error(3, "checkpoint read error");
5074887Schin 			file_size = sfseek(sp, 0L, SEEK_END);
5084887Schin 		}
5094887Schin 		else
5104887Schin 		{
5114887Schin 			file_size = pp.in->buflen;
5124887Schin 			if (!(sp = sfnew(NiL, pp.in->buffer + ((pp.in->flags & IN_static) ? 0 : PPBAKSIZ), file_size, -1, SF_READ|SF_STRING)))
5134887Schin 				error(3, "checkpoint read error");
5144887Schin 		}
5154887Schin 	}
5164887Schin 	if (!streq(s, pp.checkpoint))
5174887Schin 		error(3, "checkpoint version %s does not match %s", s, pp.checkpoint);
5184887Schin 
5194887Schin 	/*
5204887Schin 	 * get the macro and index offsets
5214887Schin 	 */
5224887Schin 
5234887Schin 	p = file_offset + file_size - 22;
5244887Schin 	if ((n = sfseek(sp, p, SEEK_SET)) != p)
5254887Schin 		error(3, "checkpoint directory seek error");
5264887Schin 	if (!(t = sfreserve(sp, 22, 0)))
5274887Schin 		error(3, "checkpoint directory read error");
5284887Schin 	macro_offset = file_offset + strtol(t, &t, 10);
5294887Schin 	index_offset = file_offset + strtol(t + 1, NiL, 10);
5304887Schin 
5314887Schin 	/*
5324887Schin 	 * read the include index
5334887Schin 	 */
5344887Schin 
5354887Schin 	if (sfseek(sp, index_offset, SEEK_SET) != index_offset)
5364887Schin 		error(3, "checkpoint index seek error");
5374887Schin 	if (!(s = sfreserve(sp, n - index_offset, 0)))
5384887Schin 		error(3, "checkpoint index read error");
5394887Schin 	if (sfset(sp, 0, 0) & SF_STRING)
5404887Schin 		b = s;
5414887Schin 	else if (!(b = ip = memdup(s, n - index_offset)))
5424887Schin 		error(3, "checkpoint index alloc error");
5434887Schin 
5444887Schin 	/*
5454887Schin 	 * loop on the index and copy the non-ignored chunks to the output
5464887Schin 	 */
5474887Schin 
5484887Schin 	ppcheckout();
5494887Schin 	p = PPBUFSIZ - (pp.outp - pp.outbuf);
5504887Schin 	keep_begin = 0;
5514887Schin 	keep_end = 0;
5524887Schin 	skip_end = 0;
5534887Schin 	while (*b)
5544887Schin 	{
5554887Schin 		fp = ppsetfile(b);
5564887Schin 		while (*b++);
5574887Schin 		g = b;
5584887Schin 		while (*b++);
5594887Schin 		next_begin = strtol(b, &t, 10);
5604887Schin 		next_end = strtol(t + 1, &t, 10);
5614887Schin 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);
5624887Schin 		b = t + 1;
5634887Schin 		if (next_begin >= skip_end)
5644887Schin 		{
5654887Schin 			if (!ppmultiple(fp, INC_TEST))
5664887Schin 			{
5674887Schin if (pp.test & 0x0100) error(2, "%s: %s IGNORE", keyname(X_CHECKPOINT), fp->name);
5684887Schin 				if (!keep_begin && skip_end < next_begin)
5694887Schin 					keep_begin = skip_end;
5704887Schin 				if (keep_begin)
5714887Schin 				{
5724887Schin 				flush:
5734887Schin 					if (sfseek(sp, file_offset + keep_begin, SEEK_SET) != file_offset + keep_begin)
5744887Schin 						error(3, "checkpoint data seek error");
5754887Schin 					n = next_begin - keep_begin;
5764887Schin if (pp.test & 0x0100) error(2, "%s: copy <%lu,%lu> n=%lu p=%lu", keyname(X_CHECKPOINT), keep_begin, next_begin - 1, n, p);
5774887Schin 					while (n > p)
5784887Schin 					{
5794887Schin 						if (sfread(sp, pp.outp, p) != p)
5804887Schin 							error(3, "checkpoint data read error");
5814887Schin 						PPWRITE(PPBUFSIZ);
5824887Schin 						pp.outp = pp.outbuf;
5834887Schin 						n -= p;
5844887Schin 						p = PPBUFSIZ;
5854887Schin 					}
5864887Schin 					if (n)
5874887Schin 					{
5884887Schin 						if (sfread(sp, pp.outp, n) != n)
5894887Schin 							error(3, "checkpoint data read error");
5904887Schin 						pp.outp += n;
5914887Schin 						p -= n;
5924887Schin 					}
5934887Schin 					keep_begin = 0;
5944887Schin 					if (keep_end <= next_end)
5954887Schin 						keep_end = 0;
5964887Schin 				}
5974887Schin 				skip_end = next_end;
5984887Schin 			}
5994887Schin 			else if (!keep_begin)
6004887Schin 			{
6014887Schin 				if (skip_end)
6024887Schin 				{
6034887Schin 					keep_begin = skip_end;
6044887Schin 					skip_end = 0;
6054887Schin 				}
6064887Schin 				else keep_begin = next_begin;
6074887Schin 				if (keep_end < next_end)
6084887Schin 					keep_end = next_end;
6094887Schin 			}
6104887Schin 		}
6114887Schin 		if (*g && fp->guard != INC_IGNORE)
6124887Schin 			fp->guard = ppsymset(pp.symtab, g);
6134887Schin 	}
6144887Schin 	if (keep_end)
6154887Schin 	{
6164887Schin 		if (!keep_begin)
6174887Schin 			keep_begin = skip_end > next_end ? skip_end : next_end;
6184887Schin 		next_begin = next_end = keep_end;
6194887Schin 		g = b;
6204887Schin 		goto flush;
6214887Schin 	}
6224887Schin if (pp.test & 0x0100) error(2, "%s: loop", keyname(X_CHECKPOINT));
6234887Schin 
6244887Schin 	/*
6254887Schin 	 * read the compacted definitions
6264887Schin 	 */
6274887Schin 
6284887Schin 	if (sfseek(sp, macro_offset, SEEK_SET) != macro_offset)
6294887Schin 		error(3, "checkpoint macro seek error");
6304887Schin 	if (!(s = sfreserve(sp, index_offset - macro_offset, 0)))
6314887Schin 		error(3, "checkpoint macro read error");
6324887Schin 
6334887Schin 	/*
6344887Schin 	 * read the flags
6354887Schin 	 */
6364887Schin 
6374887Schin 	while (*s)
6384887Schin 	{
6394887Schin #if _options_dumped_
6404887Schin 		if (streq(s, "OPTION")) /* ... */;
6414887Schin 		else
6424887Schin #endif
6434887Schin 		error(3, "%-.48s: unknown flags in checkpoint file", s);
6444887Schin 	}
6454887Schin 	s++;
6464887Schin 
6474887Schin 	/*
6484887Schin 	 * unpack and enter the definitions
6494887Schin 	 */
6504887Schin 
6514887Schin 	while (*s)
6524887Schin 	{
6534887Schin 		b = s;
6544887Schin 		while (*s++);
6554887Schin 		m = *s++;
6564887Schin 		sym = ppsymset(pp.symtab, b);
6574887Schin 		if (sym->macro)
6584887Schin 		{
6594887Schin 			if (m & LOAD_FUNCTION)
6604887Schin 			{
6614887Schin 				if (*s++ != '0')
6624887Schin 					while (*s++);
6634887Schin 				while (*s++);
6644887Schin 			}
6654887Schin if (pp.test & 0x1000) error(2, "checkpoint SKIP %s=%s [%s]", sym->name, s, sym->macro->value);
6664887Schin 			while (*s++);
6674887Schin 		}
6684887Schin 		else
6694887Schin 		{
6704887Schin 			ppfsm(FSM_MACRO, b);
6714887Schin 			sym->flags = 0;
6724887Schin 			if (m & LOAD_FUNCTION) sym->flags |= SYM_FUNCTION;
6734887Schin 			if (m & LOAD_MULTILINE) sym->flags |= SYM_MULTILINE;
6744887Schin 			if (m & LOAD_NOEXPAND) sym->flags |= SYM_NOEXPAND;
6754887Schin 			if (m & LOAD_PREDICATE) sym->flags |= SYM_PREDICATE;
6764887Schin 			if (m & LOAD_READONLY) sym->flags |= SYM_READONLY;
6774887Schin 			if (m & LOAD_VARIADIC) sym->flags |= SYM_VARIADIC;
6784887Schin 			mac = sym->macro = newof(0, struct ppmacro, 1, 0);
6794887Schin 			if (sym->flags & SYM_FUNCTION)
6804887Schin 			{
6814887Schin 				for (n = 0; *s >= '0' && *s <= '9'; n = n * 10 + *s++ - '0');
6824887Schin 				if (*s++) error(3, "%-.48: checkpoint macro arity botched", sym->name);
6834887Schin 				if (mac->arity = n)
6844887Schin 				{
6854887Schin 					b = s;
6864887Schin 					while (*s++);
6874887Schin 					mac->formals = (char*)memcpy(oldof(0, char, 0, s - b), b, s - b);
6884887Schin 				}
6894887Schin 			}
6904887Schin 			b = s;
6914887Schin 			while (*s++);
6924887Schin 			mac->size = s - b - 1;
6934887Schin 			mac->value = (char*)memcpy(oldof(0, char, 0, mac->size + 1), b, mac->size + 1);
6944887Schin if (pp.test & 0x1000) error(2, "checkpoint LOAD %s=%s", sym->name, mac->value);
6954887Schin 		}
6964887Schin 	}
6974887Schin 
6984887Schin 	/*
6994887Schin 	 * we are now at EOF
7004887Schin 	 */
7014887Schin 
7024887Schin 	if (ip)
7034887Schin 	{
7044887Schin 		pp.in->fd = -1;
7054887Schin 		free(ip);
7064887Schin 	}
7074887Schin #if ARCHIVE
7084887Schin 	if (pp.member) pp.member = 0;
7094887Schin 	else
7104887Schin #endif
7114887Schin 	{
7124887Schin 		sfclose(sp);
7134887Schin 		pp.in->flags |= IN_eof|IN_newline;
7144887Schin 		pp.in->nextchr = pp.in->buffer + PPBAKSIZ;
7154887Schin 		*pp.in->nextchr++ = 0;
7164887Schin 		*pp.in->nextchr = 0;
7174887Schin 	}
7184887Schin 	pp.mode &= ~LOADING;
7194887Schin }
7204887Schin 
7214887Schin #endif
722