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