1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2009 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
19 ***********************************************************************/
25 * preprocessor library control interface
33 #define REFONE (pp.truncate?(Hash_table_t*)0:pp.symtab)
34 #define REFALL (pp.truncate?pp.dirtab:pp.symtab)
36 #define ppiskey(t,v,p) (p=t,v>=p->value&&value<=(p+elementsof(t)-2)->value)
40 * initialization files have lowest precedence
44 set(register long* p
, register long op
, int val
)
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
))
51 if (!pp
.initialized
&& !(pp
.mode
& INIT
))
58 debug((-7, "set(%s)=%s", p
== &pp
.state
? "state" : p
== &pp
.mode
? "mode" : "option", p
== &pp
.state
? ppstatestr(*p
) : p
== &pp
.mode
? ppmodestr(*p
) : ppoptionstr(*p
)));
62 * initialize hash table with keywords from key
66 inithash(register Hash_table_t
* tab
, register struct ppkeyword
* key
)
70 for (; s
= key
->name
; key
++)
74 hashput(tab
, s
, key
->value
);
79 * return ppkeyword table name given value
83 ppkeyname(register int value
, int dir
)
86 register struct ppkeyword
* p
;
88 if (dir
&& ppiskey(directives
, value
, p
) || !dir
&& (ppiskey(options
, value
, p
) || ppiskey(predicates
, value
, p
) || ppiskey(variables
, value
, p
)))
90 s
= (p
+ (value
- p
->value
))->name
;
91 return s
+ !ppisid(*s
);
94 error(PANIC
, "no keyword table name for value=%d", value
);
100 * add to the include maps
104 ppmapinclude(char* file
, register char* s
)
107 register struct ppdirs
* dp
;
118 old_file
= error_info
.file
;
119 old_state
= pp
.state
;
121 PUSH_BUFFER("mapinclude", s
, 1);
126 if (!error_info
.file
)
128 error(1, "%s: input file name required for %s ignore", file
, dirname(INCLUDE
));
131 s
= t
= strcopy(pp
.tmpbuf
, error_info
.file
);
135 if (s
<= pp
.tmpbuf
|| *s
== '/')
147 if ((fd
= ppsearch(file
, INC_LOCAL
, SEARCH_INCLUDE
)) < 0)
154 pp
.state
|= (COMPILE
|FILEPOP
|HEADER
|JOINING
|STRIP
|NOSPACE
|PASSEOF
);
156 pp
.state
|= (COMPILE
|FILEPOP
|HEADER
|STRIP
|NOSPACE
|PASSEOF
);
163 switch (token
= pplex())
170 fp
->guard
= INC_IGNORE
;
171 for (dp
= pp
.firstdir
->next
; dp
; dp
= dp
->next
)
172 if (dp
->name
&& (c
= strlen(dp
->name
)) && !strncmp(dp
->name
, fp
->name
, c
) && fp
->name
[c
] == '/')
174 ppsetfile(fp
->name
+ c
+ 1)->guard
= INC_IGNORE
;
180 pathcanon(pp
.token
, 0);
181 fp
= ppsetfile(pp
.token
);
185 if (streq(fp
->name
, "."))
186 mp
->flags
|= INC_MAPNOLOCAL
;
188 mp
->bound
[index
] = fp
;
193 index
= token
== T_HEADER
? INC_STANDARD
: INC_LOCAL
;
197 error(3, "%s: \"name\" = \"binding\" expected");
203 if (streq(pp
.token
, "all"))
208 else if (streq(pp
.token
, "hosted"))
210 flags
= INC_MAPHOSTED
;
213 else if (streq(pp
.token
, "nohosted"))
215 flags
= INC_MAPNOHOSTED
;
220 error(3, "%s unexpected in %s map list", pptokstr(pp
.token
, 0), dirname(INCLUDE
));
226 error_info
.file
= old_file
;
227 pp
.state
= old_state
;
231 * return non-0 if file is identical to fd
235 identical(char* file
, int fd
)
240 return !stat(file
, &a
) && !fstat(fd
, &b
) && a
.st_dev
== b
.st_dev
&& a
.st_ino
== b
.st_ino
;
244 * compare up to pp.truncate chars
246 * NOTE: __STD* and symbols containing ' ' are not truncated
250 trunccomp(register char* a
, register char* b
)
252 return !strchr(b
, ' ') && !strneq(b
, "__STD", 5) ? strncmp(a
, b
, pp
.truncate
) : strcmp(a
, b
);
256 * hash up to pp.truncate chars
258 * NOTE: __STD* and symbols containing ' ' are not truncated
266 return memhash(a
, (n
= strlen(a
)) > pp
.truncate
&& !strchr(a
, ' ') && !strneq(a
, "__STD", 5) ? pp
.truncate
: n
);
269 #if DEBUG & TRACE_debug
271 * append context to debug trace
275 context(Sfio_t
* sp
, int level
, int flags
)
281 if (error_info
.trace
<= -10 && pp
.state
!= state
)
284 sfprintf(sp
, " %s", ppstatestr(pp
.state
));
291 * reset include guard
295 unguard(const char* name
, char* v
, void* handle
)
297 register struct ppfile
* fp
= (struct ppfile
*)v
;
304 * reset macro definition
310 struct ppmacro
* mac
= ((struct ppsymbol
*)p
)->macro
;
324 * NOTE: PP_INIT must be done before the first pplex() call
325 * PP_DONE must be done after the last pplex() call
326 * PP_INIT-PP_DONE must be done for each new PP_INPUT
334 register struct ppkeyword
* kp
;
341 struct ppsymkey
* key
;
346 PPLINESYNC pplinesync
;
348 static int initialized
;
361 if ((p
= va_arg(ap
, char*)) && *p
)
364 pp
.lastop
= (pp
.lastop
->next
= newof(0, struct oplist
, 1, 0));
366 pp
.firstop
= pp
.lastop
= newof(0, struct oplist
, 1, 0);
368 pp
.lastop
->value
= p
;
372 pp
.builtin
= va_arg(ap
, PPBUILTIN
);
375 p
= va_arg(ap
, char*);
380 else if (streq(p
, "-"))
383 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
388 if (!*p
|| stat((pathcanon(p
, 0), p
), &st
))
392 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
394 if (!pp
.c
&& (dp
->c
|| dp
->name
&& SAMEID(&dp
->id
, &st
)))
401 SAVEID(&pp
.cdir
.id
, &st
);
407 if (p
= va_arg(ap
, char*))
410 xp
= newof(0, struct oplist
, 1, c
+ 1);
411 xp
->value
= ((char*)xp
) + sizeof(struct oplist
);
414 while (*p
&& *p
!= c
)
417 xp
->op
= s
- xp
->value
;
419 if (*p
&& *++p
&& *p
!= c
)
421 while (*p
&& *p
!= c
)
431 if (pp
.comment
= va_arg(ap
, PPCOMMENT
))
432 pp
.flags
|= PP_comment
;
434 pp
.flags
&= ~PP_comment
;
436 case PP_COMPATIBILITY
:
437 set(&pp
.state
, COMPATIBILITY
, va_arg(ap
, int));
440 ppfsm(FSM_COMPATIBILITY
, NiL
);
442 if (pp
.state
& COMPATIBILITY
)
443 error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
445 if (pp
.state
& COMPATIBILITY
)
446 pp
.flags
|= PP_compatibility
;
448 pp
.flags
&= ~PP_compatibility
;
455 pp
.symtab
= hashalloc(NiL
, HASH_name
, "symbols", 0);
456 if (kp
= va_arg(ap
, struct ppkeyword
*))
457 for (; s
= kp
->name
; kp
++)
467 if (!(pp
.option
& PLUSPLUS
))
474 if (key
= ppkeyset(pp
.symtab
, s
))
477 key
->lex
= kp
->value
;
482 error_info
.trace
= va_arg(ap
, int);
485 if (p
= va_arg(ap
, char*))
496 if (pp
.mode
& FILEDEPS
)
498 sfputc(pp
.filedeps
.sp
, '\n');
499 if (pp
.filedeps
.sp
== sfstdout
)
500 sfsync(pp
.filedeps
.sp
);
502 sfclose(pp
.filedeps
.sp
);
504 if (pp
.state
& STANDALONE
)
506 if ((pp
.state
& (NOTEXT
|HIDDEN
)) == HIDDEN
&& pplastout() != '\n')
513 set(&pp
.mode
, DUMP
, va_arg(ap
, int));
516 error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
520 if (n
= va_arg(ap
, int))
521 pp
.filedeps
.flags
|= n
;
523 pp
.filedeps
.flags
= 0;
526 error_info
.file
= va_arg(ap
, char*);
529 if (!(pp
.mode
& INIT
))
530 pp
.ro_mode
|= HOSTED
;
531 else if (pp
.ro_mode
& HOSTED
)
534 p
= va_arg(ap
, char*);
539 else if (streq(p
, "-"))
542 set(&pp
.mode
, HOSTED
, c
);
545 pp
.hosted
= c
? 1 : 2;
546 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
548 dp
->type
|= TYPE_HOSTED
;
550 dp
->type
&= ~TYPE_HOSTED
;
555 if (!*p
|| stat((pathcanon(p
, 0), p
), &st
))
559 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
561 if (!pp
.hosted
&& ((dp
->type
& TYPE_HOSTED
) || dp
->name
&& SAMEID(&dp
->id
, &st
)))
564 dp
->type
|= TYPE_HOSTED
;
566 dp
->type
&= ~TYPE_HOSTED
;
571 SAVEID(&pp
.hostdir
.id
, &st
);
577 p
= va_arg(ap
, char*);
580 ppfsm(c
? FSM_IDADD
: FSM_IDDEL
, p
);
583 if (p
= va_arg(ap
, char*))
586 ppsetfile(p
)->guard
= INC_IGNORE
;
587 message((-3, "%s: ignore", p
));
593 pp
.ignore
= va_arg(ap
, char*);
596 if ((p
= va_arg(ap
, char*)) && *p
)
601 for (dp
= pp
.stddirs
; dp
= dp
->next
;)
602 if (dp
->name
&& SAMEID(&dp
->id
, &st
))
604 if (pp
.cdir
.path
&& SAMEID(&pp
.cdir
.id
, &st
))
609 if (pp
.hostdir
.path
&& SAMEID(&pp
.hostdir
.id
, &st
))
614 if ((pp
.mode
& INIT
) && !(pp
.ro_mode
& INIT
))
616 c
= dp
&& dp
->c
|| pp
.c
== 1;
617 n
= dp
&& (dp
->type
& TYPE_HOSTED
) || pp
.hosted
== 1;
618 if (!dp
|| dp
== pp
.lastdir
->next
)
623 n
= dp
->type
& TYPE_HOSTED
;
625 dp
= newof(0, struct ppdirs
, 1, 0);
627 SAVEID(&dp
->id
, &st
);
628 dp
->type
|= TYPE_INCLUDE
;
629 dp
->index
= INC_LOCAL
+ pp
.ignoresrc
!= 0;
630 dp
->next
= pp
.lastdir
->next
;
631 pp
.lastdir
= pp
.lastdir
->next
= dp
;
635 dp
->type
|= TYPE_HOSTED
;
637 dp
->type
&= ~TYPE_HOSTED
;
641 pp
.incref
= va_arg(ap
, PPINCREF
);
649 error_info
.errors
= 0;
650 error_info
.warnings
= 0;
655 * context initialization
661 * out of malloc is fatal
667 * initialize the error message interface
670 error_info
.version
= (char*)pp
.version
;
671 #if DEBUG & TRACE_debug
672 error_info
.auxilliary
= context
;
677 * initialize pplex tables
680 ppfsm(FSM_INIT
, NiL
);
683 * fixed macro stack size -- room for improvement
686 pp
.macp
= newof(0, struct ppmacstk
, DEFMACSTACK
, 0);
687 pp
.macp
->next
= pp
.macp
+ 1;
688 pp
.maxmac
= (char*)pp
.macp
+ DEFMACSTACK
;
692 * initial include/if control stack
695 pp
.control
= newof(0, long, pp
.constack
, 0);
696 pp
.maxcon
= pp
.control
+ pp
.constack
- 1;
707 ppop(PP_COMPATIBILITY
, 0);
708 ppop(PP_TRANSITION
, 1);
712 ppop(PP_COMPATIBILITY
, 0);
716 ppop(PP_COMPATIBILITY
, 1);
717 ppop(PP_PLUSPLUS
, 1);
718 ppop(PP_TRANSITION
, 1);
721 ppop(PP_COMPATIBILITY
, 0);
722 ppop(PP_PLUSPLUS
, 1);
726 ppop(PP_COMPATIBILITY
, 1);
731 ppop(PP_COMPATIBILITY
, 1);
732 ppop(PP_TRANSITION
, 0);
735 ppop(PP_COMPATIBILITY
, 1);
736 ppop(PP_TRANSITION
, 1);
739 if (!(pp
.state
& WARN
) && !(pp
.arg_style
& STYLE_gnu
))
740 ppop(PP_PEDANTIC
, 1);
741 if (pp
.state
& PASSTHROUGH
)
743 if (pp
.state
& COMPILE
)
745 pp
.state
&= ~PASSTHROUGH
;
746 error(1, "passthrough ignored for compile");
750 ppop(PP_COMPATIBILITY
, 1);
751 ppop(PP_HOSTDIR
, "-", 1);
752 ppop(PP_SPACEOUT
, 1);
753 set(&pp
.state
, DISABLE
, va_arg(ap
, int));
758 * create the hash tables
762 pp
.symtab
= hashalloc(NiL
, HASH_name
, "symbols", 0);
765 pp
.dirtab
= hashalloc(REFONE
, HASH_name
, "directives", 0);
766 inithash(pp
.dirtab
, directives
);
769 pp
.filtab
= hashalloc(REFALL
, HASH_name
, "files", 0);
771 pp
.prdtab
= hashalloc(REFALL
, HASH_name
, "predicates", 0);
774 pp
.strtab
= hashalloc(REFALL
, HASH_name
, "strings", 0);
775 inithash(pp
.strtab
, options
);
776 inithash(pp
.strtab
, predicates
);
777 inithash(pp
.strtab
, variables
);
779 pp
.optflags
[X_PROTOTYPED
] = OPT_GLOBAL
;
780 pp
.optflags
[X_SYSTEM_HEADER
] = OPT_GLOBAL
|OPT_PASS
;
783 * mark macros that are builtin predicates
786 for (kp
= predicates
; s
= kp
->name
; kp
++)
790 ppassert(DEFINE
, s
, 0);
794 * the remaining entry names must be allocated
797 hashset(pp
.dirtab
, HASH_ALLOCATE
);
798 hashset(pp
.filtab
, HASH_ALLOCATE
);
799 hashset(pp
.prdtab
, HASH_ALLOCATE
);
800 hashset(pp
.strtab
, HASH_ALLOCATE
);
801 hashset(pp
.symtab
, HASH_ALLOCATE
);
802 if (pp
.test
& TEST_nonoise
)
804 c
= error_info
.trace
;
805 error_info
.trace
= 0;
808 if (!(pp
.test
& TEST_noinit
))
813 * compose, push and read the builtin initialization script
816 if (!(sp
= sfstropen()))
817 error(3, "temporary buffer allocation error");
820 #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
821 #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
831 if (pp
.ppdefault
&& *pp
.ppdefault
)
835 c
= pp
.lastdir
->next
->type
;
836 pp
.lastdir
->next
->type
= 0;
838 if (ppsearch(pp
.ppdefault
, T_STRING
, SEARCH_EXISTS
) < 0)
841 if (!(pp
.ppdefault
= pathprobe(pp
.path
, NiL
, "C", pp
.pass
, pp
.probe
? pp
.probe
: PPPROBE
, 0)))
842 error(1, "cannot determine default definitions for %s", pp
.probe
? pp
.probe
: PPPROBE
);
845 pp
.lastdir
->next
->type
= c
;
849 switch (pp
.firstop
->op
)
852 sfprintf(sp
, "#%s #%s\n", dirname(DEFINE
), pp
.firstop
->value
);
855 if (*pp
.firstop
->value
== '#')
856 sfprintf(sp
, "#%s %s\n", dirname(DEFINE
), pp
.firstop
->value
);
859 if (s
= strchr(pp
.firstop
->value
, '='))
860 sfprintf(sp
, "#%s %-.*s %s\n", dirname(DEFINE
), s
- pp
.firstop
->value
, pp
.firstop
->value
, s
+ 1);
862 sfprintf(sp
, "#%s %s 1\n", dirname(DEFINE
), pp
.firstop
->value
);
866 sfprintf(sp
, "#%s\n", pp
.firstop
->value
);
869 if (s
= strchr(pp
.firstop
->value
, '='))
870 sfprintf(sp
, "#%s %s:%-.*s %s\n", dirname(PRAGMA
), pp
.pass
, s
- pp
.firstop
->value
, pp
.firstop
->value
, s
+ 1);
872 sfprintf(sp
, "#%s %s:%s\n", dirname(PRAGMA
), pp
.pass
, pp
.firstop
->value
);
875 sfprintf(sp
, "#%s \"%s\"\n", dirname(INCLUDE
), pp
.firstop
->value
);
878 sfprintf(sp
, "#%s %s\n", dirname(UNDEF
), pp
.firstop
->value
);
881 pp
.lastop
= pp
.firstop
;
882 pp
.firstop
= pp
.firstop
->next
;
890 #%s !#%s(%s) || #%s(%s)\n\
897 , keyname(X_PREDEFINED
)
900 , keyname(X_PLUSPLUS
)
903 , keyname(X_COMPATIBILITY
)
905 , keyname(X_TRANSITION
)
921 , keyname(X_ALLMULTIPLE
)
924 , keyname(X_READONLY
)
929 for (kp
= readonlys
; s
= kp
->name
; kp
++)
933 sfprintf(sp
, "#%s %s\n", dirname(UNDEF
), s
);
945 , keyname(X_PREDEFINED
)
950 #%s __STDPP__directive #(%s)\n\
953 , keyname(V_DIRECTIVE
)
955 for (kp
= variables
; s
= kp
->name
; kp
++)
956 if (ppisid(*s
) || *s
++ == '+')
958 t
= *s
== '_' ? "" : "__";
959 sfprintf(sp
, "#%s %s%s%s #(%s)\n" , dirname(DEFINE
), t
, s
, t
, s
);
968 , keyname(X_READONLY
)
973 if (pp
.ppdefault
&& *pp
.ppdefault
)
974 sfprintf(sp
, "#%s \"%s\"\n", dirname(INCLUDE
), pp
.ppdefault
);
977 #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
978 #%s __STDC__ #(STDC)\n\
986 debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t
));
987 ppcomment
= pp
.comment
;
989 pplinesync
= pp
.linesync
;
991 PUSH_INIT(pp
.pass
, t
);
995 pp
.comment
= ppcomment
;
996 pp
.linesync
= pplinesync
;
999 if (error_info
.trace
)
1000 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1001 message((-1, "include directory %s%s%s%s", dp
->name
, (dp
->type
& TYPE_VENDOR
) ? " [VENDOR]" : "", (dp
->type
& TYPE_HOSTED
) ? " [HOSTED]" : "", dp
->c
? " [C]" : ""));
1004 if (pp
.test
& TEST_nonoise
)
1005 error_info
.trace
= c
;
1009 * this is sleazy but at least it's
1010 * hidden in the library
1012 #include <preroot.h>
1014 struct pplist
* preroot
;
1016 if ((preroot
= (struct pplist
*)hashget(pp
.prdtab
, "preroot")))
1017 setpreroot(NiL
, preroot
->value
);
1022 if (pp
.ignoresrc
> 1 && pp
.stddirs
!= pp
.firstdir
)
1023 error(1, "directories up to and including %s are for \"...\" include files only", pp
.stddirs
->name
);
1024 pp
.lcldirs
= pp
.lcldirs
->next
;
1029 ppmapinclude(pp
.ignore
, NiL
);
1034 pp
.state
|= STANDALONE
;
1036 ppfsm(FSM_COMPATIBILITY
, NiL
);
1038 ppfsm(FSM_PLUSPLUS
, NiL
);
1042 pp
.reset
.symtab
= pp
.symtab
;
1044 pp
.reset
.ro_state
= pp
.ro_state
;
1045 pp
.reset
.ro_mode
= pp
.ro_mode
;
1046 pp
.reset
.ro_option
= pp
.ro_option
;
1053 hashwalk(pp
.filtab
, 0, unguard
, NiL
);
1054 hashfree(pp
.symtab
);
1056 pp
.symtab
= hashalloc(NiL
, HASH_name
, "symbols", HASH_free
, undefine
, HASH_set
, HASH_ALLOCATE
|HASH_BUCKET
, 0);
1057 hashview(pp
.symtab
, pp
.reset
.symtab
);
1058 pp
.ro_state
= pp
.reset
.ro_state
;
1059 pp
.ro_mode
= pp
.reset
.ro_mode
;
1060 pp
.ro_option
= pp
.reset
.ro_option
;
1066 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA
));
1067 (*pp
.pragma
)(dirname(PRAGMA
), pp
.pass
, keyname(X_CHECKPOINT
), pp
.checkpoint
, 1);
1070 if (n
= pp
.filedeps
.flags
)
1072 if (!(n
& PP_deps_file
))
1075 pp
.option
|= KEEPNOTEXT
;
1078 if (n
& PP_deps_generated
)
1080 if (n
& PP_deps_local
)
1081 pp
.mode
&= ~HEADERDEPS
;
1082 else if (!(pp
.mode
& FILEDEPS
))
1083 pp
.mode
|= HEADERDEPS
;
1084 pp
.mode
|= FILEDEPS
;
1088 * push the main input file -- special case for hosted mark
1091 if (pp
.firstdir
->type
& TYPE_HOSTED
)
1092 pp
.mode
|= MARKHOSTED
;
1094 pp
.mode
&= ~MARKHOSTED
;
1096 if (!(pp
.mode
& DUMP
))
1099 if (!(p
= error_info
.file
))
1103 error_info
.file
= 0;
1107 p
= ppsetfile(p
)->name
;
1112 if (pp
.mode
& FILEDEPS
)
1114 if (s
= strrchr(error_info
.file
, '/'))
1117 s
= error_info
.file
;
1120 s
= strcpy(pp
.tmpbuf
, s
);
1121 if ((t
= p
= strrchr(s
, '.')) && (*++p
== 'c' || *p
== 'C'))
1136 if (pp
.state
& NOTEXT
)
1137 pp
.filedeps
.sp
= sfstdout
;
1141 if (!(pp
.filedeps
.sp
= sfopen(NiL
, s
, "w")))
1142 error(ERROR_SYSTEM
|3, "%s: cannot create", s
);
1145 pp
.column
= sfprintf(pp
.filedeps
.sp
, "%s :", s
);
1146 if (*error_info
.file
)
1147 pp
.column
+= sfprintf(pp
.filedeps
.sp
, " %s", error_info
.file
);
1149 if (xp
= pp
.firsttx
)
1151 if (!(sp
= sfstropen()))
1152 error(3, "temporary buffer allocation error");
1155 sfprintf(sp
, "#%s \"%s\"\n", dirname(INCLUDE
), xp
->value
);
1159 PUSH_BUFFER("options", t
, 1);
1164 #if CHECKPOINT && POOL
1165 if (!(pp
.mode
& DUMP
) || pp
.pool
.input
)
1168 if (!(pp
.mode
& DUMP
))
1176 p
= va_arg(ap
, char*);
1177 if (!error_info
.file
)
1178 error_info
.file
= p
;
1180 if (open(p
, O_RDONLY
) != 0)
1181 error(ERROR_SYSTEM
|3, "%s: cannot read", p
);
1182 if (strmatch(p
, "*.(s|S|as|AS|asm|ASM)"))
1184 set(&pp
.mode
, CATLITERAL
, 0);
1185 ppop(PP_SPACEOUT
, 1);
1193 if ((p
= va_arg(ap
, char*)) && *p
)
1196 pp
.lasttx
= pp
.lasttx
->next
= newof(0, struct oplist
, 1, 0);
1198 pp
.firsttx
= pp
.lasttx
= newof(0, struct oplist
, 1, 0);
1200 pp
.lasttx
->value
= p
;
1206 set(&pp
.option
, KEYARGS
, va_arg(ap
, int));
1207 if (pp
.option
& KEYARGS
)
1209 set(&pp
.mode
, CATLITERAL
, 1);
1211 error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
1215 pp
.linesync
= va_arg(ap
, PPLINESYNC
);
1218 if (va_arg(ap
, int))
1219 pp
.flags
|= PP_linebase
;
1221 pp
.flags
&= ~PP_linebase
;
1224 if (va_arg(ap
, int))
1225 pp
.flags
|= PP_linefile
;
1227 pp
.flags
&= ~PP_linefile
;
1230 if (!(p
= va_arg(ap
, char*)))
1233 pp
.lineid
= strdup(p
);
1235 pp
.option
|= IGNORELINE
;
1238 if ((n
= va_arg(ap
, int)) >= 1)
1239 pp
.flags
|= PP_linetype
;
1241 pp
.flags
&= ~PP_linetype
;
1243 pp
.flags
|= PP_linehosted
;
1245 pp
.flags
&= ~PP_linehosted
;
1251 pp
.stddirs
= pp
.lastdir
;
1252 if (!(pp
.ro_option
& PREFIX
))
1253 pp
.option
&= ~PREFIX
;
1256 pp
.macref
= va_arg(ap
, PPMACREF
);
1259 set(&pp
.mode
, ALLMULTIPLE
, va_arg(ap
, int));
1262 set(&pp
.option
, NOHASH
, va_arg(ap
, int));
1265 op
= va_arg(ap
, int);
1266 set(&pp
.option
, NOISE
, op
);
1267 set(&pp
.option
, NOISEFILTER
, op
< 0);
1270 pp
.optarg
= va_arg(ap
, PPOPTARG
);
1273 pp
.outfile
= va_arg(ap
, char*);
1274 if (identical(pp
.outfile
, 0))
1275 error(3, "%s: identical to input", pp
.outfile
);
1277 if (open(pp
.outfile
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
) != 1)
1278 error(ERROR_SYSTEM
|3, "%s: cannot create", pp
.outfile
);
1280 case PP_PASSTHROUGH
:
1281 if (!(pp
.state
& COMPILE
))
1282 set(&pp
.state
, PASSTHROUGH
, va_arg(ap
, int));
1285 set(&pp
.mode
, PEDANTIC
, va_arg(ap
, int));
1287 case PP_PLUSCOMMENT
:
1288 set(&pp
.option
, PLUSCOMMENT
, va_arg(ap
, int));
1290 ppfsm(FSM_PLUSPLUS
, NiL
);
1293 set(&pp
.option
, PLUSPLUS
, va_arg(ap
, int));
1294 set(&pp
.option
, PLUSCOMMENT
, va_arg(ap
, int));
1296 ppfsm(FSM_PLUSPLUS
, NiL
);
1301 if (va_arg(ap
, int))
1304 pp
.pool
.input
= dup(0);
1305 pp
.pool
.output
= dup(1);
1307 if (!identical(p
, 0))
1309 if (!identical(p
, 1))
1314 error(3, "preprocessor not compiled with input pool enabled [POOL]");
1319 pp
.pragma
= va_arg(ap
, PPPRAGMA
);
1321 case PP_PRAGMAFLAGS
:
1322 if (p
= va_arg(ap
, char*))
1329 if ((c
= (int)hashref(pp
.strtab
, p
)) > 0 && c
<= X_last_option
)
1334 pp
.probe
= va_arg(ap
, char*);
1337 p
= va_arg(ap
, char*);
1338 c
= va_arg(ap
, int);
1340 ppfsm(c
? FSM_QUOTADD
: FSM_QUOTDEL
, p
);
1343 set(&pp
.option
, REGUARD
, va_arg(ap
, int));
1346 if ((pp
.state
& COMPILE
) && (p
= va_arg(ap
, char*)))
1348 if (!(sp
= sfstropen()))
1349 error(3, "temporary buffer allocation error");
1352 if (s
= strchr(p
, '='))
1358 for (t
= s
+ strlen(s
); t
> s
&& *(t
- 1) == '_'; t
--);
1363 op
= ((key
= ppkeyref(pp
.symtab
, s
)) && (key
->sym
.flags
& SYM_LEX
)) ? key
->lex
: T_NOISE
;
1364 if (pp
.test
& 0x0400)
1365 error(1, "reserved#1 `%s' %d", s
, op
);
1368 if (!(key
= ppkeyget(pp
.symtab
, p
)))
1369 key
= ppkeyset(pp
.symtab
, NiL
);
1370 else if (!(key
->sym
.flags
& SYM_LEX
))
1372 struct ppsymbol tmp
;
1375 hashlook(pp
.symtab
, p
, HASH_DELETE
, NiL
);
1376 key
= ppkeyset(pp
.symtab
, NiL
);
1377 key
->sym
.flags
= tmp
.flags
;
1378 key
->sym
.macro
= tmp
.macro
;
1379 key
->sym
.value
= tmp
.value
;
1380 key
->sym
.hidden
= tmp
.hidden
;
1382 if (!(key
->sym
.flags
& SYM_KEYWORD
))
1384 key
->sym
.flags
|= SYM_KEYWORD
|SYM_LEX
;
1386 if (pp
.test
& 0x0400)
1387 error(1, "reserved#2 `%s' %d", p
, op
);
1393 set(&pp
.state
, SPACEOUT
, va_arg(ap
, int));
1401 if ((pp
.lastdir
->next
->name
= ((p
= va_arg(ap
, char*)) && *p
) ? p
: NiL
) && !stat(p
, &st
))
1402 SAVEID(&pp
.lastdir
->next
->id
, &st
);
1403 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1405 for (hp
= pp
.firstdir
; hp
!= dp
; hp
= hp
->next
)
1406 if (hp
->name
&& SAMEID(&hp
->id
, &dp
->id
))
1409 if (dp
->type
& TYPE_HOSTED
)
1410 hp
->type
|= TYPE_HOSTED
;
1412 hp
->type
&= ~TYPE_HOSTED
;
1416 set(&pp
.state
, TRANSITION
, 0);
1417 pp
.flags
&= ~PP_transition
;
1418 set(&pp
.state
, STRICT
, va_arg(ap
, int));
1419 if (pp
.state
& STRICT
)
1420 pp
.flags
|= PP_strict
;
1422 pp
.flags
&= ~PP_strict
;
1425 if (p
= va_arg(ap
, char*))
1428 while (*p
== ' ' || *p
== '\t') p
++;
1429 for (s
= p
; n
= *s
; s
++)
1430 if (n
== ',' || n
== ' ' || n
== '\t')
1438 if (*p
== 'n' && *(p
+ 1) == 'o')
1445 if (streq(p
, "count"))
1447 else if (streq(p
, "hashcount"))
1449 else if (streq(p
, "hashdump"))
1451 else if (streq(p
, "hit"))
1453 else if (streq(p
, "init"))
1454 n
= TEST_noinit
|TEST_INVERT
;
1455 else if (streq(p
, "noise"))
1456 n
= TEST_nonoise
|TEST_INVERT
;
1457 else if (streq(p
, "proto"))
1458 n
= TEST_noproto
|TEST_INVERT
;
1459 else if (*p
>= '0' && *p
<= '9')
1460 n
= strtoul(p
, NiL
, 0);
1463 error(1, "%s: unknown test", p
);
1466 if (n
& TEST_INVERT
)
1476 debug((-4, "test = 0%o", pp
.test
));
1480 set(&pp
.state
, STRICT
, 0);
1481 pp
.flags
&= ~PP_strict
;
1482 set(&pp
.state
, TRANSITION
, va_arg(ap
, int));
1483 if (pp
.state
& TRANSITION
)
1484 pp
.flags
|= PP_transition
;
1486 pp
.flags
&= ~PP_transition
;
1491 if ((op
= va_arg(ap
, int)) < 0)
1493 set(&pp
.option
, TRUNCATE
, op
);
1494 if (pp
.option
& TRUNCATE
)
1498 Hash_position_t
* pos
;
1503 pp
.symtab
= hashalloc(NiL
, HASH_set
, tab
? HASH_ALLOCATE
: 0, HASH_compare
, trunccomp
, HASH_hash
, trunchash
, HASH_name
, "truncate", 0);
1504 if (tab
&& (pos
= hashscan(tab
, 0)))
1506 if (p
= hashnext(pos
))
1510 hashlook(pp
.symtab
, (char*)p
, HASH_BUCKET
|HASH_INSTALL
, NiL
);
1519 p
= va_arg(ap
, char*);
1520 c
= va_arg(ap
, int) != 0;
1522 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1523 dp
->type
&= ~TYPE_VENDOR
;
1524 else if (streq(p
, "-"))
1526 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1528 dp
->type
|= TYPE_VENDOR
;
1530 dp
->type
&= ~TYPE_VENDOR
;
1532 else if (!stat((pathcanon(p
, 0), p
), &st
))
1535 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1537 if (!c
&& ((dp
->type
& TYPE_VENDOR
) || dp
->name
&& SAMEID(&dp
->id
, &st
)))
1540 dp
->type
|= TYPE_VENDOR
;
1542 dp
->type
&= ~TYPE_VENDOR
;
1547 set(&pp
.state
, WARN
, va_arg(ap
, int));
1550 error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op
);
1553 error(3, "ppop(%d): invalid preprocessor operation", op
);