/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1984-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * make common definitions
 */

#include <ast.h>
#include <ls.h>
#include <ctype.h>
#include <dirent.h>
#include <fs3d.h>
#include <glob.h>
#include <hash.h>
#include <swap.h>
#include <namval.h>
#include <error.h>
#include <coshell.h>
#include <times.h>
#include <tok.h>
#include <setjmp.h>
#include <sfdisc.h>
#include <tmx.h>

#if DEBUG
#define debug(x)	do if (error_info.trace < 0) { error x; } while (0)
#define	PANIC		(ERROR_PANIC|ERROR_SOURCE|ERROR_SYSTEM),__FILE__,__LINE__
#else
#define debug(x)
#define	PANIC		ERROR_PANIC
#endif

#define COMMENT		'#'		/* make comment char		*/
#define MARK_CONTEXT	'\002'		/* context mark -- not in input!*/
#define MARK_QUOTE	'\003'		/* quote mark -- not in input!	*/
#define SALT		'#'		/* preprocessor control char	*/
#define VIEWOFFSET	'0'		/* char offset for view==0	*/

#if _WINIX
#define FILE_SPACE	'\001'		/* file name space		*/
#else
#define FILE_SPACE	'?'		/* file name space		*/
#endif

#define ATTRNAME	'.'		/* prefix to name an attribute	*/
#define ATTRSET		'+'		/* prefix to set an attribute	*/
#define ATTRCLEAR	'-'		/* prefix to clear an attribute	*/

#define CMDTRACE	(-6)		/* coshell trace debug level	*/
#define EXPTRACE	(-5)		/* explanation trace debug lev	*/

#define EXPLAIN		(state.user&&(state.explain||error_info.trace<=EXPTRACE))

#undef	atoi
#undef	atol
#undef	bind
#undef	clrbit		/* netbsd has one in <sys/param.h> */
#undef	optinit
#undef	setbit		/* netbsd has one in <sys/param.h> */

#define bind		bindrule /* avoids possible socket clash */
#define canon(x)	((state.context&&iscontextp(x,&state.tmppchar))?state.tmppchar:(state.mam.statix?mamcanon(x):pathcanon(x,0)))
#define clrbit(v,b)	((v)&=~(1L<<(b)))
#define getar(name)	((Dir_t*)hashget(table.ar,(name)))
#define getbound(name)	((char*)hashget(table.bound,(name)))
#define getdir(id)	((Dir_t*)hashget(table.dir,(char*)(id)))
#define getfile(name)	((File_t*)hashget(table.file,(name)))
#define getold(name)	((char*)hashget(table.oldvalue,(name)))
#define getreg(name)	((int*)hashget(table.regress,(name)))
#define getrule(name)	((Rule_t*)hashget(table.rule,(name)))
#define getvar(name)	((Var_t*)hashget(table.var,(name)))
#define message(x)	do if (error_info.trace < 0) { error x; } while (0)
#define notfile(r)	(((r)->property&(P_attribute|P_functional|P_make|P_operator|P_state|P_use|P_virtual))||((r)->dynamic&D_scope)||(r)->semaphore||((r)->property&P_dontcare)&&((r)->dynamic&D_bound)&&!(r)->time)
#define oldname(r)	do{if(getbound(r->uname))putbound(0,0);if(r->dynamic&D_alias)r->dynamic&=~D_alias;else putrule(r->name,0);r->name=r->uname;r->uname=0;}while(0)
#define putbound(n,d)	hashput(table.bound,(char*)(n),(char*)(d))
#define putar(name,d)	hashput(table.ar,(name),(char*)(d))
#define putdir(id,d)	hashput(table.dir,(char*)(id),(char*)(d))
#define putfile(name,f)	hashput(table.file,(char*)(name),(char*)(f))
#define putold(name,v)	hashput(table.oldvalue,(char*)(name),(char*)(v))
#define putptr(f,p)	(internal.ptr=(char*)(p),sfwrite(f,&internal.ptr,sizeof(internal.ptr)))
#define putreg(name,r)	hashput(table.regress,(char*)(name),(char*)(r))
#define putrule(name,r)	hashput(table.rule,(char*)(name),(char*)(r))
#define putvar(name,v)	hashput(table.var,(char*)(name),(char*)(v))
#define reason(x)	do if(EXPLAIN)explain x;while(0)
#define ropen(f,m)	((f)==internal.openfile?(internal.openfile=0,internal.openfd):open(f,m))
#define rsfopen(f)	((f)==internal.openfile?(internal.openfile=0,sfnew(NiL,NiL,SF_UNBOUND,internal.openfd,SF_READ)):sfopen(NiL,f,"r"))
#define setbit(v,b)	((v)|=(1L<<(b)))
#define shquote		shellquote /* netbsd has one in <stdlib.h>! */
#define statetimeq	timestateq /* avoids statetime symbol truncation clash */
#define timefix(t)      t-=(t<state.tolerance)?t:state.tolerance
#define trap()		(state.caught?handle():0)
#define tstbit(v,b)	((v)&(1L<<(b)))
#define unviewname(s)	(*(s)='(')
#define viewable(r)	((r->property&P_state)&&*r->name=='(')
#define viewname(s,v)	(*(s)=VIEWOFFSET+(v))
#define zero(x)		memzero(&(x),sizeof(x))

#define isaltstate(s)	(nametype(s,NiL)&(NAME_altstate))
#define iscontext(s)	(nametype(s,NiL)&(NAME_context))
#define iscontextp(s,p)	(nametype(s,p)&(NAME_context))
#define isdynamic(s)	(nametype(s,NiL)&(NAME_dynamic|NAME_glob))
#define isglob(s)	(nametype(s,NiL)&(NAME_glob))
#define isintvar(s)	(nametype(s,NiL)&(NAME_intvar))
#define isstate(s)	(nametype(s,NiL)&(NAME_staterule|NAME_altstate|NAME_statevar))
#define isstatevar(s)	(nametype(s,NiL)&(NAME_statevar))

#define freelist(x)	do{if(x){(x)->rule=(Rule_t*)internal.freelists;internal.freelists=(char*)(x);}}while(0)
#define freerule(r)	do{zero(*r);*((char**)r)=internal.freerules;internal.freerules=(char*)(r);}while(0)
#define freevar(v)	do{(v)->property&=(V_free|V_import);*((char**)v)=internal.freevars;internal.freevars=(char*)(v);}while(0)

