/* functions.h - declarations for functions & function processing */
/* $Id: functions.h,v 1.66 2003/02/24 18:05:23 rmg Exp $ */
#include "copyright.h"
#ifndef __FUNCTIONS_H
#define __FUNCTIONS_H
/* ---------------------------------------------------------------------------
* Type definitions.
*/
#define MAX_NFARGS 30
typedef struct fun {
const char *name; /* Function name */
void (*fun)(); /* Handler */
int nargs; /* Number of args needed or expected */
unsigned int flags; /* Function flags */
int perms; /* Access to function */
EXTFUNCS *xperms; /* Extended access to function */
} FUN;
typedef struct ufun {
char *name; /* Function name */
dbref obj; /* Object ID */
int atr; /* Attribute ID */
unsigned int flags; /* Function flags */
int perms; /* Access to function */
struct ufun *next; /* Next ufun in chain */
} UFUN;
typedef struct delim {
size_t len;
char str[MAX_DELIM_LEN];
} Delim;
typedef struct var_entry VARENT;
struct var_entry {
char *text; /* variable text */
};
typedef struct component_def COMPONENT;
struct component_def {
int (*typer_func)(); /* type-checking handler */
char *def_val; /* default value */
};
typedef struct structure_def STRUCTDEF;
struct structure_def {
char *s_name; /* name of the structure */
char **c_names; /* array of component names */
COMPONENT **c_array; /* array of pointers to components */
int c_count; /* number of components */
char delim; /* output delimiter when unloading */
int need_typecheck; /* any components without types of any? */
int n_instances; /* number of instances out there */
char *names_base; /* pointer for later freeing */
char *defs_base; /* pointer for later freeing */
};
typedef struct instance_def INSTANCE;
struct instance_def {
STRUCTDEF *datatype; /* pointer to structure data type def */
};
typedef struct data_def STRUCTDATA;
struct data_def {
char *text;
};
typedef struct object_stack OBJSTACK;
struct object_stack {
char *data;
OBJSTACK *next;
};
#ifdef FLOATING_POINTS
#ifndef linux /* linux defines atof as a macro */
double atof();
#endif /* ! linux */
#define aton atof
typedef double NVAL;
#else
#define aton atoi
typedef int NVAL;
#endif /* FLOATING_POINTS */
/* ---------------------------------------------------------------------------
* Constants used in delimiter macros.
*/
#define DELIM_EVAL 0x001 /* Must eval delimiter. */
#define DELIM_NULL 0x002 /* Null delimiter okay. */
#define DELIM_CRLF 0x004 /* '%r' delimiter okay. */
#define DELIM_STRING 0x008 /* Multi-character delimiter okay. */
/* ---------------------------------------------------------------------------
* Function declarations.
*/
extern const Delim SPACE_DELIM;
extern char *FDECL(trim_space_sep, (char *, const Delim *));
extern char *FDECL(next_token, (char *, const Delim *));
extern char *FDECL(split_token, (char **, const Delim *));
extern char *FDECL(next_token_ansi, (char *, const Delim *, int *));
extern int FDECL(countwords, (char *, const Delim *));
extern int FDECL(list2arr, (char ***, int, char *, const Delim *));
extern void FDECL(arr2list, (char **, int, char *, char **, const Delim *));
extern int FDECL(list2ansi, (int *, int *, int, char *, const Delim *));
extern INLINE void FDECL(do_reverse, (char *, char *));
extern int FDECL(fn_range_check, (const char *, int, int, int, char *, char **));
extern int FDECL(delim_check, ( char *, char **, dbref, dbref, dbref, char **, int, char **, int, int, Delim *, int ));
/* ---------------------------------------------------------------------------
* Function prototype macro.
*/
#define FUNCTION_ARGLIST buff, bufc, player, caller, cause, fargs, nfargs, cargs, ncargs
#define FUNCTION(x) \
void x( FUNCTION_ARGLIST ) \
char *buff, **bufc; \
dbref player, caller, cause; \
char *fargs[], *cargs[]; \
int nfargs, ncargs;
/* ---------------------------------------------------------------------------
* Delimiter macros for functions that take an optional delimiter character.
*/
/* Minimum work needed to copy a delimiter. Assumes that the "str" member
* of the Delim struct is last.
*/
#define Delim_Copy(sep_dest, sep_src) \
memcpy((sep_dest), (sep_src), \
sizeof(Delim) - MAX_DELIM_LEN + 1 + (sep_src)->len)
/* Separator checking "helper" macros.
* VaChk_Sep(sep_ptr, sep_len, arg_n, flags): Use arg_n as separator.
* VaChk_InSep(arg_number, flags): Use arg_number as input sep.
* VaChk_DefaultOut(arg_number): If nfargs less than arg_number,
* use the input separator. DO NOT PUT A SEMI-COLON AFTER THIS MACRO.
* VaChk_OutSep(arg_number, flags): Use arg_number as output sep.
*/
#define VaChk_Sep(xsep, xargnum, xflags) \
if (!delim_check( FUNCTION_ARGLIST, xargnum, xsep, xflags)) \
return
#define VaChk_InSep(xargnum, xflags) \
VaChk_Sep(&isep, xargnum, (xflags)|DELIM_STRING)
#define VaChk_DefaultOut(xargnum) \
if (nfargs < xargnum) { \
Delim_Copy(&osep, &isep); \
} else
#define VaChk_OutSep(xargnum, xflags) \
VaChk_Sep(&osep, xargnum, (xflags)|DELIM_STRING|DELIM_NULL|DELIM_CRLF)
/*
* VaChk_Range(min_args, max_args): Functions which take
* between min_args and max_args. Don't check for delimiters.
*
* VaChk_Only_InPure(max_args): Functions which take max_args - 1
* args or, with a delimiter, max_args args. No special stuff.
*
* VaChk_Only_In(max_args): Functions which take max_args - 1 args
* or, with a delimiter, max_args args.
*
* VaChk_Only_Out(max_args): Functions which take max_args - 1 args
* or, with a delimiter, max_args args. The one delimiter is an output delim.
*
* VaChk_InPure(max_args): Functions which take max_args - 1
* args or, with a delimiter, max_args args. No special stuff.
*
* VaChk_In(min_args, max_args): Functions which take
* between min_args and max_args, with max_args as a delimiter.
*
* VaChk_Out(min_args, max_args): Functions which take
* between min_args and max_args, with max_args as an output delimiter.
*
* VaChk_Only_In_Out(max_args): Functions which take at least
* max_args - 2, with max_args - 1 as an input delimiter, and max_args as
* an output delimiter.
*
* VaChk_In_Out(min_args, max_args): Functions which take at
* least min_args, with max_args - 1 as an input delimiter, and max_args
* as an output delimiter.
*
* VaChk_InEval_OutEval(min_args, max_args): Functions which
* take at least min_args, with max_args - 1 as an input delimiter that
* must be evaluated, and max_args as an output delimiter which must
* be evaluated.
*/
#define VaChk_Range(xminargs,xnargs) \
if (!fn_range_check(((FUN *)fargs[-1])->name, nfargs, xminargs, xnargs, \
buff, bufc)) \
return
#define VaChk_Only_InPure(xnargs) \
VaChk_Range(xnargs-1, xnargs); \
if (!delim_check( FUNCTION_ARGLIST, xnargs, &isep, 0)) \
return
#define VaChk_Only_In(xnargs) \
VaChk_Range(xnargs-1, xnargs); \
VaChk_InSep(xnargs, 0)
#define VaChk_Only_Out(xnargs) \
VaChk_Range(xnargs-1, xnargs); \
VaChk_OutSep(xnargs, 0)
#define VaChk_InPure(xminargs, xnargs) \
VaChk_Range(xminargs, xnargs); \
if (!delim_check( FUNCTION_ARGLIST, xnargs, &isep, 0)) \
return
#define VaChk_In(xminargs, xnargs) \
VaChk_Range(xminargs, xnargs); \
VaChk_InSep(xnargs, 0)
#define VaChk_Out(xminargs, xnargs) \
VaChk_Range(xminargs, xnargs); \
VaChk_OutSep(xnargs, 0)
#define VaChk_Only_In_Out(xnargs) \
VaChk_Range(xnargs-2, xnargs); \
VaChk_InSep(xnargs-1, 0); \
VaChk_DefaultOut(xnargs) { \
VaChk_OutSep(xnargs, 0); \
}
#define VaChk_In_Out(xminargs, xnargs) \
VaChk_Range(xminargs, xnargs); \
VaChk_InSep(xnargs-1, 0); \
VaChk_DefaultOut(xnargs) { \
VaChk_OutSep(xnargs, 0); \
}
#define VaChk_InEval_OutEval(xminargs, xnargs) \
VaChk_Range(xminargs, xnargs); \
VaChk_InSep(xnargs-1, DELIM_EVAL); \
VaChk_OutSep(xnargs, DELIM_EVAL)
/* ---------------------------------------------------------------------------
* Miscellaneous macros.
*/
/* Get function flags. Note that Is_Func() and Func_Mask() are identical;
* they are given specific names for code clarity.
*/
#define Func_Flags(x) (((FUN *)(x)[-1])->flags)
#define Is_Func(x) (((FUN *)fargs[-1])->flags & (x))
#define Func_Mask(x) (((FUN *)fargs[-1])->flags & (x))
/* Check access to built-in function. */
#define Check_Func_Access(p,f) \
(check_access(p,(f)->perms) && \
(!((f)->xperms) || check_mod_access(p,(f)->xperms)))
/* Trim spaces. */
#define Eat_Spaces(x) trim_space_sep((x), &SPACE_DELIM)
/* Special handling of separators. */
#define print_sep(s,b,p) \
if ((s)->len == 1) { \
if ((s)->str[0] == '\r') { \
safe_crlf((b),(p)); \
} else if ((s)->str[0] != '\0') { \
safe_chr((s)->str[0],(b),(p)); \
} \
} else { \
safe_known_str((s)->str, (s)->len, (b), (p)); \
}
/* Macro for finding an <attr> or <obj>/<attr>
*/
#define Parse_Uattr(p,s,t,n,a) \
if (parse_attrib((p), (s), &(t), &(n), 0)) { \
if (((n) == NOTHING) || !(Good_obj(t))) \
(a) = NULL; \
else \
(a) = atr_num(n); \
} else { \
(t) = (p); \
(a) = atr_str(s); \
}
/* Macro for obtaining an attrib. */
#define Get_Uattr(p,t,a,b,o,f,l) \
if (!(a)) { \
return; \
} \
(b) = atr_pget(t, (a)->number, &(o), &(f), &(l)); \
if (!*(b) || !(See_attr((p), (t), (a), (o), (f)))) { \
free_lbuf(b); \
return; \
}
/* Macro for writing a certain amount of padding into a buffer.
* l is the number of characters left to write.
* m is a throwaway integer for holding the maximum.
* c is the separator character to use.
*/
#define print_padding(l,m,c) \
if ((l) > 0) { \
(m) = LBUF_SIZE - 1 - (*bufc - buff); \
(l) = ((l) > (m)) ? (m) : (l); \
memset(*bufc, (c), (l)); \
*bufc += (l); \
**bufc = '\0'; \
}
/* Handling CPU time checking. */
/*
* CPU time "clock()" compatibility notes:
*
* Linux clock() doesn't necessarily start at 0.
* BSD clock() does appear to always start at 0.
*
* Linux sets CLOCKS_PER_SEC to 1000000, citing POSIX, so its clock()
* will wrap around from (32-bit) INT_MAX to INT_MIN every 72 cpu-minutes
* or so. The actual clock resolution is low enough that, for example,
* it probably never returns odd numbers.
*
* BSD sets CLOCKS_PER_SEC to 100, so theoretically I could hose a cpu
* for 250 days and see what it does when it hits INT_MAX. Any bets? Any
* possible reason to care?
*
* NetBSD clock() can occasionally decrease as the scheduler's estimate of
* how much cpu the mush will use during the current timeslice is revised,
* so we can't use subtraction.
*
* BSD clock() returns -1 if there is an error.
*/
/*
* CPU time logic notes:
*
* B = mudstate.cputime_base
* L = mudstate.cputime_base + mudconf.func_cpu_lim
* N = mudstate.cputime_now
*
* Assuming B != -1 and N != -1 to catch errors on BSD, the possible
* combinations of these values are as follows (note >> means "much
* greater than", not right shift):
*
* 1. B < L normal -- limit should be checked, and is not wrapped yet
* 2. B == L disabled -- limit should not be checked
* 3. B > L strange -- probably misconfigured
* 4. B >> L wrapped -- limit should be checked, and note L wrapped
*
* 1. normal:
* 1a. N << B -- too much, N wrapped
* 1b. N < B -- fine, NetBSD counted backwards
* 1c. N >= B, N <= L -- fine
* 1d. N > L -- too much
*
* 2. disabled:
* 2a. always -- fine, not checking
*
* 3. strange:
* 3a. always -- fine, I guess we shouldn't check
*
* 4. wrapped:
* 4a. N <= L -- fine, N wrapped but not over limit yet
* 4b. N > L, N << B -- too much, N wrapped
* 4c. N < B -- fine, NetBSD counted backwards
* 4d. N >= B -- fine
*
* Note that 1a, 1d, and 4b are the cases where we can be certain that
* too much cpu has been used. The code below only checks for 1d. The
* other two are corner cases that require some distinction between
* "x > y" and "x >> y".
*/
#define Too_Much_CPU() \
((mudstate.cputime_now = clock()), \
((mudstate.cputime_now > mudstate.cputime_base + mudconf.func_cpu_lim) && \
(mudstate.cputime_base + mudconf.func_cpu_lim > mudstate.cputime_base) && \
(mudstate.cputime_base != -1) && \
(mudstate.cputime_now != -1)))
/* ---------------------------------------------------------------------------
* Function-specific flags used in the function table.
*/
/* from handle_sets (setunion, setdiff, setinter, lunion, ldiff, linter): */
#define SET_OPER 0x0f /* mask to select set operation bits */
#define SET_UNION 0
#define SET_INTERSECT 1
#define SET_DIFF 2
#define SET_TYPE 0x10 /* set type is given, don't autodetect */
/* from process_tables (tables, rtables, ctables): */
/* from perform_border (border, rborder, cborder): */
#define JUST_TYPE 0x0f /* mask to select justification bits */
#define JUST_LEFT 0
#define JUST_RIGHT 1
#define JUST_CENTER 2
/* from handle_logic (and, or, andbool, orbool, land, lor, landbool, lorbool,
* cand, cor, candbool, corbool, xor, xorbool): */
/* from handle_flaglists (andflags, orflags): */
/* from handle_filter (filter, filterbool): */
#define LOGIC_OPER 0x0f /* mask to select boolean operation bits */
#define LOGIC_AND 0
#define LOGIC_OR 1
#define LOGIC_XOR 2
#define LOGIC_BOOL 0x10 /* interpret operands as boolean, not int */
#define LOGIC_LIST 0x40 /* operands come in a list, not separately */
/* from handle_vectors (vadd, vsub, vmul, vdot): */
#define VEC_OPER 0x0f /* mask to select vector operation bits */
#define VEC_ADD 0
#define VEC_SUB 1
#define VEC_MUL 2
#define VEC_DOT 3
/* #define VEC_CROSS 4 -- not implemented */
/* from handle_vector (vmag, vunit): */
#define VEC_MAG 5
#define VEC_UNIT 6
/* from perform_loop (loop, parse): */
/* from perform_iter (list, iter, whentrue, whenfalse, istrue, isfalse): */
#define BOOL_COND_TYPE 0x0f /* mask to select exit-condition bits */
#define BOOL_COND_NONE 1 /* loop until end of list */
#define BOOL_COND_FALSE 2 /* loop until true */
#define BOOL_COND_TRUE 3 /* loop until false */
#define FILT_COND_TYPE 0x0f0 /* mask to select filter bits */
#define FILT_COND_NONE 0x010 /* show all results */
#define FILT_COND_FALSE 0x020 /* show only false results */
#define FILT_COND_TRUE 0x030 /* show only true results */
#define LOOP_NOTIFY 0x100 /* send loop results directly to enactor */
/* from handle_okpres (hears, moves, knows): */
#define PRESFN_OPER 0x0f /* Mask to select bits */
#define PRESFN_HEARS 0x01 /* Detect hearing */
#define PRESFN_MOVES 0x02 /* Detect movement */
#define PRESFN_KNOWS 0x04 /* Detect knows */
/* from perform_get (get, get_eval, xget, eval(a,b)): */
#define GET_EVAL 0x01 /* evaluate the attribute */
#define GET_XARGS 0x02 /* obj and attr are two separate args */
/* from handle_pop (pop, peek, toss): */
#define POP_PEEK 0x01 /* don't remove item from stack */
#define POP_TOSS 0x02 /* don't display item from stack */
/* from perform_regedit (regedit, regediti, regeditall, regeditalli): */
/* from perform_regparse (regparse, regparsei): */
/* from perform_regrab (regrab, regrabi, regraball, regraballi): */
/* from perform_regmatch (regmatch, regmatchi): */
/* from perform_grep (grep, grepi, wildgrep, regrep, regrepi): */
#define REG_CASELESS 0x01 /* XXX must equal PCRE_CASELESS */
#define REG_MATCH_ALL 0x02 /* operate on all matches in a list */
#define REG_TYPE 0x0c /* mask to select grep type bits */
#define GREP_EXACT 0
#define GREP_WILD 4
#define GREP_REGEXP 8
/* from handle_trig (sin, cos, tan, asin, acos, atan, sind, cosd, tand,
* asind, acosd, atand): */
#define TRIG_OPER 0x0f /* mask to select trig function bits */
#define TRIG_CO 0x01 /* co-function, like cos as opposed to sin */
#define TRIG_TAN 0x02 /* tan-function, like cot as opposed to cos */
#define TRIG_ARC 0x04 /* arc-function, like asin as opposed to sin */
/* #define TRIG_REC 0x08 -- reciprocal, like sec as opposed to sin */
#define TRIG_DEG 0x10 /* angles are in degrees, not radians */
/* from handle_pronoun (obj, poss, subj, aposs): */
#define PRONOUN_OBJ 0
#define PRONOUN_POSS 1
#define PRONOUN_SUBJ 2
#define PRONOUN_APOSS 3
/* Miscellaneous */
#define LATTR_COUNT 0x01 /* nattr: just return attribute count */
#define LOCFN_WHERE 0x01 /* loc: where() vs. loc() */
#define NAMEFN_FULLNAME 0x01 /* name: fullname() vs. name() */
#define CHECK_PARENTS 0x01 /* hasattrp: recurse up the parent chain */
#define U_LOCAL 0x01 /* ulocal: preserve global registers */
#define TIMESTAMP_MOD 0x01 /* timestamp: lastmod() vs. lastaccess() */
#define CONNINFO_IDLE 0x01 /* conninfo: idle() vs. conn() */
#endif /* __FUNCTIONS_H */