Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libpp/ppop.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 library control interface
26
*/
27
28
#include "pplib.h"
29
#include "pptab.h"
30
31
#include <ls.h>
32
33
#define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab)
34
#define REFALL (pp.truncate?pp.dirtab:pp.symtab)
35
36
#define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
37
38
/*
39
* set option value
40
* initialization files have lowest precedence
41
*/
42
43
int
44
ppset(register long* p, register long op, int val)
45
{
46
long* r;
47
48
r = p == &pp.state ? &pp.ro_state : p == &pp.mode ? &pp.ro_mode : &pp.ro_option;
49
if ((pp.mode & INIT) && pp.in->type == IN_FILE && (*r & op))
50
{
51
debug((-7, "set %s %s skipped -- readonly", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r)));
52
return 0;
53
}
54
if (!pp.initialized && (!(pp.mode & INIT) || !(pp.mode & BUILTIN)) && (p != &pp.mode || !(op & BUILTIN)) && (p != &pp.option || !(op & PREDEFINED)))
55
{
56
*r |= op;
57
debug((-7, "set %s %s readonly", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r)));
58
}
59
if (val)
60
*p |= op;
61
else
62
*p &= ~op;
63
debug((-7, "set %s %s", p == &pp.state ? "state" : p == &pp.mode ? "mode" : "option", p == &pp.state ? ppstatestr(*r) : p == &pp.mode ? ppmodestr(*r) : ppoptionstr(*r)));
64
return 1;
65
}
66
67
/*
68
* initialize hash table with keywords from key
69
*/
70
71
static void
72
inithash(register Hash_table_t* tab, register struct ppkeyword* key)
73
{
74
register char* s;
75
76
for (; s = key->name; key++)
77
{
78
if (!ppisid(*s))
79
s++;
80
hashput(tab, s, key->value);
81
}
82
}
83
84
/*
85
* return ppkeyword table name given value
86
*/
87
88
char*
89
ppkeyname(register int value, int dir)
90
{
91
register char* s;
92
register struct ppkeyword* p;
93
94
if (dir && ppiskey(directives, value, p) || !dir && (ppiskey(options, value, p) || ppiskey(predicates, value, p) || ppiskey(variables, value, p)))
95
{
96
s = (p + (value - p->value))->name;
97
return s + !ppisid(*s);
98
}
99
#if DEBUG
100
error(PANIC, "no keyword table name for value=%d", value);
101
#endif
102
return "UNKNOWN";
103
}
104
105
/*
106
* add to the include maps
107
*/
108
109
void
110
ppmapinclude(char* file, register char* s)
111
{
112
register int c;
113
register struct ppdirs* dp;
114
int fd;
115
int flags;
116
int index;
117
int token;
118
char* t;
119
char* old_file;
120
long old_state;
121
struct ppfile* fp;
122
struct ppfile* mp;
123
124
old_file = error_info.file;
125
old_state = pp.state;
126
if (s)
127
PUSH_BUFFER("mapinclude", s, 1);
128
else if (file)
129
{
130
if (*file == '-')
131
{
132
if (!error_info.file)
133
{
134
error(1, "%s: input file name required for %s ignore", file, dirname(INCLUDE));
135
return;
136
}
137
s = t = strcopy(pp.tmpbuf, error_info.file);
138
c = *++file;
139
for (;;)
140
{
141
if (s <= pp.tmpbuf || *s == '/')
142
{
143
s = t;
144
break;
145
}
146
else if (*s == c)
147
break;
148
s--;
149
}
150
strcpy(s, file);
151
file = pp.tmpbuf;
152
}
153
if ((fd = ppsearch(file, INC_LOCAL, SEARCH_INCLUDE)) < 0)
154
return;
155
PUSH_FILE(file, fd);
156
}
157
else
158
return;
159
#if CATSTRINGS
160
pp.state |= (COMPILE|FILEPOP|HEADER|JOINING|STRIP|NOSPACE|PASSEOF);
161
#else
162
pp.state |= (COMPILE|FILEPOP|HEADER|STRIP|NOSPACE|PASSEOF);
163
#endif
164
pp.level++;
165
flags = INC_MAPALL;
166
fp = mp = 0;
167
for (;;)
168
{
169
switch (token = pplex())
170
{
171
case 0:
172
case T_STRING:
173
case T_HEADER:
174
if (fp)
175
{
176
fp->guard = INC_IGNORE;
177
for (dp = pp.firstdir->next; dp; dp = dp->next)
178
if (dp->name && (c = strlen(dp->name)) && !strncmp(dp->name, fp->name, c) && fp->name[c] == '/')
179
{
180
ppsetfile(fp->name + c + 1)->guard = INC_IGNORE;
181
break;
182
}
183
}
184
if (!token)
185
break;
186
pathcanon(pp.token, 0, 0);
187
fp = ppsetfile(pp.token);
188
if (mp)
189
{
190
mp->flags |= flags;
191
if (streq(fp->name, "."))
192
mp->flags |= INC_MAPNOLOCAL;
193
else
194
mp->bound[index] = fp;
195
196
fp = mp = 0;
197
}
198
else
199
index = token == T_HEADER ? INC_STANDARD : INC_LOCAL;
200
continue;
201
case '=':
202
if (!(mp = fp))
203
error(3, "%s: \"name\" = \"binding\" expected");
204
fp = 0;
205
continue;
206
case '\n':
207
continue;
208
case T_ID:
209
if (streq(pp.token, "all"))
210
{
211
flags = INC_MAPALL;
212
continue;
213
}
214
else if (streq(pp.token, "hosted"))
215
{
216
flags = INC_MAPHOSTED;
217
continue;
218
}
219
else if (streq(pp.token, "nohosted"))
220
{
221
flags = INC_MAPNOHOSTED;
222
continue;
223
}
224
/*FALLTHROUGH*/
225
default:
226
error(3, "%s unexpected in %s map list", pptokstr(pp.token, 0), dirname(INCLUDE));
227
break;
228
}
229
break;
230
}
231
pp.level--;
232
error_info.file = old_file;
233
pp.state = old_state;
234
}
235
236
/*
237
* return non-0 if file is identical to fd
238
*/
239
240
static int
241
identical(char* file, int fd)
242
{
243
struct stat a;
244
struct stat b;
245
246
return !stat(file, &a) && !fstat(fd, &b) && a.st_dev == b.st_dev && a.st_ino == b.st_ino;
247
}
248
249
/*
250
* compare up to pp.truncate chars
251
*
252
* NOTE: __STD* and symbols containing ' ' are not truncated
253
*/
254
255
static int
256
trunccomp(register char* a, register char* b)
257
{
258
return !strchr(b, ' ') && !strneq(b, "__STD", 5) ? strncmp(a, b, pp.truncate) : strcmp(a, b);
259
}
260
261
/*
262
* hash up to pp.truncate chars
263
*
264
* NOTE: __STD* and symbols containing ' ' are not truncated
265
*/
266
267
static unsigned int
268
trunchash(char* a)
269
{
270
int n;
271
272
return memhash(a, (n = strlen(a)) > pp.truncate && !strchr(a, ' ') && !strneq(a, "__STD", 5) ? pp.truncate : n);
273
}
274
275
#if DEBUG & TRACE_debug
276
/*
277
* append context to debug trace
278
*/
279
280
static int
281
context(Sfio_t* sp, int level, int flags)
282
{
283
static int state;
284
285
NoP(level);
286
NoP(flags);
287
if (error_info.trace <= -10 && pp.state != state)
288
{
289
state = pp.state;
290
sfprintf(sp, " %s", ppstatestr(pp.state));
291
}
292
return 1;
293
}
294
#endif
295
296
/*
297
* reset include guard
298
*/
299
300
static int
301
unguard(const char* name, char* v, void* handle)
302
{
303
register struct ppfile* fp = (struct ppfile*)v;
304
305
fp->guard = 0;
306
return 0;
307
}
308
309
/*
310
* reset macro definition
311
*/
312
313
static void
314
undefine(void* p)
315
{
316
struct ppmacro* mac = ((struct ppsymbol*)p)->macro;
317
318
if (mac)
319
{
320
if (mac->formals)
321
free(mac->formals);
322
free(mac->value);
323
free(mac);
324
}
325
}
326
327
/*
328
* return non-zero if its ok to ppop(op)
329
*/
330
331
static int
332
ppok(int op)
333
{
334
long n;
335
long* r;
336
337
r = &pp.ro_op[op >> 5];
338
n = 1L << op;
339
if ((pp.mode & INIT) && pp.in->type == IN_FILE && (*r & n))
340
{
341
debug((-7, "set op %d index %d skipped -- readonly", op, op >> 5));
342
return 0;
343
}
344
else if (!pp.initialized && (!(pp.mode & INIT) || !(pp.mode & BUILTIN)))
345
{
346
*r |= n;
347
debug((-7, "set op %d index %d readonly", op, op >> 5));
348
}
349
else
350
debug((-7, "set op %d index %d", op, op >> 5));
351
return 1;
352
}
353
354
/*
355
* pp operations
356
*
357
* NOTE: PP_INIT must be done before the first pplex() call
358
* PP_DONE must be done after the last pplex() call
359
* PP_INIT-PP_DONE must be done for each new PP_INPUT
360
*/
361
362
void
363
ppop(int op, ...)
364
{
365
va_list ap;
366
register char* p;
367
register struct ppkeyword* kp;
368
register char* s;
369
int c;
370
long n;
371
long* r;
372
char* t;
373
struct ppdirs* dp;
374
struct ppdirs* hp;
375
struct ppsymkey* key;
376
struct oplist* xp;
377
Sfio_t* sp;
378
struct stat st;
379
PPCOMMENT ppcomment;
380
PPLINESYNC pplinesync;
381
382
static int initialized;
383
384
va_start(ap, op);
385
switch (op)
386
{
387
case PP_ASSERT:
388
case PP_DEFINE:
389
case PP_DIRECTIVE:
390
case PP_OPTION:
391
case PP_READ:
392
case PP_UNDEF:
393
if (pp.initialized)
394
goto before;
395
if ((p = va_arg(ap, char*)) && *p)
396
{
397
if (pp.lastop)
398
pp.lastop = (pp.lastop->next = newof(0, struct oplist, 1, 0));
399
else
400
pp.firstop = pp.lastop = newof(0, struct oplist, 1, 0);
401
pp.lastop->op = op;
402
pp.lastop->value = p;
403
}
404
break;
405
case PP_BUILTIN:
406
pp.builtin = va_arg(ap, PPBUILTIN);
407
break;
408
case PP_CDIR:
409
p = va_arg(ap, char*);
410
c = va_arg(ap, int);
411
pp.cdir.path = 0;
412
if (!p)
413
pp.c = c;
414
else if (streq(p, "-"))
415
{
416
pp.c = c;
417
for (dp = pp.firstdir; dp; dp = dp->next)
418
dp->c = c;
419
}
420
else if (!pp.c)
421
{
422
if (!*p || stat((pathcanon(p, 0, 0), p), &st))
423
pp.c = c;
424
else
425
{
426
for (dp = pp.firstdir; dp; dp = dp->next)
427
{
428
if (!pp.c && (dp->c || dp->name && SAMEID(&dp->id, &st)))
429
pp.c = 1;
430
dp->c = pp.c == 1;
431
}
432
if (!pp.c)
433
{
434
pp.cdir.path = p;
435
SAVEID(&pp.cdir.id, &st);
436
}
437
}
438
}
439
break;
440
case PP_CHOP:
441
if (p = va_arg(ap, char*))
442
{
443
c = strlen(p);
444
xp = newof(0, struct oplist, 1, c + 1);
445
xp->value = ((char*)xp) + sizeof(struct oplist);
446
s = xp->value;
447
c = *p++;
448
while (*p && *p != c)
449
*s++ = *p++;
450
*s++ = '/';
451
xp->op = s - xp->value;
452
*s++ = 0;
453
if (*p && *++p && *p != c)
454
{
455
while (*p && *p != c)
456
*s++ = *p++;
457
*s++ = '/';
458
}
459
*s = 0;
460
xp->next = pp.chop;
461
pp.chop = xp;
462
}
463
break;
464
case PP_COMMENT:
465
if (pp.comment = va_arg(ap, PPCOMMENT))
466
pp.flags |= PP_comment;
467
else
468
pp.flags &= ~PP_comment;
469
break;
470
case PP_COMPATIBILITY:
471
if (ppset(&pp.state, COMPATIBILITY, va_arg(ap, int)))
472
{
473
#if COMPATIBLE
474
if (pp.initialized)
475
ppfsm(FSM_COMPATIBILITY, NiL);
476
#else
477
if (pp.state & COMPATIBILITY)
478
error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
479
#endif
480
if (pp.state & COMPATIBILITY)
481
pp.flags |= PP_compatibility;
482
else
483
pp.flags &= ~PP_compatibility;
484
}
485
break;
486
case PP_COMPILE:
487
if (pp.initialized)
488
goto before;
489
pp.state |= COMPILE;
490
if (!pp.symtab)
491
pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
492
if (kp = va_arg(ap, struct ppkeyword*))
493
for (; s = kp->name; kp++)
494
{
495
n = SYM_LEX;
496
switch (*s)
497
{
498
case '-':
499
s++;
500
break;
501
case '+':
502
s++;
503
if (!(pp.option & PLUSPLUS))
504
break;
505
/*FALLTHROUGH*/
506
default:
507
n |= SYM_KEYWORD;
508
break;
509
}
510
if (key = ppkeyset(pp.symtab, s))
511
{
512
key->sym.flags = n;
513
key->lex = kp->value;
514
}
515
}
516
break;
517
case PP_DEBUG:
518
error_info.trace = va_arg(ap, int);
519
break;
520
case PP_DEFAULT:
521
if (p = va_arg(ap, char*))
522
p = strdup(p);
523
if (pp.ppdefault)
524
free(pp.ppdefault);
525
pp.ppdefault = p;
526
break;
527
case PP_DONE:
528
#if CHECKPOINT
529
if (pp.mode & DUMP)
530
ppdump();
531
#endif
532
if (pp.mode & FILEDEPS)
533
{
534
sfputc(pp.filedeps.sp, '\n');
535
if (pp.filedeps.sp == sfstdout)
536
sfsync(pp.filedeps.sp);
537
else
538
sfclose(pp.filedeps.sp);
539
}
540
if (pp.state & STANDALONE)
541
{
542
if ((pp.state & (NOTEXT|HIDDEN)) == HIDDEN && pplastout() != '\n')
543
ppputchar('\n');
544
ppflushout();
545
}
546
error_info.file = 0;
547
break;
548
case PP_DUMP:
549
ppset(&pp.mode, DUMP, va_arg(ap, int));
550
#if !CHECKPOINT
551
if (pp.mode & DUMP)
552
error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
553
#endif
554
break;
555
case PP_FILEDEPS:
556
if (n = va_arg(ap, int))
557
pp.filedeps.flags |= n;
558
else
559
pp.filedeps.flags = 0;
560
break;
561
case PP_FILENAME:
562
error_info.file = va_arg(ap, char*);
563
break;
564
case PP_HOSTDIR:
565
if (!(pp.mode & INIT))
566
pp.ro_mode |= HOSTED;
567
else if (pp.ro_mode & HOSTED)
568
break;
569
pp.ro_mode |= INIT;
570
p = va_arg(ap, char*);
571
c = va_arg(ap, int);
572
pp.hostdir.path = 0;
573
if (!p)
574
pp.hosted = c;
575
else if (streq(p, "-"))
576
{
577
if (pp.initialized)
578
ppset(&pp.mode, HOSTED, c);
579
else
580
{
581
pp.hosted = c ? 1 : 2;
582
for (dp = pp.firstdir; dp; dp = dp->next)
583
if (pp.hosted == 1)
584
dp->type |= TYPE_HOSTED;
585
else
586
dp->type &= ~TYPE_HOSTED;
587
}
588
}
589
else if (!pp.hosted)
590
{
591
if (!*p || stat((pathcanon(p, 0, 0), p), &st))
592
pp.hosted = 1;
593
else
594
{
595
for (dp = pp.firstdir; dp; dp = dp->next)
596
{
597
if (!pp.hosted && ((dp->type & TYPE_HOSTED) || dp->name && SAMEID(&dp->id, &st)))
598
pp.hosted = 1;
599
if (pp.hosted == 1)
600
dp->type |= TYPE_HOSTED;
601
else
602
dp->type &= ~TYPE_HOSTED;
603
}
604
if (!pp.hosted)
605
{
606
pp.hostdir.path = p;
607
SAVEID(&pp.hostdir.id, &st);
608
}
609
}
610
}
611
break;
612
case PP_ID:
613
p = va_arg(ap, char*);
614
c = va_arg(ap, int);
615
if (p)
616
ppfsm(c ? FSM_IDADD : FSM_IDDEL, p);
617
break;
618
case PP_IGNORE:
619
if (p = va_arg(ap, char*))
620
{
621
pathcanon(p, 0, 0);
622
ppsetfile(p)->guard = INC_IGNORE;
623
message((-3, "%s: ignore", p));
624
}
625
break;
626
case PP_IGNORELIST:
627
if (pp.initialized)
628
goto before;
629
pp.ignore = va_arg(ap, char*);
630
break;
631
case PP_INCLUDE:
632
if ((p = va_arg(ap, char*)) && *p)
633
{
634
pathcanon(p, 0, 0);
635
if (stat(p, &st))
636
break;
637
for (dp = pp.stddirs; dp = dp->next;)
638
if (dp->name && SAMEID(&dp->id, &st))
639
break;
640
if (pp.cdir.path && SAMEID(&pp.cdir.id, &st))
641
{
642
pp.cdir.path = 0;
643
pp.c = 1;
644
}
645
if (pp.hostdir.path && SAMEID(&pp.hostdir.id, &st))
646
{
647
pp.hostdir.path = 0;
648
pp.hosted = 1;
649
}
650
if ((pp.mode & INIT) && !(pp.ro_mode & INIT))
651
pp.hosted = 1;
652
c = dp && dp->c || pp.c == 1;
653
n = dp && (dp->type & TYPE_HOSTED) || pp.hosted == 1;
654
if (!dp || dp == pp.lastdir->next)
655
{
656
if (dp)
657
{
658
c = dp->c;
659
n = dp->type & TYPE_HOSTED;
660
}
661
dp = newof(0, struct ppdirs, 1, 0);
662
dp->name = p;
663
SAVEID(&dp->id, &st);
664
dp->type |= TYPE_INCLUDE;
665
dp->index = INC_LOCAL + pp.ignoresrc != 0;
666
dp->next = pp.lastdir->next;
667
pp.lastdir = pp.lastdir->next = dp;
668
}
669
dp->c = c;
670
if (n)
671
dp->type |= TYPE_HOSTED;
672
else
673
dp->type &= ~TYPE_HOSTED;
674
}
675
break;
676
case PP_INCREF:
677
pp.incref = va_arg(ap, PPINCREF);
678
break;
679
case PP_RESET:
680
pp.reset.on = 1;
681
break;
682
case PP_INIT:
683
if (pp.initialized)
684
{
685
error_info.errors = 0;
686
error_info.warnings = 0;
687
}
688
else
689
{
690
/*
691
* context initialization
692
*/
693
694
if (!initialized)
695
{
696
/*
697
* out of malloc is fatal
698
*/
699
700
memfatal();
701
702
/*
703
* initialize the error message interface
704
*/
705
706
error_info.version = (char*)pp.version;
707
#if DEBUG & TRACE_debug
708
error_info.auxilliary = context;
709
pptrace(0);
710
#endif
711
712
/*
713
* initialize pplex tables
714
*/
715
716
ppfsm(FSM_INIT, NiL);
717
718
/*
719
* fixed macro stack size -- room for improvement
720
*/
721
722
pp.macp = newof(0, struct ppmacstk, DEFMACSTACK, 0);
723
pp.macp->next = pp.macp + 1;
724
pp.maxmac = (char*)pp.macp + DEFMACSTACK;
725
initialized = 1;
726
727
/*
728
* initial include/if control stack
729
*/
730
731
pp.control = newof(0, long, pp.constack, 0);
732
pp.maxcon = pp.control + pp.constack - 1;
733
}
734
735
/*
736
* validate modes
737
*/
738
739
switch (pp.arg_mode)
740
{
741
case 'a':
742
case 'C':
743
ppop(PP_COMPATIBILITY, 0);
744
ppop(PP_TRANSITION, 1);
745
break;
746
case 'A':
747
case 'c':
748
ppop(PP_COMPATIBILITY, 0);
749
ppop(PP_STRICT, 1);
750
break;
751
case 'f':
752
ppop(PP_COMPATIBILITY, 1);
753
ppop(PP_PLUSPLUS, 1);
754
ppop(PP_TRANSITION, 1);
755
break;
756
case 'F':
757
ppop(PP_COMPATIBILITY, 0);
758
ppop(PP_PLUSPLUS, 1);
759
break;
760
case 'k':
761
case 's':
762
ppop(PP_COMPATIBILITY, 1);
763
ppop(PP_STRICT, 1);
764
break;
765
case 'o':
766
case 'O':
767
ppop(PP_COMPATIBILITY, 1);
768
ppop(PP_TRANSITION, 0);
769
break;
770
case 't':
771
ppop(PP_COMPATIBILITY, 1);
772
ppop(PP_TRANSITION, 1);
773
break;
774
}
775
if (!(pp.state & WARN) && !(pp.arg_style & STYLE_gnu))
776
ppop(PP_PEDANTIC, 1);
777
if (pp.state & PASSTHROUGH)
778
{
779
if (pp.state & COMPILE)
780
{
781
pp.state &= ~PASSTHROUGH;
782
error(1, "passthrough ignored for compile");
783
}
784
else
785
{
786
ppop(PP_COMPATIBILITY, 1);
787
ppop(PP_HOSTDIR, "-", 1);
788
ppop(PP_SPACEOUT, 1);
789
ppset(&pp.state, DISABLE, va_arg(ap, int));
790
}
791
}
792
793
/*
794
* create the hash tables
795
*/
796
797
if (!pp.symtab)
798
pp.symtab = hashalloc(NiL, HASH_name, "symbols", 0);
799
if (!pp.dirtab)
800
{
801
pp.dirtab = hashalloc(REFONE, HASH_name, "directives", 0);
802
inithash(pp.dirtab, directives);
803
}
804
if (!pp.filtab)
805
pp.filtab = hashalloc(REFALL, HASH_name, "files", 0);
806
if (!pp.prdtab)
807
pp.prdtab = hashalloc(REFALL, HASH_name, "predicates", 0);
808
if (!pp.strtab)
809
{
810
pp.strtab = hashalloc(REFALL, HASH_name, "strings", 0);
811
inithash(pp.strtab, options);
812
inithash(pp.strtab, predicates);
813
inithash(pp.strtab, variables);
814
}
815
pp.optflags[X_PROTOTYPED] = OPT_GLOBAL;
816
pp.optflags[X_SYSTEM_HEADER] = OPT_GLOBAL|OPT_PASS;
817
818
/*
819
* mark macros that are builtin predicates
820
*/
821
822
for (kp = predicates; s = kp->name; kp++)
823
{
824
if (!ppisid(*s))
825
s++;
826
ppassert(DEFINE, s, 0);
827
}
828
829
/*
830
* the remaining entry names must be allocated
831
*/
832
833
hashset(pp.dirtab, HASH_ALLOCATE);
834
hashset(pp.filtab, HASH_ALLOCATE);
835
hashset(pp.prdtab, HASH_ALLOCATE);
836
hashset(pp.strtab, HASH_ALLOCATE);
837
hashset(pp.symtab, HASH_ALLOCATE);
838
if (pp.test & TEST_nonoise)
839
{
840
c = error_info.trace;
841
error_info.trace = 0;
842
}
843
#if DEBUG
844
if (!(pp.test & TEST_noinit))
845
{
846
#endif
847
848
/*
849
* compose, push and read the builtin initialization script
850
*/
851
852
if (!(sp = sfstropen()))
853
error(3, "temporary buffer allocation error");
854
sfprintf(sp,
855
"\
856
#%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
857
#%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
858
",
859
dirname(PRAGMA),
860
pp.pass,
861
keyname(X_MAP),
862
dirname(DEFINE),
863
dirname(PRAGMA),
864
pp.pass,
865
keyname(X_MAP),
866
dirname(UNDEF));
867
if (pp.ppdefault && *pp.ppdefault)
868
{
869
if (pp.probe)
870
{
871
c = pp.lastdir->next->type;
872
pp.lastdir->next->type = 0;
873
}
874
if (ppsearch(pp.ppdefault, T_STRING, SEARCH_EXISTS) < 0)
875
{
876
free(pp.ppdefault);
877
if (!(pp.ppdefault = pathprobe("C", pp.pass, pp.probe ? pp.probe : PPPROBE, 0, pp.path, MAXTOKEN + 1, NiL, 0)))
878
error(1, "cannot determine default definitions for %s", pp.probe ? pp.probe : PPPROBE);
879
}
880
if (pp.probe)
881
pp.lastdir->next->type = c;
882
}
883
while (pp.firstop)
884
{
885
switch (pp.firstop->op)
886
{
887
case PP_ASSERT:
888
sfprintf(sp, "#%s #%s\n", dirname(DEFINE), pp.firstop->value);
889
break;
890
case PP_DEFINE:
891
if (*pp.firstop->value == '#')
892
sfprintf(sp, "#%s %s\n", dirname(DEFINE), pp.firstop->value);
893
else
894
{
895
if (s = strchr(pp.firstop->value, '='))
896
sfprintf(sp, "#%s %-.*s %s\n", dirname(DEFINE), s - pp.firstop->value, pp.firstop->value, s + 1);
897
else
898
sfprintf(sp, "#%s %s 1\n", dirname(DEFINE), pp.firstop->value);
899
}
900
break;
901
case PP_DIRECTIVE:
902
sfprintf(sp, "#%s\n", pp.firstop->value);
903
break;
904
case PP_OPTION:
905
if (s = strchr(pp.firstop->value, '='))
906
sfprintf(sp, "#%s %s:%-.*s %s\n", dirname(PRAGMA), pp.pass, s - pp.firstop->value, pp.firstop->value, s + 1);
907
else
908
sfprintf(sp, "#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.firstop->value);
909
break;
910
case PP_READ:
911
sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.firstop->value);
912
break;
913
case PP_UNDEF:
914
sfprintf(sp, "#%s %s\n", dirname(UNDEF), pp.firstop->value);
915
break;
916
}
917
pp.lastop = pp.firstop;
918
pp.firstop = pp.firstop->next;
919
free(pp.lastop);
920
}
921
sfprintf(sp,
922
"\
923
#%s %s:%s\n\
924
#%s %s:%s\n\
925
#%s !#%s(%s)\n\
926
#%s !#%s(%s) || #%s(%s)\n\
927
"
928
, dirname(PRAGMA)
929
, pp.pass
930
, keyname(X_BUILTIN)
931
, dirname(PRAGMA)
932
, pp.pass
933
, keyname(X_PREDEFINED)
934
, dirname(IF)
935
, keyname(X_OPTION)
936
, keyname(X_PLUSPLUS)
937
, dirname(IF)
938
, keyname(X_OPTION)
939
, keyname(X_COMPATIBILITY)
940
, keyname(X_OPTION)
941
, keyname(X_TRANSITION)
942
);
943
sfprintf(sp,
944
"\
945
#%s #%s(%s)\n\
946
#%s %s:%s\n\
947
#%s %s:%s\n\
948
#%s __STRICT__ 1\n\
949
#%s\n\
950
#%s\n\
951
"
952
, dirname(IF)
953
, keyname(X_OPTION)
954
, keyname(X_STRICT)
955
, dirname(PRAGMA)
956
, pp.pass
957
, keyname(X_ALLMULTIPLE)
958
, dirname(PRAGMA)
959
, pp.pass
960
, keyname(X_READONLY)
961
, dirname(DEFINE)
962
, dirname(ENDIF)
963
, dirname(ENDIF)
964
);
965
for (kp = readonlys; s = kp->name; kp++)
966
{
967
if (!ppisid(*s))
968
s++;
969
sfprintf(sp, "#%s %s\n", dirname(UNDEF), s);
970
}
971
sfprintf(sp,
972
"\
973
#%s\n\
974
#%s __STDPP__ 1\n\
975
#%s %s:no%s\n\
976
"
977
, dirname(ENDIF)
978
, dirname(DEFINE)
979
, dirname(PRAGMA)
980
, pp.pass
981
, keyname(X_PREDEFINED)
982
);
983
if (!pp.truncate)
984
sfprintf(sp,
985
"\
986
#%s __STDPP__directive #(%s)\n\
987
"
988
, dirname(DEFINE)
989
, keyname(V_DIRECTIVE)
990
);
991
for (kp = variables; s = kp->name; kp++)
992
if (ppisid(*s) || *s++ == '+')
993
{
994
t = *s == '_' ? "" : "__";
995
sfprintf(sp, "#%s %s%s%s #(%s)\n" , dirname(DEFINE), t, s, t, s);
996
}
997
sfprintf(sp,
998
"\
999
#%s %s:no%s\n\
1000
#%s %s:no%s\n\
1001
"
1002
, dirname(PRAGMA)
1003
, pp.pass
1004
, keyname(X_READONLY)
1005
, dirname(PRAGMA)
1006
, pp.pass
1007
, keyname(X_BUILTIN)
1008
);
1009
if (pp.ppdefault && *pp.ppdefault)
1010
sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), pp.ppdefault);
1011
sfprintf(sp,
1012
"\
1013
#%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
1014
#%s __STDC__ #(STDC)\n\
1015
#%s\n\
1016
"
1017
, dirname(IF)
1018
, dirname(DEFINE)
1019
, dirname(ENDIF)
1020
);
1021
t = sfstruse(sp);
1022
debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t));
1023
ppcomment = pp.comment;
1024
pp.comment = 0;
1025
pplinesync = pp.linesync;
1026
pp.linesync = 0;
1027
PUSH_INIT(pp.pass, t);
1028
pp.mode |= INIT;
1029
while (pplex());
1030
pp.mode &= ~INIT;
1031
pp.comment = ppcomment;
1032
pp.linesync = pplinesync;
1033
pp.prefix = 0;
1034
sfstrclose(sp);
1035
if (error_info.trace)
1036
for (dp = pp.firstdir; dp; dp = dp->next)
1037
message((-1, "include directory %s%s%s%s", dp->name, (dp->type & TYPE_VENDOR) ? " [VENDOR]" : "", (dp->type & TYPE_HOSTED) ? " [HOSTED]" : "", dp->c ? " [C]" : ""));
1038
#if DEBUG
1039
}
1040
if (pp.test & TEST_nonoise)
1041
error_info.trace = c;
1042
#endif
1043
{
1044
/*
1045
* this is sleazy but at least it's
1046
* hidden in the library
1047
*/
1048
#include <preroot.h>
1049
#if FS_PREROOT
1050
struct pplist* preroot;
1051
1052
if ((preroot = (struct pplist*)hashget(pp.prdtab, "preroot")))
1053
setpreroot(NiL, preroot->value);
1054
#endif
1055
}
1056
if (pp.ignoresrc)
1057
{
1058
if (pp.ignoresrc > 1 && pp.stddirs != pp.firstdir)
1059
error(1, "directories up to and including %s are for \"...\" include files only", pp.stddirs->name);
1060
pp.lcldirs = pp.lcldirs->next;
1061
}
1062
if (pp.ignore)
1063
{
1064
if (*pp.ignore)
1065
ppmapinclude(pp.ignore, NiL);
1066
else
1067
pp.ignore = 0;
1068
}
1069
if (pp.standalone)
1070
pp.state |= STANDALONE;
1071
#if COMPATIBLE
1072
ppfsm(FSM_COMPATIBILITY, NiL);
1073
#endif
1074
ppfsm(FSM_PLUSPLUS, NiL);
1075
pp.initialized = 1;
1076
if (pp.reset.on)
1077
{
1078
pp.reset.symtab = pp.symtab;
1079
pp.symtab = 0;
1080
pp.reset.ro_state = pp.ro_state;
1081
pp.reset.ro_mode = pp.ro_mode;
1082
pp.reset.ro_option = pp.ro_option;
1083
}
1084
}
1085
if (pp.reset.on)
1086
{
1087
if (pp.symtab)
1088
{
1089
hashwalk(pp.filtab, 0, unguard, NiL);
1090
hashfree(pp.symtab);
1091
}
1092
pp.symtab = hashalloc(NiL, HASH_name, "symbols", HASH_free, undefine, HASH_set, HASH_ALLOCATE|HASH_BUCKET, 0);
1093
hashview(pp.symtab, pp.reset.symtab);
1094
pp.ro_state = pp.reset.ro_state;
1095
pp.ro_mode = pp.reset.ro_mode;
1096
pp.ro_option = pp.reset.ro_option;
1097
}
1098
#if CHECKPOINT
1099
if (pp.mode & DUMP)
1100
{
1101
if (!pp.pragma)
1102
error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA));
1103
(*pp.pragma)(dirname(PRAGMA), pp.pass, keyname(X_CHECKPOINT), pp.checkpoint, 1);
1104
}
1105
#endif
1106
if (n = pp.filedeps.flags)
1107
{
1108
if (!(n & PP_deps_file))
1109
{
1110
pp.state |= NOTEXT;
1111
pp.option |= KEEPNOTEXT;
1112
pp.linesync = 0;
1113
}
1114
if (n & PP_deps_generated)
1115
pp.mode |= GENDEPS;
1116
if (n & PP_deps_local)
1117
pp.mode &= ~HEADERDEPS;
1118
else if (!(pp.mode & FILEDEPS))
1119
pp.mode |= HEADERDEPS;
1120
pp.mode |= FILEDEPS;
1121
}
1122
1123
/*
1124
* push the main input file -- special case for hosted mark
1125
*/
1126
1127
if (pp.firstdir->type & TYPE_HOSTED)
1128
pp.mode |= MARKHOSTED;
1129
else
1130
pp.mode &= ~MARKHOSTED;
1131
#if CHECKPOINT
1132
if (!(pp.mode & DUMP))
1133
#endif
1134
{
1135
if (!(p = error_info.file))
1136
p = "";
1137
else
1138
{
1139
error_info.file = 0;
1140
if (*p)
1141
{
1142
pathcanon(p, 0, 0);
1143
p = ppsetfile(p)->name;
1144
}
1145
}
1146
PUSH_FILE(p, 0);
1147
}
1148
if (pp.mode & FILEDEPS)
1149
{
1150
if (s = strrchr(error_info.file, '/'))
1151
s++;
1152
else
1153
s = error_info.file;
1154
if (!*s)
1155
s = "-";
1156
s = strcpy(pp.tmpbuf, s);
1157
if ((t = p = strrchr(s, '.')) && (*++p == 'c' || *p == 'C'))
1158
{
1159
if (c = *++p)
1160
while (*++p == c);
1161
if (*p)
1162
t = 0;
1163
else
1164
t++;
1165
}
1166
if (!t)
1167
{
1168
t = s + strlen(s);
1169
*t++ = '.';
1170
}
1171
*(t + 1) = 0;
1172
if (pp.state & NOTEXT)
1173
pp.filedeps.sp = sfstdout;
1174
else
1175
{
1176
*t = 'd';
1177
if (!(pp.filedeps.sp = sfopen(NiL, s, "w")))
1178
error(ERROR_SYSTEM|3, "%s: cannot create", s);
1179
}
1180
*t = 'o';
1181
pp.column = sfprintf(pp.filedeps.sp, "%s :", s);
1182
if (*error_info.file)
1183
pp.column += sfprintf(pp.filedeps.sp, " %s", error_info.file);
1184
}
1185
if (xp = pp.firsttx)
1186
{
1187
if (!(sp = sfstropen()))
1188
error(3, "temporary buffer allocation error");
1189
while (xp)
1190
{
1191
sfprintf(sp, "#%s \"%s\"\n", dirname(INCLUDE), xp->value);
1192
xp = xp->next;
1193
}
1194
t = sfstruse(sp);
1195
PUSH_BUFFER("options", t, 1);
1196
sfstrclose(sp);
1197
}
1198
break;
1199
case PP_INPUT:
1200
#if CHECKPOINT && POOL
1201
if (!(pp.mode & DUMP) || pp.pool.input)
1202
#else
1203
#if CHECKPOINT
1204
if (!(pp.mode & DUMP))
1205
#else
1206
#if POOL
1207
if (pp.pool.input)
1208
#endif
1209
#endif
1210
#endif
1211
{
1212
p = va_arg(ap, char*);
1213
if (!error_info.file)
1214
error_info.file = p;
1215
close(0);
1216
if (open(p, O_RDONLY) != 0)
1217
error(ERROR_SYSTEM|3, "%s: cannot read", p);
1218
if (strmatch(p, "*.(s|S|as|AS|asm|ASM)"))
1219
{
1220
ppset(&pp.mode, CATLITERAL, 0);
1221
ppop(PP_SPACEOUT, 1);
1222
}
1223
break;
1224
}
1225
/*FALLTHROUGH*/
1226
case PP_TEXT:
1227
if (pp.initialized)
1228
goto before;
1229
if ((p = va_arg(ap, char*)) && *p)
1230
{
1231
if (pp.lasttx)
1232
pp.lasttx = pp.lasttx->next = newof(0, struct oplist, 1, 0);
1233
else
1234
pp.firsttx = pp.lasttx = newof(0, struct oplist, 1, 0);
1235
pp.lasttx->op = op;
1236
pp.lasttx->value = p;
1237
}
1238
break;
1239
case PP_KEYARGS:
1240
if (pp.initialized)
1241
goto before;
1242
ppset(&pp.option, KEYARGS, va_arg(ap, int));
1243
if (pp.option & KEYARGS)
1244
#if MACKEYARGS
1245
ppset(&pp.mode, CATLITERAL, 1);
1246
#else
1247
error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
1248
#endif
1249
break;
1250
case PP_LINE:
1251
if (ppok(op))
1252
pp.linesync = va_arg(ap, PPLINESYNC);
1253
break;
1254
case PP_LINEBASE:
1255
if (ppok(op))
1256
{
1257
if (va_arg(ap, int))
1258
pp.flags |= PP_linebase;
1259
else
1260
pp.flags &= ~PP_linebase;
1261
}
1262
break;
1263
case PP_LINEFILE:
1264
if (ppok(op))
1265
{
1266
if (va_arg(ap, int))
1267
pp.flags |= PP_linefile;
1268
else
1269
pp.flags &= ~PP_linefile;
1270
}
1271
break;
1272
case PP_LINEID:
1273
if (ppok(op))
1274
{
1275
if (!(p = va_arg(ap, char*)))
1276
pp.lineid = "";
1277
else if (*p != '-')
1278
pp.lineid = strdup(p);
1279
else
1280
pp.option |= IGNORELINE;
1281
}
1282
break;
1283
case PP_LINETYPE:
1284
if (ppok(op))
1285
{
1286
if ((n = va_arg(ap, int)) >= 1)
1287
pp.flags |= PP_linetype;
1288
else
1289
pp.flags &= ~PP_linetype;
1290
if (n >= 2)
1291
pp.flags |= PP_linehosted;
1292
else
1293
pp.flags &= ~PP_linehosted;
1294
}
1295
break;
1296
case PP_LOCAL:
1297
if (pp.initialized)
1298
goto before;
1299
pp.ignoresrc++;
1300
pp.stddirs = pp.lastdir;
1301
if (!(pp.ro_option & PREFIX))
1302
pp.option &= ~PREFIX;
1303
break;
1304
case PP_MACREF:
1305
pp.macref = va_arg(ap, PPMACREF);
1306
break;
1307
case PP_MULTIPLE:
1308
ppset(&pp.mode, ALLMULTIPLE, va_arg(ap, int));
1309
break;
1310
case PP_NOHASH:
1311
ppset(&pp.option, NOHASH, va_arg(ap, int));
1312
break;
1313
case PP_NOISE:
1314
op = va_arg(ap, int);
1315
ppset(&pp.option, NOISE, op);
1316
ppset(&pp.option, NOISEFILTER, op < 0);
1317
break;
1318
case PP_OPTARG:
1319
pp.optarg = va_arg(ap, PPOPTARG);
1320
break;
1321
case PP_OUTPUT:
1322
pp.outfile = va_arg(ap, char*);
1323
if (identical(pp.outfile, 0))
1324
error(3, "%s: identical to input", pp.outfile);
1325
close(1);
1326
if (open(pp.outfile, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) != 1)
1327
error(ERROR_SYSTEM|3, "%s: cannot create", pp.outfile);
1328
break;
1329
case PP_PASSTHROUGH:
1330
if (!(pp.state & COMPILE))
1331
ppset(&pp.state, PASSTHROUGH, va_arg(ap, int));
1332
break;
1333
case PP_PEDANTIC:
1334
ppset(&pp.mode, PEDANTIC, va_arg(ap, int));
1335
break;
1336
case PP_PLUSCOMMENT:
1337
if (ppset(&pp.option, PLUSCOMMENT, va_arg(ap, int)) && pp.initialized)
1338
ppfsm(FSM_PLUSPLUS, NiL);
1339
break;
1340
case PP_PLUSPLUS:
1341
if (ppset(&pp.option, PLUSPLUS, va_arg(ap, int)) && ppset(&pp.option, PLUSCOMMENT, va_arg(ap, int)) && pp.initialized)
1342
ppfsm(FSM_PLUSPLUS, NiL);
1343
break;
1344
case PP_POOL:
1345
if (pp.initialized)
1346
goto before;
1347
if (va_arg(ap, int))
1348
{
1349
#if POOL
1350
pp.pool.input = dup(0);
1351
pp.pool.output = dup(1);
1352
p = "/dev/null";
1353
if (!identical(p, 0))
1354
{
1355
if (!identical(p, 1))
1356
ppop(PP_OUTPUT, p);
1357
ppop(PP_INPUT, p);
1358
}
1359
#else
1360
error(3, "preprocessor not compiled with input pool enabled [POOL]");
1361
#endif
1362
}
1363
break;
1364
case PP_PRAGMA:
1365
pp.pragma = va_arg(ap, PPPRAGMA);
1366
break;
1367
case PP_PRAGMAFLAGS:
1368
if (p = va_arg(ap, char*))
1369
{
1370
n = OPT_GLOBAL;
1371
if (*p == '-')
1372
p++;
1373
else
1374
n |= OPT_PASS;
1375
if ((c = (int)hashref(pp.strtab, p)) > 0 && c <= X_last_option)
1376
pp.optflags[c] = n;
1377
}
1378
break;
1379
case PP_PROBE:
1380
pp.probe = va_arg(ap, char*);
1381
break;
1382
case PP_QUOTE:
1383
p = va_arg(ap, char*);
1384
c = va_arg(ap, int);
1385
if (p)
1386
ppfsm(c ? FSM_QUOTADD : FSM_QUOTDEL, p);
1387
break;
1388
case PP_REGUARD:
1389
ppset(&pp.option, REGUARD, va_arg(ap, int));
1390
break;
1391
case PP_RESERVED:
1392
if ((pp.state & COMPILE) && (p = va_arg(ap, char*)))
1393
{
1394
if (!(sp = sfstropen()))
1395
error(3, "temporary buffer allocation error");
1396
sfputr(sp, p, -1);
1397
p = sfstruse(sp);
1398
if (s = strchr(p, '='))
1399
*s++ = 0;
1400
else
1401
s = p;
1402
while (*s == '_')
1403
s++;
1404
for (t = s + strlen(s); t > s && *(t - 1) == '_'; t--);
1405
if (*t == '_')
1406
*t = 0;
1407
else
1408
t = 0;
1409
op = ((key = ppkeyref(pp.symtab, s)) && (key->sym.flags & SYM_LEX)) ? key->lex : T_NOISE;
1410
if (pp.test & 0x0400)
1411
error(1, "reserved#1 `%s' %d", s, op);
1412
if (t)
1413
*t = '_';
1414
if (!(key = ppkeyget(pp.symtab, p)))
1415
key = ppkeyset(pp.symtab, NiL);
1416
else if (!(key->sym.flags & SYM_LEX))
1417
{
1418
struct ppsymbol tmp;
1419
1420
tmp = key->sym;
1421
hashlook(pp.symtab, p, HASH_DELETE, NiL);
1422
key = ppkeyset(pp.symtab, NiL);
1423
key->sym.flags = tmp.flags;
1424
key->sym.macro = tmp.macro;
1425
key->sym.value = tmp.value;
1426
key->sym.hidden = tmp.hidden;
1427
}
1428
if (!(key->sym.flags & SYM_KEYWORD))
1429
{
1430
key->sym.flags |= SYM_KEYWORD|SYM_LEX;
1431
key->lex = op;
1432
if (pp.test & 0x0400)
1433
error(1, "reserved#2 `%s' %d", p, op);
1434
}
1435
sfstrclose(sp);
1436
}
1437
break;
1438
case PP_SPACEOUT:
1439
ppset(&pp.state, SPACEOUT, va_arg(ap, int));
1440
break;
1441
case PP_STANDALONE:
1442
if (pp.initialized)
1443
goto before;
1444
pp.standalone = 1;
1445
break;
1446
case PP_STANDARD:
1447
if ((pp.lastdir->next->name = ((p = va_arg(ap, char*)) && *p) ? p : NiL) && !stat(p, &st))
1448
SAVEID(&pp.lastdir->next->id, &st);
1449
for (dp = pp.firstdir; dp; dp = dp->next)
1450
if (dp->name)
1451
for (hp = pp.firstdir; hp != dp; hp = hp->next)
1452
if (hp->name && SAMEID(&hp->id, &dp->id))
1453
{
1454
hp->c = dp->c;
1455
if (dp->type & TYPE_HOSTED)
1456
hp->type |= TYPE_HOSTED;
1457
else
1458
hp->type &= ~TYPE_HOSTED;
1459
}
1460
break;
1461
case PP_STRICT:
1462
if (ppset(&pp.state, STRICT, va_arg(ap, int)))
1463
{
1464
if (ppset(&pp.state, TRANSITION, 0))
1465
pp.flags &= ~PP_transition;
1466
if (pp.state & STRICT)
1467
pp.flags |= PP_strict;
1468
else
1469
pp.flags &= ~PP_strict;
1470
}
1471
break;
1472
case PP_TEST:
1473
if (p = va_arg(ap, char*))
1474
for (;;)
1475
{
1476
while (*p == ' ' || *p == '\t') p++;
1477
for (s = p; n = *s; s++)
1478
if (n == ',' || n == ' ' || n == '\t')
1479
{
1480
*s++ = 0;
1481
break;
1482
}
1483
if (!*p)
1484
break;
1485
n = 0;
1486
if (*p == 'n' && *(p + 1) == 'o')
1487
{
1488
p += 2;
1489
op = 0;
1490
}
1491
else
1492
op = 1;
1493
if (streq(p, "count"))
1494
n = TEST_count;
1495
else if (streq(p, "hashcount"))
1496
n = TEST_hashcount;
1497
else if (streq(p, "hashdump"))
1498
n = TEST_hashdump;
1499
else if (streq(p, "hit"))
1500
n = TEST_hit;
1501
else if (streq(p, "init"))
1502
n = TEST_noinit|TEST_INVERT;
1503
else if (streq(p, "noise"))
1504
n = TEST_nonoise|TEST_INVERT;
1505
else if (streq(p, "proto"))
1506
n = TEST_noproto|TEST_INVERT;
1507
else if (*p >= '0' && *p <= '9')
1508
n = strtoul(p, NiL, 0);
1509
else
1510
{
1511
error(1, "%s: unknown test", p);
1512
break;
1513
}
1514
if (n & TEST_INVERT)
1515
{
1516
n &= ~TEST_INVERT;
1517
op = !op;
1518
}
1519
if (op)
1520
pp.test |= n;
1521
else
1522
pp.test &= ~n;
1523
p = s;
1524
debug((-4, "test = 0%o", pp.test));
1525
}
1526
break;
1527
case PP_TRANSITION:
1528
if (ppset(&pp.state, TRANSITION, va_arg(ap, int)))
1529
{
1530
if (ppset(&pp.state, STRICT, 0))
1531
pp.flags &= ~PP_strict;
1532
if (pp.state & TRANSITION)
1533
pp.flags |= PP_transition;
1534
else
1535
pp.flags &= ~PP_transition;
1536
}
1537
break;
1538
case PP_TRUNCATE:
1539
if (pp.initialized)
1540
goto before;
1541
if ((op = va_arg(ap, int)) < 0)
1542
op = 0;
1543
ppset(&pp.option, TRUNCATE, op);
1544
if (pp.option & TRUNCATE)
1545
{
1546
Hash_bucket_t* b;
1547
Hash_bucket_t* p;
1548
Hash_position_t* pos;
1549
Hash_table_t* tab;
1550
1551
pp.truncate = op;
1552
tab = pp.symtab;
1553
pp.symtab = hashalloc(NiL, HASH_set, tab ? HASH_ALLOCATE : 0, HASH_compare, trunccomp, HASH_hash, trunchash, HASH_name, "truncate", 0);
1554
if (tab && (pos = hashscan(tab, 0)))
1555
{
1556
if (p = hashnext(pos))
1557
do
1558
{
1559
b = hashnext(pos);
1560
hashlook(pp.symtab, (char*)p, HASH_BUCKET|HASH_INSTALL, NiL);
1561
} while (p = b);
1562
hashdone(pos);
1563
}
1564
}
1565
else
1566
pp.truncate = 0;
1567
break;
1568
case PP_VENDOR:
1569
p = va_arg(ap, char*);
1570
c = va_arg(ap, int) != 0;
1571
if (!p || !*p)
1572
for (dp = pp.firstdir; dp; dp = dp->next)
1573
dp->type &= ~TYPE_VENDOR;
1574
else if (streq(p, "-"))
1575
{
1576
for (dp = pp.firstdir; dp; dp = dp->next)
1577
if (c)
1578
dp->type |= TYPE_VENDOR;
1579
else
1580
dp->type &= ~TYPE_VENDOR;
1581
}
1582
else if (!stat((pathcanon(p, 0, 0), p), &st))
1583
{
1584
c = 0;
1585
for (dp = pp.firstdir; dp; dp = dp->next)
1586
{
1587
if (!c && ((dp->type & TYPE_VENDOR) || dp->name && SAMEID(&dp->id, &st)))
1588
c = 1;
1589
if (c)
1590
dp->type |= TYPE_VENDOR;
1591
else
1592
dp->type &= ~TYPE_VENDOR;
1593
}
1594
}
1595
break;
1596
case PP_WARN:
1597
ppset(&pp.state, WARN, va_arg(ap, int));
1598
break;
1599
before:
1600
error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op);
1601
break;
1602
default:
1603
error(3, "ppop(%d): invalid preprocessor operation", op);
1604
break;
1605
}
1606
va_end(ap);
1607
}
1608
1609