#define newlist(x)	do{if(x=(List_t*)internal.freelists){if(x->next){x=x->next;*((char**)internal.freelists)=(char*)x->next;}else internal.freelists=(char*)x->rule;}else x=(List_t*)newchunk(&internal.freelists,sizeof(List_t));}while(0)
#define newrule(r)	do{if(r=(Rule_t*)internal.freerules){internal.freerules=(*((char**)r));zero(*r);}else r=(Rule_t*)newchunk(&internal.freerules,sizeof(Rule_t));}while(0)
#define newvar(v)	do{if(v=(Var_t*)internal.freevars){internal.freevars=(*((char**)v));}else v=(Var_t*)newchunk(&internal.freevars,sizeof(Var_t));}while(0)

#if CHAR_MIN < 0
#define ctable		(ctypes-(CHAR_MIN)+1)
#else
#define ctable		(ctypes)
#endif

#define istype(c,t)	(ctable[c]&(t))
#define settype(c,t)	(ctable[c]|=(t))
#define unsettype(c,t)	(ctable[c]&=~(t))

#define NOTYET		0	/* don't know what to do yet		*/
#define UPDATE		1	/* rule in process of being updated	*/
#define MAKING		2	/* executing update action		*/
#define TOUCH		3	/* archive member to be touched		*/
#define EXISTS		4	/* rule already exists in desired state	*/
#define IGNORE		5	/* rule make failed but ignore errors	*/
#define FAILED		6	/* rule make failed			*/
#define OLDRULE		7	/* makefile compiler old rule mark	*/

#define RECOMPILE	1	/* recompile make object		*/
#define COMPILED	2	/* make object compiled (if necessary)	*/
#define SAVED		3	/* make state saved			*/

#define DELETE	NiL		/* delete path component in edit()	*/
#define KEEP	((char*)1)	/* keep path component in edit()	*/

#define NOTIME	TMX_NOTIME	/* not checked time			*/
#define OLDTIME	((Time_t)(1))	/* oldest valid time			*/
#define CURTIME	tmxgettime()	/* high resolution current time		*/
#define CURSECS	((Seconds_t)time(NiL)) /* seconds resolution time	*/

/*
 * VAR and RULE must not change -- the rest must be in sequence
 */

#define VAR		0	/* state var from var in staterule()	*/
#define CONSISTENT	VAR	/* consistency check bits		*/
#define RULE		1	/* state rule in staterule()		*/
#define PREREQS		2	/* alternate prereqs in staterule()	*/
#define STATERULES	2	/* last staterule() index		*/

#define MINVALUE	32	/* minimum variable value length	*/
#define MAXJOBS		128	/* maximum number concurrent jobs	*/
#define MAXNAME		1024	/* maximum file pathname length		*/
#define PCTGARBAGE	10	/* maximum state garbage percentage	*/

#define MAXVIEW		(sizeof(Flags_t)*CHAR_BIT) /* max view index	*/

#if BINDINDEX
#define MAXBIND		UCHAR_MAX/* maximum bind index			*/
#endif

#define A_clear		(1<<0)	/* assertion() .CLEAR			*/
#define A_copy		(1<<1)	/* assertion() .COPY			*/
#define A_delete	(1<<2)	/* assertion() .DELETE			*/
#define A_group		(1<<3)	/* assertion() metarule (...) grouping	*/
#define A_insert	(1<<4)	/* assertion() .INSERT			*/
#define A_metarule	(1<<5)	/* assertion() pattern metarule 	*/
#define A_negate	(1<<6)	/* assertion() -attribute		*/
#define A_nooptions	(1<<7)	/* assertion() no more option prereqs	*/
#define A_norhs		(1<<8)	/* assertion() empty rhs		*/
#define A_null		(1<<9)	/* assertion() .NULL			*/
#define A_scan		(1<<10)	/* assertion() .SCAN			*/
#define A_scope		(1<<11)	/* assertion() metarule scope prereqs	*/
#define A_special	(1<<12)	/* assertion() .SPECIAL			*/
#define A_target	(1<<13)	/* assertion() set P_target		*/

#define C_ID1		(1<<0)	/* istype() first identifier char	*/
#define C_ID2		(1<<1)	/* istype() remaining id chars		*/
#define C_MATCH		(1<<2)	/* istype() shell pattern match chars	*/
#define C_OPTVAL	(1<<3)	/* istype() option value separator	*/
#define C_SEP		(1<<4)	/* istype() token separator		*/
#define C_TERMINAL	(1<<5)	/* istype() terminal chars		*/
#define C_VARIABLE1	(1<<6)	/* istype() first variable name char	*/
#define C_VARIABLE2	(1<<7)	/* istype() remaining variable chars	*/

#define C_VARPOS1	(1<<8)	/* istype() var superimposed code 1	*/
#define C_VARPOS2	(1<<9)	/* istype() var superimposed code 2	*/
#define C_VARPOS3	(1<<10)	/* istype() var superimposed code 3	*/
#define C_VARPOS4	(1<<11)	/* istype() var superimposed code 4	*/
#define C_VARPOS5	(1<<12)	/* istype() var superimposed code 5	*/
#define C_VARPOS6	(1<<13)	/* istype() var superimposed code 6	*/
#define C_VARPOS7	(1<<14)	/* istype() var superimposed code 7	*/
#define C_VARPOS8	(1L<<15)/* istype() var superimposed code 8	*/

#define NAME_altstate	0x001	/* altername state rule name		*/
#define NAME_assignment	0x002	/* assignment				*/
#define NAME_context	0x004	/* context string			*/
#define NAME_dynamic	0x008	/* requires dynamic expand()		*/
#define NAME_glob	0x010	/* requires dynamic glob()		*/
#define NAME_identifier	0x020	/* identifier name			*/
#define NAME_intvar	0x040	/* internal variable name		*/
#define NAME_option	0x080	/* option				*/
#define NAME_path	0x100	/* path name				*/
#define NAME_staterule	0x200	/* state rule name			*/
#define NAME_statevar	0x400	/* state variable name			*/
#define NAME_variable	0x800	/* variable name			*/

#define ARG_ASSIGN	(1<<0)	/* command line assignment arg flag	*/
#define ARG_SCRIPT	(1<<1)	/* command line script arg flag		*/
#define ARG_TARGET	(1<<2)	/* command line target arg flag		*/

