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
;
323 * NOTE: PP_INIT must be done before the first pplex() call
324 * PP_DONE must be done after the last pplex() call
325 * PP_INIT-PP_DONE must be done for each new PP_INPUT
333 register struct ppkeyword
* kp
;
340 struct ppsymkey
* key
;
345 PPLINESYNC pplinesync
;
347 static int initialized
;
360 if ((p
= va_arg(ap
, char*)) && *p
)
363 pp
.lastop
= (pp
.lastop
->next
= newof(0, struct oplist
, 1, 0));
365 pp
.firstop
= pp
.lastop
= newof(0, struct oplist
, 1, 0);
367 pp
.lastop
->value
= p
;
371 pp
.builtin
= va_arg(ap
, PPBUILTIN
);
374 p
= va_arg(ap
, char*);
379 else if (streq(p
, "-"))
382 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
387 if (!*p
|| stat((pathcanon(p
, 0), p
), &st
))
391 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
393 if (!pp
.c
&& (dp
->c
|| dp
->name
&& SAMEID(&dp
->id
, &st
)))
400 SAVEID(&pp
.cdir
.id
, &st
);
406 if (p
= va_arg(ap
, char*))
409 xp
= newof(0, struct oplist
, 1, c
+ 1);
410 xp
->value
= ((char*)xp
) + sizeof(struct oplist
);
413 while (*p
&& *p
!= c
)
416 xp
->op
= s
- xp
->value
;
418 if (*p
&& *++p
&& *p
!= c
)
420 while (*p
&& *p
!= c
)
430 if (pp
.comment
= va_arg(ap
, PPCOMMENT
))
431 pp
.flags
|= PP_comment
;
433 pp
.flags
&= ~PP_comment
;
435 case PP_COMPATIBILITY
:
436 set(&pp
.state
, COMPATIBILITY
, va_arg(ap
, int));
439 ppfsm(FSM_COMPATIBILITY
, NiL
);
441 if (pp
.state
& COMPATIBILITY
)
442 error(3, "preprocessor not compiled with compatibility dialect enabled [COMPATIBLE]");
444 if (pp
.state
& COMPATIBILITY
)
445 pp
.flags
|= PP_compatibility
;
447 pp
.flags
&= ~PP_compatibility
;
454 pp
.symtab
= hashalloc(NiL
, HASH_name
, "symbols", 0);
455 if (kp
= va_arg(ap
, struct ppkeyword
*))
456 for (; s
= kp
->name
; kp
++)
466 if (!(pp
.option
& PLUSPLUS
))
473 if (key
= ppkeyset(pp
.symtab
, s
))
476 key
->lex
= kp
->value
;
481 error_info
.trace
= va_arg(ap
, int);
484 if (p
= va_arg(ap
, char*))
494 if (pp
.mode
& FILEDEPS
)
496 sfputc(pp
.filedeps
.sp
, '\n');
497 if (pp
.filedeps
.sp
== sfstdout
)
498 sfsync(pp
.filedeps
.sp
);
500 sfclose(pp
.filedeps
.sp
);
502 if (pp
.state
& STANDALONE
)
504 if ((pp
.state
& (NOTEXT
|HIDDEN
)) == HIDDEN
&& pplastout() != '\n')
511 set(&pp
.mode
, DUMP
, va_arg(ap
, int));
514 error(3, "preprocessor not compiled with checkpoint enabled [CHECKPOINT]");
518 if (n
= va_arg(ap
, int))
519 pp
.filedeps
.flags
|= n
;
521 pp
.filedeps
.flags
= 0;
524 error_info
.file
= va_arg(ap
, char*);
527 if (!(pp
.mode
& INIT
))
528 pp
.ro_mode
|= HOSTED
;
529 else if (pp
.ro_mode
& HOSTED
)
532 p
= va_arg(ap
, char*);
537 else if (streq(p
, "-"))
540 set(&pp
.mode
, HOSTED
, c
);
543 pp
.hosted
= c
? 1 : 2;
544 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
546 dp
->type
|= TYPE_HOSTED
;
548 dp
->type
&= ~TYPE_HOSTED
;
553 if (!*p
|| stat((pathcanon(p
, 0), p
), &st
))
557 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
559 if (!pp
.hosted
&& ((dp
->type
& TYPE_HOSTED
) || dp
->name
&& SAMEID(&dp
->id
, &st
)))
562 dp
->type
|= TYPE_HOSTED
;
564 dp
->type
&= ~TYPE_HOSTED
;
569 SAVEID(&pp
.hostdir
.id
, &st
);
575 p
= va_arg(ap
, char*);
578 ppfsm(c
? FSM_IDADD
: FSM_IDDEL
, p
);
581 if (p
= va_arg(ap
, char*))
584 ppsetfile(p
)->guard
= INC_IGNORE
;
585 message((-3, "%s: ignore", p
));
591 pp
.ignore
= va_arg(ap
, char*);
594 if ((p
= va_arg(ap
, char*)) && *p
)
599 for (dp
= pp
.stddirs
; dp
= dp
->next
;)
600 if (dp
->name
&& SAMEID(&dp
->id
, &st
))
602 if (pp
.cdir
.path
&& SAMEID(&pp
.cdir
.id
, &st
))
607 if (pp
.hostdir
.path
&& SAMEID(&pp
.hostdir
.id
, &st
))
612 if ((pp
.mode
& INIT
) && !(pp
.ro_mode
& INIT
))
614 c
= dp
&& dp
->c
|| pp
.c
== 1;
615 n
= dp
&& (dp
->type
& TYPE_HOSTED
) || pp
.hosted
== 1;
616 if (!dp
|| dp
== pp
.lastdir
->next
)
621 n
= dp
->type
& TYPE_HOSTED
;
623 dp
= newof(0, struct ppdirs
, 1, 0);
625 SAVEID(&dp
->id
, &st
);
626 dp
->type
|= TYPE_INCLUDE
;
627 dp
->index
= INC_LOCAL
+ pp
.ignoresrc
!= 0;
628 dp
->next
= pp
.lastdir
->next
;
629 pp
.lastdir
= pp
.lastdir
->next
= dp
;
633 dp
->type
|= TYPE_HOSTED
;
635 dp
->type
&= ~TYPE_HOSTED
;
639 pp
.incref
= va_arg(ap
, PPINCREF
);
647 error_info
.errors
= 0;
648 error_info
.warnings
= 0;
653 * context initialization
659 * out of malloc is fatal
665 * initialize the error message interface
668 error_info
.version
= (char*)pp
.version
;
669 #if DEBUG & TRACE_debug
670 error_info
.auxilliary
= context
;
675 * initialize pplex tables
678 ppfsm(FSM_INIT
, NiL
);
681 * fixed macro stack size -- room for improvement
684 pp
.macp
= newof(0, struct ppmacstk
, DEFMACSTACK
, 0);
685 pp
.macp
->next
= pp
.macp
+ 1;
686 pp
.maxmac
= (char*)pp
.macp
+ DEFMACSTACK
;
690 * initial include/if control stack
693 pp
.control
= newof(0, long, pp
.constack
, 0);
694 pp
.maxcon
= pp
.control
+ pp
.constack
- 1;
705 ppop(PP_COMPATIBILITY
, 0);
706 ppop(PP_TRANSITION
, 1);
710 ppop(PP_COMPATIBILITY
, 0);
714 ppop(PP_COMPATIBILITY
, 1);
715 ppop(PP_PLUSPLUS
, 1);
716 ppop(PP_TRANSITION
, 1);
719 ppop(PP_COMPATIBILITY
, 0);
720 ppop(PP_PLUSPLUS
, 1);
724 ppop(PP_COMPATIBILITY
, 1);
729 ppop(PP_COMPATIBILITY
, 1);
730 ppop(PP_TRANSITION
, 0);
733 ppop(PP_COMPATIBILITY
, 1);
734 ppop(PP_TRANSITION
, 1);
737 if (!(pp
.state
& WARN
) && !(pp
.arg_style
& STYLE_gnu
))
738 ppop(PP_PEDANTIC
, 1);
739 if (pp
.state
& PASSTHROUGH
)
741 if (pp
.state
& COMPILE
)
743 pp
.state
&= ~PASSTHROUGH
;
744 error(1, "passthrough ignored for compile");
748 ppop(PP_COMPATIBILITY
, 1);
749 ppop(PP_HOSTDIR
, "-", 1);
750 ppop(PP_SPACEOUT
, 1);
751 set(&pp
.state
, DISABLE
, va_arg(ap
, int));
756 * create the hash tables
760 pp
.symtab
= hashalloc(NiL
, HASH_name
, "symbols", 0);
763 pp
.dirtab
= hashalloc(REFONE
, HASH_name
, "directives", 0);
764 inithash(pp
.dirtab
, directives
);
767 pp
.filtab
= hashalloc(REFALL
, HASH_name
, "files", 0);
769 pp
.prdtab
= hashalloc(REFALL
, HASH_name
, "predicates", 0);
772 pp
.strtab
= hashalloc(REFALL
, HASH_name
, "strings", 0);
773 inithash(pp
.strtab
, options
);
774 inithash(pp
.strtab
, predicates
);
775 inithash(pp
.strtab
, variables
);
777 pp
.optflags
[X_PROTOTYPED
] = OPT_GLOBAL
;
778 pp
.optflags
[X_SYSTEM_HEADER
] = OPT_GLOBAL
|OPT_PASS
;
781 * mark macros that are builtin predicates
784 for (kp
= predicates
; s
= kp
->name
; kp
++)
788 ppassert(DEFINE
, s
, 0);
792 * the remaining entry names must be allocated
795 hashset(pp
.dirtab
, HASH_ALLOCATE
);
796 hashset(pp
.filtab
, HASH_ALLOCATE
);
797 hashset(pp
.prdtab
, HASH_ALLOCATE
);
798 hashset(pp
.strtab
, HASH_ALLOCATE
);
799 hashset(pp
.symtab
, HASH_ALLOCATE
);
800 if (pp
.test
& TEST_nonoise
)
802 c
= error_info
.trace
;
803 error_info
.trace
= 0;
806 if (!(pp
.test
& TEST_noinit
))
811 * compose, push and read the builtin initialization script
814 if (!(sp
= sfstropen()))
815 error(3, "temporary buffer allocation error");
818 #%s %s:%s \"/#<assert> /\" \"/assert /%s #/\"\n\
819 #%s %s:%s \"/#<unassert> /\" \"/unassert /%s #/\"\n\
829 if (pp
.ppdefault
&& *pp
.ppdefault
)
833 c
= pp
.lastdir
->next
->type
;
834 pp
.lastdir
->next
->type
= 0;
836 if (ppsearch(pp
.ppdefault
, T_STRING
, SEARCH_EXISTS
) < 0)
839 if (!(pp
.ppdefault
= pathprobe(pp
.path
, NiL
, "C", pp
.pass
, pp
.probe
? pp
.probe
: PPPROBE
, 0)))
840 error(1, "cannot determine default definitions for %s", pp
.probe
? pp
.probe
: PPPROBE
);
843 pp
.lastdir
->next
->type
= c
;
847 switch (pp
.firstop
->op
)
850 sfprintf(sp
, "#%s #%s\n", dirname(DEFINE
), pp
.firstop
->value
);
853 if (*pp
.firstop
->value
== '#')
854 sfprintf(sp
, "#%s %s\n", dirname(DEFINE
), pp
.firstop
->value
);
857 if (s
= strchr(pp
.firstop
->value
, '='))
858 sfprintf(sp
, "#%s %-.*s %s\n", dirname(DEFINE
), s
- pp
.firstop
->value
, pp
.firstop
->value
, s
+ 1);
860 sfprintf(sp
, "#%s %s 1\n", dirname(DEFINE
), pp
.firstop
->value
);
864 sfprintf(sp
, "#%s\n", pp
.firstop
->value
);
867 if (s
= strchr(pp
.firstop
->value
, '='))
868 sfprintf(sp
, "#%s %s:%-.*s %s\n", dirname(PRAGMA
), pp
.pass
, s
- pp
.firstop
->value
, pp
.firstop
->value
, s
+ 1);
870 sfprintf(sp
, "#%s %s:%s\n", dirname(PRAGMA
), pp
.pass
, pp
.firstop
->value
);
873 sfprintf(sp
, "#%s \"%s\"\n", dirname(INCLUDE
), pp
.firstop
->value
);
876 sfprintf(sp
, "#%s %s\n", dirname(UNDEF
), pp
.firstop
->value
);
879 pp
.lastop
= pp
.firstop
;
880 pp
.firstop
= pp
.firstop
->next
;
888 #%s !#%s(%s) || #%s(%s)\n\
895 , keyname(X_PREDEFINED
)
898 , keyname(X_PLUSPLUS
)
901 , keyname(X_COMPATIBILITY
)
903 , keyname(X_TRANSITION
)
919 , keyname(X_ALLMULTIPLE
)
922 , keyname(X_READONLY
)
927 for (kp
= readonlys
; s
= kp
->name
; kp
++)
931 sfprintf(sp
, "#%s %s\n", dirname(UNDEF
), s
);
943 , keyname(X_PREDEFINED
)
948 #%s __STDPP__directive #(%s)\n\
951 , keyname(V_DIRECTIVE
)
953 for (kp
= variables
; s
= kp
->name
; kp
++)
954 if (ppisid(*s
) || *s
++ == '+')
956 t
= *s
== '_' ? "" : "__";
957 sfprintf(sp
, "#%s %s%s%s #(%s)\n" , dirname(DEFINE
), t
, s
, t
, s
);
966 , keyname(X_READONLY
)
971 if (pp
.ppdefault
&& *pp
.ppdefault
)
972 sfprintf(sp
, "#%s \"%s\"\n", dirname(INCLUDE
), pp
.ppdefault
);
975 #%s !defined(__STDC__) && (!#option(compatibility) || #option(transition))\n\
976 #%s __STDC__ #(STDC)\n\
984 debug((-9, "\n/* begin initialization */\n%s/* end initialization */", t
));
985 ppcomment
= pp
.comment
;
987 pplinesync
= pp
.linesync
;
989 PUSH_INIT(pp
.pass
, t
);
993 pp
.comment
= ppcomment
;
994 pp
.linesync
= pplinesync
;
997 if (error_info
.trace
)
998 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
999 message((-1, "include directory %s%s%s%s", dp
->name
, (dp
->type
& TYPE_VENDOR
) ? " [VENDOR]" : "", (dp
->type
& TYPE_HOSTED
) ? " [HOSTED]" : "", dp
->c
? " [C]" : ""));
1002 if (pp
.test
& TEST_nonoise
)
1003 error_info
.trace
= c
;
1007 * this is sleazy but at least it's
1008 * hidden in the library
1010 #include <preroot.h>
1012 struct pplist
* preroot
;
1014 if ((preroot
= (struct pplist
*)hashget(pp
.prdtab
, "preroot")))
1015 setpreroot(NiL
, preroot
->value
);
1020 if (pp
.ignoresrc
> 1 && pp
.stddirs
!= pp
.firstdir
)
1021 error(1, "directories up to and including %s are for \"...\" include files only", pp
.stddirs
->name
);
1022 pp
.lcldirs
= pp
.lcldirs
->next
;
1027 ppmapinclude(pp
.ignore
, NiL
);
1032 pp
.state
|= STANDALONE
;
1034 ppfsm(FSM_COMPATIBILITY
, NiL
);
1036 ppfsm(FSM_PLUSPLUS
, NiL
);
1040 pp
.reset
.symtab
= pp
.symtab
;
1042 pp
.reset
.ro_state
= pp
.ro_state
;
1043 pp
.reset
.ro_mode
= pp
.ro_mode
;
1044 pp
.reset
.ro_option
= pp
.ro_option
;
1051 hashwalk(pp
.filtab
, 0, unguard
, NiL
);
1052 hashfree(pp
.symtab
);
1054 pp
.symtab
= hashalloc(NiL
, HASH_name
, "symbols", HASH_free
, undefine
, HASH_set
, HASH_ALLOCATE
|HASH_BUCKET
, 0);
1055 hashview(pp
.symtab
, pp
.reset
.symtab
);
1056 pp
.ro_state
= pp
.reset
.ro_state
;
1057 pp
.ro_mode
= pp
.reset
.ro_mode
;
1058 pp
.ro_option
= pp
.reset
.ro_option
;
1064 error(3, "#%s must be enabled for checkpoints", dirname(PRAGMA
));
1065 (*pp
.pragma
)(dirname(PRAGMA
), pp
.pass
, keyname(X_CHECKPOINT
), pp
.checkpoint
, 1);
1068 if (n
= pp
.filedeps
.flags
)
1070 if (!(n
& PP_deps_file
))
1073 pp
.option
|= KEEPNOTEXT
;
1076 if (n
& PP_deps_generated
)
1078 if (n
& PP_deps_local
)
1079 pp
.mode
&= ~HEADERDEPS
;
1080 else if (!(pp
.mode
& FILEDEPS
))
1081 pp
.mode
|= HEADERDEPS
;
1082 pp
.mode
|= FILEDEPS
;
1086 * push the main input file -- special case for hosted mark
1089 if (pp
.firstdir
->type
& TYPE_HOSTED
)
1090 pp
.mode
|= MARKHOSTED
;
1092 pp
.mode
&= ~MARKHOSTED
;
1094 if (!(pp
.mode
& DUMP
))
1097 if (!(p
= error_info
.file
))
1101 error_info
.file
= 0;
1105 p
= ppsetfile(p
)->name
;
1110 if (pp
.mode
& FILEDEPS
)
1112 if (s
= strrchr(error_info
.file
, '/'))
1115 s
= error_info
.file
;
1118 s
= strcpy(pp
.tmpbuf
, s
);
1119 if ((t
= p
= strrchr(s
, '.')) && (*++p
== 'c' || *p
== 'C'))
1134 if (pp
.state
& NOTEXT
)
1135 pp
.filedeps
.sp
= sfstdout
;
1139 if (!(pp
.filedeps
.sp
= sfopen(NiL
, s
, "w")))
1140 error(ERROR_SYSTEM
|3, "%s: cannot create", s
);
1143 pp
.column
= sfprintf(pp
.filedeps
.sp
, "%s :", s
);
1144 if (*error_info
.file
)
1145 pp
.column
+= sfprintf(pp
.filedeps
.sp
, " %s", error_info
.file
);
1147 if (xp
= pp
.firsttx
)
1149 if (!(sp
= sfstropen()))
1150 error(3, "temporary buffer allocation error");
1153 sfprintf(sp
, "#%s \"%s\"\n", dirname(INCLUDE
), xp
->value
);
1157 PUSH_BUFFER("options", t
, 1);
1162 #if CHECKPOINT && POOL
1163 if (!(pp
.mode
& DUMP
) || pp
.pool
.input
)
1166 if (!(pp
.mode
& DUMP
))
1174 p
= va_arg(ap
, char*);
1175 if (!error_info
.file
)
1176 error_info
.file
= p
;
1178 if (open(p
, O_RDONLY
) != 0)
1179 error(ERROR_SYSTEM
|3, "%s: cannot read", p
);
1180 if (strmatch(p
, "*.(s|S|as|AS|asm|ASM)"))
1182 set(&pp
.mode
, CATLITERAL
, 0);
1183 ppop(PP_SPACEOUT
, 1);
1191 if ((p
= va_arg(ap
, char*)) && *p
)
1194 pp
.lasttx
= pp
.lasttx
->next
= newof(0, struct oplist
, 1, 0);
1196 pp
.firsttx
= pp
.lasttx
= newof(0, struct oplist
, 1, 0);
1198 pp
.lasttx
->value
= p
;
1204 set(&pp
.option
, KEYARGS
, va_arg(ap
, int));
1205 if (pp
.option
& KEYARGS
)
1207 set(&pp
.mode
, CATLITERAL
, 1);
1209 error(3, "preprocessor not compiled with macro keyword arguments enabled [MACKEYARGS]");
1213 pp
.linesync
= va_arg(ap
, PPLINESYNC
);
1216 if (va_arg(ap
, int))
1217 pp
.flags
|= PP_linebase
;
1219 pp
.flags
&= ~PP_linebase
;
1222 if (va_arg(ap
, int))
1223 pp
.flags
|= PP_linefile
;
1225 pp
.flags
&= ~PP_linefile
;
1228 if (!(p
= va_arg(ap
, char*)))
1231 pp
.lineid
= strdup(p
);
1233 pp
.option
|= IGNORELINE
;
1236 if ((n
= va_arg(ap
, int)) >= 1)
1237 pp
.flags
|= PP_linetype
;
1239 pp
.flags
&= ~PP_linetype
;
1241 pp
.flags
|= PP_linehosted
;
1243 pp
.flags
&= ~PP_linehosted
;
1249 pp
.stddirs
= pp
.lastdir
;
1250 if (!(pp
.ro_option
& PREFIX
))
1251 pp
.option
&= ~PREFIX
;
1254 pp
.macref
= va_arg(ap
, PPMACREF
);
1257 set(&pp
.mode
, ALLMULTIPLE
, va_arg(ap
, int));
1260 set(&pp
.option
, NOHASH
, va_arg(ap
, int));
1263 op
= va_arg(ap
, int);
1264 set(&pp
.option
, NOISE
, op
);
1265 set(&pp
.option
, NOISEFILTER
, op
< 0);
1268 pp
.optarg
= va_arg(ap
, PPOPTARG
);
1271 pp
.outfile
= va_arg(ap
, char*);
1272 if (identical(pp
.outfile
, 0))
1273 error(3, "%s: identical to input", pp
.outfile
);
1275 if (open(pp
.outfile
, O_WRONLY
|O_CREAT
|O_TRUNC
, S_IRUSR
|S_IWUSR
|S_IRGRP
|S_IWGRP
|S_IROTH
|S_IWOTH
) != 1)
1276 error(ERROR_SYSTEM
|3, "%s: cannot create", pp
.outfile
);
1278 case PP_PASSTHROUGH
:
1279 if (!(pp
.state
& COMPILE
))
1280 set(&pp
.state
, PASSTHROUGH
, va_arg(ap
, int));
1283 set(&pp
.mode
, PEDANTIC
, va_arg(ap
, int));
1285 case PP_PLUSCOMMENT
:
1286 set(&pp
.option
, PLUSCOMMENT
, va_arg(ap
, int));
1288 ppfsm(FSM_PLUSPLUS
, NiL
);
1291 set(&pp
.option
, PLUSPLUS
, va_arg(ap
, int));
1292 set(&pp
.option
, PLUSCOMMENT
, va_arg(ap
, int));
1294 ppfsm(FSM_PLUSPLUS
, NiL
);
1299 if (va_arg(ap
, int))
1302 pp
.pool
.input
= dup(0);
1303 pp
.pool
.output
= dup(1);
1305 if (!identical(p
, 0))
1307 if (!identical(p
, 1))
1312 error(3, "preprocessor not compiled with input pool enabled [POOL]");
1317 pp
.pragma
= va_arg(ap
, PPPRAGMA
);
1319 case PP_PRAGMAFLAGS
:
1320 if (p
= va_arg(ap
, char*))
1327 if ((c
= (int)hashref(pp
.strtab
, p
)) > 0 && c
<= X_last_option
)
1332 pp
.probe
= va_arg(ap
, char*);
1335 p
= va_arg(ap
, char*);
1336 c
= va_arg(ap
, int);
1338 ppfsm(c
? FSM_QUOTADD
: FSM_QUOTDEL
, p
);
1341 set(&pp
.option
, REGUARD
, va_arg(ap
, int));
1344 if ((pp
.state
& COMPILE
) && (p
= va_arg(ap
, char*)))
1346 if (!(sp
= sfstropen()))
1347 error(3, "temporary buffer allocation error");
1350 if (s
= strchr(p
, '='))
1356 for (t
= s
+ strlen(s
); t
> s
&& *(t
- 1) == '_'; t
--);
1361 op
= ((key
= ppkeyref(pp
.symtab
, s
)) && (key
->sym
.flags
& SYM_LEX
)) ? key
->lex
: T_NOISE
;
1362 if (pp
.test
& 0x0400)
1363 error(1, "reserved#1 `%s' %d", s
, op
);
1366 if (!(key
= ppkeyget(pp
.symtab
, p
)))
1367 key
= ppkeyset(pp
.symtab
, NiL
);
1368 else if (!(key
->sym
.flags
& SYM_LEX
))
1370 struct ppsymbol tmp
;
1373 hashlook(pp
.symtab
, p
, HASH_DELETE
, NiL
);
1374 key
= ppkeyset(pp
.symtab
, NiL
);
1375 key
->sym
.flags
= tmp
.flags
;
1376 key
->sym
.macro
= tmp
.macro
;
1377 key
->sym
.value
= tmp
.value
;
1378 key
->sym
.hidden
= tmp
.hidden
;
1380 if (!(key
->sym
.flags
& SYM_KEYWORD
))
1382 key
->sym
.flags
|= SYM_KEYWORD
|SYM_LEX
;
1384 if (pp
.test
& 0x0400)
1385 error(1, "reserved#2 `%s' %d", p
, op
);
1391 set(&pp
.state
, SPACEOUT
, va_arg(ap
, int));
1399 if ((pp
.lastdir
->next
->name
= ((p
= va_arg(ap
, char*)) && *p
) ? p
: NiL
) && !stat(p
, &st
))
1400 SAVEID(&pp
.lastdir
->next
->id
, &st
);
1401 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1403 for (hp
= pp
.firstdir
; hp
!= dp
; hp
= hp
->next
)
1404 if (hp
->name
&& SAMEID(&hp
->id
, &dp
->id
))
1407 if (dp
->type
& TYPE_HOSTED
)
1408 hp
->type
|= TYPE_HOSTED
;
1410 hp
->type
&= ~TYPE_HOSTED
;
1414 set(&pp
.state
, TRANSITION
, 0);
1415 pp
.flags
&= ~PP_transition
;
1416 set(&pp
.state
, STRICT
, va_arg(ap
, int));
1417 if (pp
.state
& STRICT
)
1418 pp
.flags
|= PP_strict
;
1420 pp
.flags
&= ~PP_strict
;
1423 if (p
= va_arg(ap
, char*))
1426 while (*p
== ' ' || *p
== '\t') p
++;
1427 for (s
= p
; n
= *s
; s
++)
1428 if (n
== ',' || n
== ' ' || n
== '\t')
1436 if (*p
== 'n' && *(p
+ 1) == 'o')
1443 if (streq(p
, "count"))
1445 else if (streq(p
, "hashcount"))
1447 else if (streq(p
, "hashdump"))
1449 else if (streq(p
, "hit"))
1451 else if (streq(p
, "init"))
1452 n
= TEST_noinit
|TEST_INVERT
;
1453 else if (streq(p
, "noise"))
1454 n
= TEST_nonoise
|TEST_INVERT
;
1455 else if (streq(p
, "proto"))
1456 n
= TEST_noproto
|TEST_INVERT
;
1457 else if (*p
>= '0' && *p
<= '9')
1458 n
= strtoul(p
, NiL
, 0);
1461 error(1, "%s: unknown test", p
);
1464 if (n
& TEST_INVERT
)
1474 debug((-4, "test = 0%o", pp
.test
));
1478 set(&pp
.state
, STRICT
, 0);
1479 pp
.flags
&= ~PP_strict
;
1480 set(&pp
.state
, TRANSITION
, va_arg(ap
, int));
1481 if (pp
.state
& TRANSITION
)
1482 pp
.flags
|= PP_transition
;
1484 pp
.flags
&= ~PP_transition
;
1489 if ((op
= va_arg(ap
, int)) < 0)
1491 set(&pp
.option
, TRUNCATE
, op
);
1492 if (pp
.option
& TRUNCATE
)
1496 Hash_position_t
* pos
;
1501 pp
.symtab
= hashalloc(NiL
, HASH_set
, tab
? HASH_ALLOCATE
: 0, HASH_compare
, trunccomp
, HASH_hash
, trunchash
, HASH_name
, "truncate", 0);
1502 if (tab
&& (pos
= hashscan(tab
, 0)))
1504 if (p
= hashnext(pos
))
1508 hashlook(pp
.symtab
, (char*)p
, HASH_BUCKET
|HASH_INSTALL
, NiL
);
1517 p
= va_arg(ap
, char*);
1518 c
= va_arg(ap
, int) != 0;
1520 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1521 dp
->type
&= ~TYPE_VENDOR
;
1522 else if (streq(p
, "-"))
1524 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1526 dp
->type
|= TYPE_VENDOR
;
1528 dp
->type
&= ~TYPE_VENDOR
;
1530 else if (!stat((pathcanon(p
, 0), p
), &st
))
1533 for (dp
= pp
.firstdir
; dp
; dp
= dp
->next
)
1535 if (!c
&& ((dp
->type
& TYPE_VENDOR
) || dp
->name
&& SAMEID(&dp
->id
, &st
)))
1538 dp
->type
|= TYPE_VENDOR
;
1540 dp
->type
&= ~TYPE_VENDOR
;
1545 set(&pp
.state
, WARN
, va_arg(ap
, int));
1548 error(3, "ppop(%d): preprocessor operation must be done before PP_INIT", op
);
1551 error(3, "ppop(%d): invalid preprocessor operation", op
);