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