#define BIND_DOT	(1<<0)	/* bindfile in .			*/
#define BIND_FORCE	(1<<1)	/* force bindfile current time		*/
#define BIND_MAKEFILE	(1<<2)	/* bindfile using makefile dirs		*/
#define BIND_RULE	(1<<3)	/* force bindfile makerule		*/

#define MERGE_ALL	(1<<0)	/* merge everything			*/
#define MERGE_ASSOC	(1<<1)	/* pattern association merge		*/
#define MERGE_ATTR	(1<<2)	/* merge just attributes		*/
#define MERGE_BOUND	(1<<3)	/* MERGE_ALL but no bind		*/
#define MERGE_FORCE	(1<<4)	/* override attributes			*/
#define MERGE_SCANNED	(1<<5)	/* MERGE_ALL but no entries|scanned	*/

#define COMP_BASE	(1<<0)	/* base rules prereq			*/
#define COMP_DONTCARE	(1<<1)	/* optional include prereq		*/
#define COMP_FILE	(1<<2)	/* -f prereq				*/
#define COMP_GLOBAL	(1<<3)	/* -g prereq				*/
#define COMP_INCLUDE	(1<<4)	/* include prereq			*/
#define COMP_OPTIONS	(1<<5)	/* -[DIU]* prereq			*/
#define COMP_RULES	(1<<6)	/* from explicit rules statement	*/
#define COMP_NSEC	(1<<7)	/* next prereq nsec			*/

#define PREREQ_APPEND	1	/* addprereq append			*/
#define PREREQ_DELETE	2	/* addprereq delete			*/
#define PREREQ_INSERT	3	/* addprereq insert			*/
#define PREREQ_LENGTH	4	/* addprereq insert by length		*/

#define SCAN_IGNORE	1	/* .SCAN.IGNORE scan index		*/
#define SCAN_NULL	2	/* .SCAN.NULL scan index		*/
#define SCAN_STATE	3	/* .SCAN.STATE scan index		*/
#define SCAN_USER	8	/* first user defined scan index	*/
#define SCAN_MAX	UCHAR_MAX/* max scan index			*/

#define CO_ALWAYS	(CO_USER<<0)	/* always exec			*/
#define CO_DATAFILE	(CO_USER<<1)	/* job output to state.tmpdata	*/
#define CO_ERRORS	(CO_USER<<2)	/* job had errors		*/
#define CO_FOREGROUND	(CO_USER<<3)	/* wait for completion		*/
#define CO_KEEPGOING	(CO_USER<<4)	/* keep going on job error	*/
#define CO_LOCALSTACK	(CO_USER<<5)	/* stack local vars for action	*/
#define CO_PRIMARY	(CO_USER<<6)	/* primary prereq added		*/
#define CO_SEMAPHORES	(CO_USER<<7)	/* release semaphores		*/
#define CO_URGENT	(CO_USER<<8)	/* enter job at top of queue	*/

/*
 * rule.property flags
 */

#define P_accept	(1<<0)		/* ignore state conflicts	*/
#define P_after		(1<<1)		/* make after parent update	*/
#define P_always	(1<<2)		/* execute even if !state.exec	*/
#define P_archive	(1<<3)		/* rule bound to archive file	*/
#define P_attribute	(1<<4)		/* rule is an attribute		*/
#define P_before	(1<<5)		/* make before parent update	*/
#define P_command	(1<<6)		/* command target -- no pattern	*/
#define P_dontcare	(1<<7)		/* don't care if rule made	*/
#define P_force		(1<<8)		/* target is always out of date	*/
#define P_foreground	(1<<9)		/* run action in foreground	*/
#define P_functional	(1<<10)		/* associated w/functional var	*/
#define P_ignore	(1<<11)		/* parent to ignore this prereq	*/
#define P_immediate	(1<<12)		/* rule needs immediate action	*/
#define P_implicit	(1<<13)		/* force implicit prereq checks	*/
#define P_internal	(1<<14)		/* don't compile unless prereq	*/
#define P_joint		(1L<<15)	/* pseudo for joint targets	*/
#define P_make		(1L<<16)	/* make (not shell) action	*/
#define P_metarule	(1L<<17)	/* metarule			*/
#define P_multiple	(1L<<18)	/* multi prereq occurrences OK	*/

#define P_local		(1L<<19)	/* local affinity		*/

#define P_operator	(1L<<20)	/* rule is an operator		*/
#define P_parameter	(1L<<21)	/* rule bound to parameter file	*/
#define P_readonly	(1L<<22)	/* no user modifications	*/
#define P_repeat	(1L<<23)	/* make even if already made	*/
#define P_state		(1L<<24)	/* state atom			*/
#define P_staterule	(1L<<25)	/* staterule			*/
#define P_statevar	(1L<<26)	/* statevar			*/
#define P_target	(1L<<27)	/* rule is an explicit target	*/
#define P_terminal	(1L<<28)	/* terminal target or metarule	*/
#define P_use		(1L<<29)	/* rule is a .USE script	*/
#define P_virtual	(1L<<30)	/* target is not a file		*/

#define P_read		(1L<<31)	/* read action output		*/

#define P_failure	(P_after|P_before)	/* conjoined		*/

/*
 * rule.dynamic flags
 */

#define D_alias		(1<<0)		/* more than one unbound name	*/
#define D_aliaschanged	(1<<1)		/* alias changed		*/
#define D_bound		(1<<2)		/* rule has been bound		*/
#define D_built		(1<<3)		/* triggered action built target*/
#define D_cached	(1<<4)		/* post assertion info cached	*/
#define D_compiled	(1<<5)		/* rule has been compiled	*/
#define D_dynamic	(1<<6)		/* must do dynamic expansion	*/
#define D_entries	(1<<7)		/* scanned rule has entries	*/
#define D_garbage	(1<<8)		/* state file GC mark		*/
#define D_hasafter	(1<<9)		/* rule has after prereqs	*/
#define D_hasbefore	(1<<10)		/* rule has before prereqs	*/

#define D_membertoo	(1<<11)		/* D_member was also set	*/
#define D_hassemaphore	(1<<12)		/* has rule.semaphore prereq	*/
#define D_same		(1<<13)		/* target unchanged by action	*/

#define D_lower		(1<<14)		/* state from lower view	*/

#define D_source	(1L<<15)	/* .SOURCE directory		*/

#define D_member	(1L<<16)	/* rule bound to archive member	*/

#define D_global	(1L<<17)	/* global view if view==0	*/

#define D_regular	(1L<<18)	/* rule bound to regular file	*/
#define D_scanned	(1L<<19)	/* has been scanned		*/
#define D_select0	(1L<<20)	/* $(...) select bit 0		*/
#define D_select1	(1L<<21)	/* $(...) select bit 1		*/
#define D_triggered	(1L<<22)	/* rule action triggered	*/

#define D_index		(1L<<23)	/* load time index consistency	*/

#define D_bindindex	(1L<<24)	/* bind index table entry	*/

#define D_intermediate	(1L<<25)	/* intermediate pretend target	*/

#define D_hasscope	(1L<<26)	/* has D_scope prereqs		*/
#define D_scope		(1L<<27)	/* scoped var assignment	*/

#define D_hasmake	(1L<<28)	/* rule has .MAKE after prereqs	*/

#define D_context	(1L<<29)	/* ref may be diff dir context	*/

#define D_lowres	(1L<<30)	/* low resolution time		*/

#define D_CLEAROBJECT	(~(D_bindindex|D_built|D_compiled|D_context|D_dynamic|D_index|D_lower|D_lowres|D_scope))

#define M_bind		(1<<0)		/* bind recursion mark		*/
#define M_compile	(1<<1)		/* compilation mark		*/
#define M_directory	(1<<2)		/* bind directory mark		*/
#define M_generate	(1<<3)		/* prereq generation mark	*/
#define M_mark		(1<<4)		/* temporary mark		*/
#define M_metarule	(1<<5)		/* metarule closure mark	*/
#define M_scan		(1<<6)		/* scan recursion mark		*/
#define M_waiting	(1<<7)		/* waiting to complete mark	*/

/*
 * var.property flags
 */

#define V_compiled	(1<<0)		/* variable has been compiled	*/
#define V_frozen	(1<<1)		/* frozen in make object file	*/
#define V_functional	(1<<2)		/* make rule name before access	*/
#define V_import	(1<<3)		/* imported from environment	*/
#define V_local_D	(1<<4)		/* :T=D: localview reference	*/
#define V_oldvalue	(1<<5)		/* compile old value		*/
#define V_readonly	(1<<6)		/* only dynamic modifications	*/
#define V_retain	(1<<7)		/* retain value in state file	*/
#define V_scan		(1<<8)		/* scan for implicit state var	*/

#define V_local_E	(1<<9)		/* :T=E: localview reference	*/

#define V_auxiliary	(1<<10)		/* auxiliary &= assignment	*/
#define V_append	(1<<11)		/* cmd line += property or op	*/
#define V_free		(1<<12)		/* value may be freed		*/
#define V_builtin	(1<<13)		/* builtin V_functional		*/
#define V_scope		(1<<14)		/* scoped value			*/

#define V_restored	(1L<<15)	/* retained value stored	*/

#define V_CLEARSTATE	(V_free|V_restored)
#define V_CLEAROBJECT	(~(V_auxiliary|V_builtin|V_functional|V_import|V_retain|V_scan|V_scope))

/*
 * getval() flags
 */

#define VAL_AUXILIARY	(1<<0)		/* auxilliary value		*/
#define VAL_BRACE	(1<<1)		/* { }				*/
#define VAL_FILE	(1<<2)		/* !notfile(r)			*/
#define VAL_PRIMARY	(1<<3)		/* primary value		*/
#define VAL_UNBOUND	(1<<4)		/* unbound name			*/

typedef struct dirent Dirent_t;
typedef struct stat Stat_t;

struct File_s; typedef struct File_s File_t;
struct Frame_s; typedef struct Frame_s Frame_t;
struct List_s; typedef struct List_s List_t;
struct Rule_s; typedef struct Rule_s Rule_t;

typedef unsigned _ast_int4_t Flags_t;	/* flag bit vector		*/
typedef unsigned _ast_int4_t Seconds_t;	/* seconds resolution time	*/

typedef struct Fileid_s			/* unique file id		*/
{
	long		dev;		/* device number		*/
	long		ino;		/* inode number			*/
} Fileid_t;

typedef struct Dir_s			/* scanned directory entry	*/
{
	char*		name;		/* directory name		*/
	Time_t		time;		/* modify time			*/
	unsigned char	archive;	/* directory is an archive	*/
	unsigned char	directory;	/* directory is a real directory*/
	unsigned char	ignorecase;	/* pox on dirs that ignore case	*/
	unsigned char	truncate;	/* names truncated to this	*/
} Dir_t;

struct File_s				/* file table entry		*/
{
	File_t*		next;		/* next in list			*/
	Dir_t*		dir;		/* directory containing file	*/
	Time_t		time;		/* modify time			*/
};

struct Frame_s				/* active target frame		*/
{
	Frame_t*	parent;		/* parent frame			*/
	Frame_t*	previous;	/* previous active frame	*/
	Rule_t*		target;		/* target in frame		*/
	List_t*		prereqs;	/* original prereqs		*/
	char*		action;		/* original action		*/
	char*		original;	/* original bound name		*/
	char*		primary;	/* metarule primary prereq name	*/
	char*		stem;		/* metarule stem		*/

	struct
	{
	char*		name;		/* original target name		*/
	Frame_t*	frame;		/* original target frame	*/
	Time_t		time;		/* original target time		*/
	}		context;	/* context push/pop		*/
};

/*
 * statevar data, staterule sync time and unbound rule name -- shared in rule.u1
 */

#define event		u1.u_event
#define statedata	u1.u_data
#define uname		u1.u_uname
#define unbound(r)	((r)->uname?(r)->uname:(r)->name)

struct Rule_s				/* rule				*/
{
	char*		name;		/* rule name			*/
	Frame_t*	active;		/* active target frame		*/

	union
	{
	char*		u_uname;	/* unbound name			*/
	char*		u_data;		/* state value			*/
	Time_t		u_event;	/* state rule event time	*/
	}		u1;

	List_t*		prereqs;	/* prerequisites		*/
	char*		action;		/* update action		*/
	Time_t		time;		/* modify time			*/

	Flags_t		attribute;	/* external named attributes	*/
	Flags_t		dynamic;	/* dynamic properties		*/
	Flags_t		property;	/* stable properties		*/

	unsigned char	scan;		/* file scan strategy index	*/
	unsigned char	semaphore;	/* semaphore + count		*/
	unsigned char	status;		/* disposition			*/
	unsigned char	view;		/* view bind index		*/

	unsigned char	mark;		/* M_* marks			*/
	unsigned char	preview;	/* min prereq view		*/
	unsigned short	must;		/* cancel if == 0		*/

	unsigned long	complink;	/* compilation link		*/
	Flags_t		checked[STATERULES+1];	/* view state check	*/

#if BINDINDEX
	unsigned char	source;		/* source bind index		*/
#endif
};

typedef struct Internal_s		/* internal rule and list info	*/
{
	/*
	 * read/write rule attributes
	 */

	Rule_t*		accept;		/* .ACCEPT rule pointer		*/
	Rule_t*		after;		/* .AFTER rule pointer		*/
	Rule_t*		alarm;		/* .ALARM rule pointer		*/
	Rule_t*		always;		/* .ALWAYS rule pointer		*/
	Rule_t*		archive;	/* .ARCHIVE rule pointer	*/
	Rule_t*		attribute;	/* .ATTRIBUTE rule pointer	*/
	Rule_t*		before;		/* .BEFORE rule pointer		*/
	Rule_t*		command;	/* .COMMAND rule pointer	*/
	Rule_t*		dontcare;	/* .DONTCARE rule pointer	*/
	Rule_t*		force;		/* .FORCE rule pointer		*/
	Rule_t*		foreground;	/* .FOREGROUND rule pointer	*/
	Rule_t*		functional;	/* .FUNCTIONAL rule pointer	*/
	Rule_t*		freeze;		/* .FREEZE rule pointer		*/
	Rule_t*		ignore;		/* .IGNORE rule pointer		*/
	Rule_t*		immediate;	/* .IMMEDIATE rule pointer	*/
	Rule_t*		implicit;	/* .IMPLICIT rule pointer	*/
	Rule_t*		insert;		/* .INSERT rule pointer		*/
	Rule_t*		joint;		/* .JOINT rule pointer		*/
	Rule_t*		local;		/* .LOCAL rule pointer		*/
	Rule_t*		make;		/* .MAKE rule pointer		*/
	Rule_t*		making;		/* .MAKING rule pointer		*/
	Rule_t*		multiple;	/* .MULTIPLE rule pointer	*/
	Rule_t*		op;		/* .OPERATOR rule pointer	*/
	Rule_t*		parameter;	/* .PARAMETER rule pointer	*/
	Rule_t*		read;		/* .READ rule pointer		*/
	Rule_t*		readonly;	/* .READONLY rule pointer	*/
	Rule_t*		regular;	/* .REGULAR rule pointer	*/
	Rule_t*		repeat;		/* .REPEAT rule pointer		*/
	Rule_t*		run;		/* .RUN rule pointer		*/
	Rule_t*		semaphore;	/* .SEMAPHORE rule pointer	*/
	Rule_t*		source;		/* .SOURCE rule pointer		*/
	Rule_t*		state;		/* .STATE rule pointer		*/
	Rule_t*		sync;		/* .SYNC rule pointer		*/
	Rule_t*		terminal;	/* .TERMINAL rule pointer	*/
	Rule_t*		use;		/* .USE rule pointer		*/
	Rule_t*		virt;		/* .VIRTUAL rule pointer	*/
	Rule_t*		wait;		/* .WAIT rule pointer		*/

	/*
	 * readonly rule attributes
	 */
	 
	Rule_t*		active;		/* .ACTIVE rule pointer		*/
	Rule_t*		bound;		/* .BOUND rule pointer		*/
	Rule_t*		built;		/* .BUILT rule pointer		*/
	Rule_t*		entries;	/* .ENTRIES rule pointer	*/
	Rule_t*		exists;		/* .EXISTS rule pointer		*/
	Rule_t*		failed;		/* .FAILED rule pointer		*/
	Rule_t*		file;		/* .FILE rule pointer		*/
	Rule_t*		global;		/* .GLOBAL rule pointer		*/
	Rule_t*		member;		/* .MEMBER rule pointer		*/
	Rule_t*		notyet;		/* .NOTYET rule pointer		*/
	Rule_t*		scanned;	/* .SCANNED rule pointer	*/
	Rule_t*		staterule;	/* .STATERULE rule pointer	*/
	Rule_t*		statevar;	/* .STATEVAR rule pointer	*/
	Rule_t*		target;		/* .TARGET rule pointer		*/
	Rule_t*		triggered;	/* .TRIGGERED rule pointer	*/

	/*
	 * special rules and names
	 */

	Rule_t*		args;		/* .ARGS rule pointer		*/
	Rule_t*		bind;		/* .BIND rule pointer		*/
	Rule_t*		clear;		/* .CLEAR rule pointer		*/
	Rule_t*		copy;		/* .COPY rule pointer		*/
	Rule_t*		delete;		/* .DELETE rule pointer		*/
	Rule_t*		dot;		/* . rule pointer		*/
	Rule_t*		empty;		/* "" rule pointer		*/
	Rule_t*		error;		/* error intercept rule pointer	*/
	Rule_t*		exported;	/* .EXPORT rule pointer		*/
	Rule_t*		globalfiles;	/* .GLOBALFILES rule pointer	*/
	Rule_t*		include;	/* .INCLUDE rule pointer	*/
	Rule_t*		internal;	/* .INTERNAL rule pointer	*/
	Rule_t*		main;		/* .MAIN rule pointer		*/
	Rule_t*		makefiles;	/* .MAKEFILES rule pointer	*/
	Rule_t*		metarule;	/* .METARULE rule pointer	*/
	Rule_t*		null;		/* .NULL rule pointer		*/
	Rule_t*		preprocess;	/* .PREPROCESS rule pointer	*/
	Rule_t*		query;		/* .QUERY rule pointer		*/
	Rule_t*		rebind;		/* .REBIND rule pointer		*/
	Rule_t*		reset;		/* .RESET rule pointer		*/
	Rule_t*		retain;		/* .RETAIN rule pointer		*/
	Rule_t*		scan;		/* .SCAN rule pointer		*/
	Rule_t*		special;	/* .SPECIAL rule pointer	*/
	Rule_t*		tmplist;	/* .TMPLIST rule pointer	*/
	Rule_t*		unbind;		/* .UNBIND rule pointer		*/
	Rule_t*		view;		/* .VIEW rule pointer		*/

	/*
	 * pattern association rules
	 */

	Rule_t*		append_p;	/* .APPEND. rule pointer	*/
	Rule_t*		assert_p;	/* .ASSERT. rule pointer	*/
	Rule_t*		assign_p;	/* .ASSIGN. rule pointer	*/
	Rule_t*		attribute_p;	/* .ATTRIBUTE. rule pointer	*/
	Rule_t*		bind_p;		/* .BIND. rule pointer		*/
	Rule_t*		dontcare_p;	/* .DONTCARE. rule pointer	*/
	Rule_t*		insert_p;	/* .INSERT. rule pointer	*/
	Rule_t*		require_p;	/* .REQUIRE. rule pointer	*/
	Rule_t*		source_p;	/* .SOURCE. rule pointer	*/

	/*
	 * miscellaneous internal info
	 */

	Sfio_t*		met;		/* metarule expansion buffer	*/
	Sfio_t*		nam;		/* name generation buffer	*/
	Sfio_t*		tmp;		/* very temporary work buffer	*/
	Sfio_t*		val;		/* initial getval return buffer	*/
	Sfio_t*		wrk;		/* very temporary work buffer	*/

	char*		freelists;	/* free lists list		*/
	char*		freerules;	/* free rules list		*/
	char*		freevars;	/* free variables list		*/

	char*		issource;	/* internal.source* match pat	*/
	char*		openfile;	/* bind()-scan() optimization	*/
	char*		pwd;		/* PWD value			*/
	char*		ptr;		/* temporary for sfstrptr()	*/

	int		openfd;		/* bind()-scan() optimization	*/
	int		pwdlen;		/* strlen(internal.pwd)		*/
} Internal_t;

typedef struct External_s		/* external engine name info	*/
{
	/*
	 * names of variables defined by engine, init, or environment
	 */

	char*		args;		/* candidate args file name(s)	*/
	char*		convert;	/* makefile converter patterns	*/
	char*		file;		/* main input makefile name	*/
	char*		files;		/* candidate makefile name(s)	*/
	char*		import;		/* explicit env override vars	*/
	char*		lib;		/* related file lib directory	*/
	char*		make;		/* program path name		*/
	char*		nproc;		/* # jobs for compatibility	*/
	char*		old;		/* old program path name	*/
	char*		pwd;		/* pwd name			*/
	char*		rules;		/* candidate rules file name(s)	*/
	char*		skip;		/* order directory skip pattern	*/
	char*		version;	/* engine version stamp		*/
	char*		viewdot;	/* . view dir list		*/
	char*		viewnode;	/* view node dir list		*/

	/*
	 * infrequently used engine interface names
	 */

	char*		compdone;	/* made after makefile compiled	*/
	char*		compinit;	/* made before makefile compiled*/
	char*		done;		/* made just before exit	*/
	char*		init;		/* made before first user target*/
	char*		interrupt;	/* made on first interrupt	*/
	char*		jobdone;	/* made when each job done	*/
	char*		makedone;	/* made after done		*/
	char*		makeinit;	/* made after before init	*/
	char*		makeprompt;	/* made just before each prompt	*/
	char*		makerun;	/* made just before each job	*/
	char*		mamname;	/* external mam atom name	*/
	char*		mamaction;	/* external mam action		*/
	char*		order;		/* :W=[OPR]: favorites		*/

	/*
	 * related file suffixes
	 */

	char*		lock;		/* make lock file suffix	*/
	char*		object;		/* make object file suffix	*/
	char*		source;		/* make source file suffix	*/
	char*		state;		/* make state file suffix	*/
	char*		tmp;		/* make temporary file suffix	*/
} External_t;

typedef struct Tables_s			/* hash table pointers		*/
{
	Hash_table_t*	ar;		/* archives dir info by name	*/
	Hash_table_t*	bound;		/* directory of bound file	*/
	Hash_table_t*	dir;		/* directories and archives	*/
	Hash_table_t*	file;		/* files from scanned dirs	*/
	Hash_table_t*	oldvalue;	/* old variable values		*/
	Hash_table_t*	regress;	/* regression path maps		*/
	Hash_table_t*	rule;		/* rule names			*/
	Hash_table_t*	var;		/* variable names		*/
} Tables_t;

#define BIND_EXISTS	(1<<0)		/* statefile loaded		*/
#define BIND_LOADED	(1<<1)		/* statefile loaded		*/

typedef struct Binding_s		/* binding info			*/
{
#if BINDINDEX
	Rule_t*		path;		/* path name component		*/
#else
	char*		path;		/* path name component		*/
#endif
	char*		root;		/* path root			*/
	short		pathlen;	/* path length			*/
	short		rootlen;	/* root length			*/
	unsigned char	flags;		/* BIND_* flags			*/
	unsigned char	map;		/* external index map		*/
} Binding_t;

typedef struct Label_s			/* resume label			*/
{
	jmp_buf		label;
} Label_t;

typedef struct Mam_s			/* mam state			*/
{
	Sfdisc_t	disc;		/* output discipline -- first!	*/

	int		level;		/* next error() message level	*/
	int		parent;		/* mam parent label		*/
	int		rootlen;	/* strlen(state.mam.root)	*/

	char*		label;		/* instruction label		*/
	char*		options;	/* option string		*/
	char*		root;		/* names relative to this root	*/
	char*		type;		/* mam type name		*/

	Sfio_t*		out;		/* output stream pointer	*/

	unsigned char	dynamic;	/* dynamic mam			*/
	unsigned char	regress;	/* regression mam		*/
	unsigned char	statix;		/* static mam			*/

	unsigned char	dontcare;	/* emit dontcare rules too	*/
	unsigned char	port;		/* emit porting hints		*/
} Mam_t;

typedef struct State_s			/* program state		*/
{
	unsigned char	accept;		/* accept all existing targets	*/
	unsigned char	alias;		/* enable directory aliasing	*/
	unsigned char	base;		/* compile base|global rules	*/
	unsigned char	caught;		/* a signal was caught		*/
	unsigned char	compile;	/* make object compile state	*/
	unsigned char	compileonly;	/* only compile (force)		*/
	unsigned char	compatibility;	/* disable compatibility msgs	*/
	unsigned char	cross;		/* don't run gen'd executables	*/
	unsigned char	exec;		/* execute shell actions	*/
	unsigned char	expandview;	/* expand paths if fsview!=0	*/
	unsigned char	explain;	/* explain reason for actions	*/
	unsigned char	explicitrules;	/* explicit rules statement	*/
	unsigned char	finish;		/* in finish()			*/
	unsigned char	force;		/* force target updates		*/
	unsigned char	forceread;	/* force makefiles to be read	*/
	unsigned char	forcescan;	/* force implicit prereq scan	*/
	unsigned char	fsview;		/* file system handles views	*/
	unsigned char	fullscan;	/* scan for impl state prereqs	*/
	unsigned char	global;		/* reading global rules		*/
	unsigned char	ignore;		/* ignore sh action errors	*/
	unsigned char	ignorelock;	/* ignore state lock		*/
	unsigned char	import;		/* import var def precedence	*/
	unsigned char	init;		/* engine initialization	*/
	unsigned char	intermediate;	/* force intermediate targets	*/
	unsigned char	interpreter;	/* in interpreter main loop	*/
	unsigned char	keepgoing;	/* continue w/ sibling prereqs	*/
	unsigned char	list;		/* list readable definitions	*/
	unsigned char	localview;	/* automatics to local view	*/
#if BINDINDEX
	unsigned char	logical;	/* emit logical pathnames	*/
#endif
	unsigned char	never;		/* really - don't exec anything	*/
	unsigned char	op;		/* currently parsing operator	*/
	unsigned char	override;	/* override explicit rules	*/
	unsigned char	preprocess;	/* preprocess all makefiles	*/
	unsigned char	reading;	/* currently reading makefile	*/
	unsigned char	readonly;	/* current vars|opts readonly	*/
	unsigned char	regress;	/* output for regression test	*/
	unsigned char	ruledump;	/* dump rule information	*/
	unsigned char	savestate;	/* must save state variables	*/
	unsigned char	scan;		/* scan|check implicit prereqs	*/
	unsigned char	serialize;	/* serialize concurrent output	*/
	unsigned char	silent;		/* run silently			*/
	unsigned char	strictview;	/* strict views			*/
	unsigned char	targetcontext;	/* expand in target dir context	*/
	unsigned char	touch;		/* touch out of date targets	*/
	unsigned char	user;		/* user activities started	*/
	unsigned char	val;		/* internal.val in use		*/
	unsigned char	vardump;	/* dump variable information	*/
	unsigned char	virtualdot;	/* fsview . is virtual		*/
	unsigned char	waiting;	/* waiting for job completion	*/
	unsigned char	warn;		/* enable source file warnings	*/

	int		argc;		/* global argc			*/
	int		believe;	/* believe state from this level*/
	int		errors;		/* keepgoing error count	*/
	int		interrupt;	/* interrupt causing exit	*/
	int		jobs;		/* sh action concurrency level	*/
	int		pid;		/* make pid			*/
	int		readstate;	/* state files to this view ok	*/
	int		reread;		/* input makefile reread count	*/
	int		stateview;	/* state file view index	*/
	int		tabstops;	/* tab stops for makefile parse	*/
	int		targetview;	/* most recent active targ view	*/
	int		tolerance;	/* time comparison tolerance	*/
	int		unwind;		/* make() dontcare unwind level	*/

	Flags_t		questionable;	/* questionable code enable bits*/
	Flags_t		test;		/* test code enable bits	*/

	Time_t		start;		/* start time of this make	*/

	char*		corrupt;	/* corrupt state file action	*/
	char*		errorid;	/* error message id		*/
	char*		hold;		/* hold error trap		*/
	char*		loading;	/* loading this object file	*/
	char*		makefile;	/* first makefile name		*/
	char*		objectfile;	/* make object file name	*/
	char*		rules;		/* base rules base name		*/
	char*		statefile;	/* state variable file name	*/
	char*		targetprefix;	/* target prefix dir separator	*/
	char*		tmppchar;	/* macro char* temporary	*/
	char*		tmpfile;	/* temporary file name		*/
	char*		writeobject;	/* 0:nowrite or object file def	*/
	char*		writestate;	/* 0:nowrite or state file def	*/

	int*		argf;		/* global argv ARG_* flags	*/

	char**		argv;		/* global argv			*/

	Dir_t*		archive;	/* .SCAN archive		*/

	Sfio_t*		context;	/* localview() target context	*/

	Frame_t*	frame;		/* current target frame		*/

#if BINDINDEX
	Binding_t	source[MAXBIND+1];/* source bind table		*/
	int		maxsource;	/* max source bind index	*/
#endif
	Binding_t	view[MAXVIEW+1];/* view bind table		*/
	unsigned int	maxview;	/* max view bind index		*/

	int (*compnew)(const char*, char*, void*); /* new compile rule	*/
	void*		comparg;	/* compnew handle		*/

	Label_t		resume;		/* if interpreter!=0		*/

	Mam_t		mam;		/* mam state			*/

	Coshell_t*	coshell;	/* coshell handle		*/

	Sfio_t*		io[11];		/* print/read streams		*/
} State_t;

typedef struct Var_s			/* variable			*/
{
	char*		name;		/* name				*/
	char*		value;		/* value			*/
	Flags_t		property;	/* static and dynamic		*/
	size_t		length;		/* maximum length of value	*/
	char*		(*builtin)(char**);	/* builtin function	*/
} Var_t;

struct List_s				/* rule cons cell		*/
{
	List_t*		next;		/* next in list			*/
	Rule_t*		rule;		/* list item			*/
};

/*
 * make globals
 */

extern External_t	external;	/* external engine names	*/
extern Internal_t	internal;	/* internal rule and list info	*/
extern State_t		state;		/* engine state			*/
extern Tables_t		table;		/* hash table pointers		*/

extern char		null[];		/* null string			*/
extern char		tmpname[];	/* temporary name buffer	*/

extern short		ctypes[];	/* internal character types	*/

extern char*		idname;		/* interface id name		*/
extern char*		initdynamic;	/* dynamic initialization	*/
extern char*		initstatic;	/* static initialization	*/
extern char*		version;	/* program version stamp	*/

/*
 * make routines
 */

extern File_t*		addfile(Dir_t*, char*, Time_t);
extern void		addprereq(Rule_t*, Rule_t*, int);
extern List_t*		append(List_t*, List_t*);
extern int		apply(Rule_t*, char*, char*, char*, Flags_t);
extern void		argcount(void);
extern void		arscan(Rule_t*);
extern void		artouch(char*, char*);
extern char*		arupdate(char*);
extern Rule_t*		associate(Rule_t*, Rule_t*, char*, List_t**);
extern Var_t*		auxiliary(char*, int);
extern Rule_t*		bind(Rule_t*);
extern void		bindattribute(Rule_t*);
extern Rule_t*		bindfile(Rule_t*, char*, int);
extern Rule_t*		bindstate(Rule_t*, char*);
extern int		block(int);
extern void		candidates(void);
extern char*		call(Rule_t*, char*);
extern Rule_t*		catrule(char*, char*, char*, int);
extern char*		colonlist(Sfio_t*, char*, int, int);
extern void		compile(char*, char*);
extern int		complete(Rule_t*, List_t*, Time_t*, Flags_t);
extern void		compref(Rule_t*, int);
extern List_t*		cons(Rule_t*, List_t*);
extern void		dirscan(Rule_t*);
extern void		drop(void);
extern void		dump(Sfio_t*, int);
extern void		dumpaction(Sfio_t*, const char*, char*, const char*);
extern void		dumpjobs(int);
extern void		dumpregress(Sfio_t*, const char*, const char*, char*);
extern void		dumprule(Sfio_t*, Rule_t*);
extern void		dumpvar(Sfio_t*, Var_t*);
extern void		dynamic(Rule_t*);
extern void		edit(Sfio_t*, char*, char*, char*, char*);
extern void		expand(Sfio_t*, char*);
extern void		explain(int, ...);
extern long		expr(Sfio_t*, char*);
extern Sfio_t*		fapply(Rule_t*, char*, char*, char*, Flags_t);
extern void		finish(int);
extern int		forcescan(const char*, char* v, void*);
extern char*		getarg(char**, int*);
extern void		getop(Sfio_t*, char*, int);
extern char*		getval(char*, int);
extern char**		globv(glob_t*, char*);
extern int		handle(void);
extern int		hasattribute(Rule_t*, Rule_t*, Rule_t*);
extern int		hasafter(Rule_t*, Flags_t);
extern void		immediate(Rule_t*);
extern void		initcode(void);
extern void		inithash(void);
extern void		initrule(void);
extern void		initscan(int);
extern void		inittrap(void);
extern void		initview(void);
extern void		initwakeup(int);
extern void		interpreter(char*);
extern int		isoption(const char*);
extern int		nametype(const char*, char**);
extern List_t*		joint(Rule_t*);
extern List_t*		listcopy(List_t*);
extern void		listops(Sfio_t*, int);
extern int		load(Sfio_t*, const char*, int);
extern int		loadable(Sfio_t*, Rule_t*, int);
extern void		localvar(Sfio_t*, Var_t*, char*, int);
extern char*		localview(Rule_t*);
extern void		lockstate(int);
extern int		make(Rule_t*, Time_t*, char*, Flags_t);
extern int		makeafter(Rule_t*, Flags_t);
extern int		makebefore(Rule_t*);
extern Rule_t*		makerule(char*);
extern void		maketop(Rule_t*, int, char*);
extern char*		mamcanon(char*);
extern ssize_t		mamerror(int, const void*, size_t);
extern char*		mamname(Rule_t*);
extern void		mampop(Sfio_t*, Rule_t*, Flags_t);
extern int		mampush(Sfio_t*, Rule_t*, Flags_t);
extern Sfio_t*		mamout(Rule_t*);
extern char*		maprule(char*, Rule_t*);
extern void		merge(Rule_t*, Rule_t*, int);
extern void		mergestate(Rule_t*, Rule_t*);
extern void		metaclose(Rule_t*, Rule_t*, int);
extern void		metaexpand(Sfio_t*, char*, char*);
extern Rule_t*		metaget(Rule_t*, List_t*, char*, Rule_t**);
extern Rule_t*		metainfo(int, char*, char*, int);
extern int		metamatch(char*, char*, char*);
extern Rule_t*		metarule(char*, char*, int);
extern void		negate(Rule_t*, Rule_t*);
extern void*		newchunk(char**, size_t);
extern void		newfile(Rule_t*, char*, Time_t);
extern char*		objectfile(void);
extern void		parentage(Sfio_t*, Rule_t*, char*);
extern int		parse(Sfio_t*, char*, char*, Sfio_t*);
extern char*		parsefile(void);
extern char*		pathname(char*, Rule_t*);
extern void		poplocal(void*);
extern int		prereqchange(Rule_t*, List_t*, Rule_t*, List_t*);
extern void		punt(int);
extern void*		pushlocal(void);
extern void		readcheck(void);
extern void		readclear(void);
extern void		readenv(void);
extern int		readfile(char*, int, char*);
extern void		readstate(void);
extern void		rebind(Rule_t*, int);
extern void		remdup(List_t*);
extern void		remtmp(int);
extern int		resolve(char*, int, int);
extern int		rstat(char*, Stat_t*, int);
extern void		rules(char*);
extern Rule_t*		rulestate(Rule_t*, int);
extern void		savestate(void);
extern List_t*		scan(Rule_t*, Time_t*);
extern int		scanargs(int, char**, int*);
extern int		set(char*, int, Sfio_t*);
extern Var_t*		setvar(char*, char*, int);
extern void		shquote(Sfio_t*, char*);
extern Rule_t*		source(Rule_t*);
extern int		special(Rule_t*);
extern char*		statefile(void);
extern Rule_t*		staterule(int, Rule_t*, char*, int);
extern Time_t		statetime(Rule_t*, int);
extern int		statetimeq(Rule_t*, Rule_t*);
extern int		strprintf(Sfio_t*, const char*, char*, int, int);
extern void		terminate(void);
extern char*		timefmt(const char*, Time_t);
extern Time_t		timenum(const char*, char**);
extern char*		timestr(Time_t);
extern void		trigger(Rule_t*, Rule_t*, char*, Flags_t);
extern int		unbind(const char*, char*, void*);
extern Dir_t*		unique(Rule_t*);
extern void		unparse(int);
extern Var_t*		varstate(Rule_t*, int);
extern void		wakeup(Seconds_t, List_t*);
