411 lines
18 KiB
C
411 lines
18 KiB
C
|
// script binding functionality
|
||
|
|
||
|
enum { VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR, VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT, VAL_CSTR, VAL_CANY, VAL_WORD, VAL_POP, VAL_COND };
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
CODE_START = 0,
|
||
|
CODE_OFFSET,
|
||
|
CODE_NULL, CODE_TRUE, CODE_FALSE, CODE_NOT,
|
||
|
CODE_POP,
|
||
|
CODE_ENTER, CODE_ENTER_RESULT,
|
||
|
CODE_EXIT, CODE_RESULT_ARG,
|
||
|
CODE_VAL, CODE_VALI,
|
||
|
CODE_DUP,
|
||
|
CODE_MACRO,
|
||
|
CODE_BOOL,
|
||
|
CODE_BLOCK, CODE_EMPTY,
|
||
|
CODE_COMPILE, CODE_COND,
|
||
|
CODE_FORCE,
|
||
|
CODE_RESULT,
|
||
|
CODE_IDENT, CODE_IDENTU, CODE_IDENTARG,
|
||
|
CODE_COM, CODE_COMD, CODE_COMC, CODE_COMV,
|
||
|
CODE_CONC, CODE_CONCW, CODE_CONCM, CODE_DOWN,
|
||
|
CODE_SVAR, CODE_SVARM, CODE_SVAR1,
|
||
|
CODE_IVAR, CODE_IVAR1, CODE_IVAR2, CODE_IVAR3,
|
||
|
CODE_FVAR, CODE_FVAR1,
|
||
|
CODE_LOOKUP, CODE_LOOKUPU, CODE_LOOKUPARG,
|
||
|
CODE_LOOKUPM, CODE_LOOKUPMU, CODE_LOOKUPMARG,
|
||
|
CODE_ALIAS, CODE_ALIASU, CODE_ALIASARG, CODE_CALL, CODE_CALLU, CODE_CALLARG,
|
||
|
CODE_PRINT,
|
||
|
CODE_LOCAL,
|
||
|
CODE_DO, CODE_DOARGS,
|
||
|
CODE_JUMP, CODE_JUMP_TRUE, CODE_JUMP_FALSE, CODE_JUMP_RESULT_TRUE, CODE_JUMP_RESULT_FALSE,
|
||
|
|
||
|
CODE_OP_MASK = 0x3F,
|
||
|
CODE_RET = 6,
|
||
|
CODE_RET_MASK = 0xC0,
|
||
|
|
||
|
/* return type flags */
|
||
|
RET_NULL = VAL_NULL<<CODE_RET,
|
||
|
RET_STR = VAL_STR<<CODE_RET,
|
||
|
RET_INT = VAL_INT<<CODE_RET,
|
||
|
RET_FLOAT = VAL_FLOAT<<CODE_RET,
|
||
|
};
|
||
|
|
||
|
enum { ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND, ID_ALIAS, ID_LOCAL, ID_DO, ID_DOARGS, ID_IF, ID_RESULT, ID_NOT, ID_AND, ID_OR };
|
||
|
|
||
|
enum { IDF_PERSIST = 1<<0, IDF_OVERRIDE = 1<<1, IDF_HEX = 1<<2, IDF_READONLY = 1<<3, IDF_OVERRIDDEN = 1<<4, IDF_UNKNOWN = 1<<5, IDF_ARG = 1<<6 };
|
||
|
|
||
|
struct ident;
|
||
|
|
||
|
struct identval
|
||
|
{
|
||
|
union
|
||
|
{
|
||
|
int i; // ID_VAR, VAL_INT
|
||
|
float f; // ID_FVAR, VAL_FLOAT
|
||
|
char *s; // ID_SVAR, VAL_STR
|
||
|
const uint *code; // VAL_CODE
|
||
|
ident *id; // VAL_IDENT
|
||
|
const char *cstr; // VAL_CSTR
|
||
|
};
|
||
|
};
|
||
|
|
||
|
struct tagval : identval
|
||
|
{
|
||
|
int type;
|
||
|
|
||
|
void setint(int val) { type = VAL_INT; i = val; }
|
||
|
void setfloat(float val) { type = VAL_FLOAT; f = val; }
|
||
|
void setnumber(double val) { i = int(val); if(val == i) type = VAL_INT; else { type = VAL_FLOAT; f = val; } }
|
||
|
void setstr(char *val) { type = VAL_STR; s = val; }
|
||
|
void setnull() { type = VAL_NULL; i = 0; }
|
||
|
void setcode(const uint *val) { type = VAL_CODE; code = val; }
|
||
|
void setmacro(const uint *val) { type = VAL_MACRO; code = val; }
|
||
|
void setcstr(const char *val) { type = VAL_CSTR; cstr = val; }
|
||
|
void setident(ident *val) { type = VAL_IDENT; id = val; }
|
||
|
|
||
|
const char *getstr() const;
|
||
|
int getint() const;
|
||
|
float getfloat() const;
|
||
|
double getnumber() const;
|
||
|
bool getbool() const;
|
||
|
void getval(tagval &r) const;
|
||
|
|
||
|
void cleanup();
|
||
|
};
|
||
|
|
||
|
struct identstack
|
||
|
{
|
||
|
identval val;
|
||
|
int valtype;
|
||
|
identstack *next;
|
||
|
};
|
||
|
|
||
|
union identvalptr
|
||
|
{
|
||
|
void *p; // ID_*VAR
|
||
|
int *i; // ID_VAR
|
||
|
float *f; // ID_FVAR
|
||
|
char **s; // ID_SVAR
|
||
|
};
|
||
|
|
||
|
typedef void (__cdecl *identfun)(ident *id);
|
||
|
|
||
|
struct ident
|
||
|
{
|
||
|
uchar type; // one of ID_* above
|
||
|
union
|
||
|
{
|
||
|
uchar valtype; // ID_ALIAS
|
||
|
uchar numargs; // ID_COMMAND
|
||
|
};
|
||
|
ushort flags;
|
||
|
int index;
|
||
|
const char *name;
|
||
|
union
|
||
|
{
|
||
|
struct // ID_VAR, ID_FVAR, ID_SVAR
|
||
|
{
|
||
|
union
|
||
|
{
|
||
|
struct { int minval, maxval; }; // ID_VAR
|
||
|
struct { float minvalf, maxvalf; }; // ID_FVAR
|
||
|
};
|
||
|
identvalptr storage;
|
||
|
identval overrideval;
|
||
|
};
|
||
|
struct // ID_ALIAS
|
||
|
{
|
||
|
uint *code;
|
||
|
identval val;
|
||
|
identstack *stack;
|
||
|
};
|
||
|
struct // ID_COMMAND
|
||
|
{
|
||
|
const char *args;
|
||
|
uint argmask;
|
||
|
};
|
||
|
};
|
||
|
identfun fun; // ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND
|
||
|
|
||
|
ident() {}
|
||
|
// ID_VAR
|
||
|
ident(int t, const char *n, int m, int x, int *s, void *f = NULL, int flags = 0)
|
||
|
: type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minval(m), maxval(x), fun((identfun)f)
|
||
|
{ storage.i = s; }
|
||
|
// ID_FVAR
|
||
|
ident(int t, const char *n, float m, float x, float *s, void *f = NULL, int flags = 0)
|
||
|
: type(t), flags(flags | (m > x ? IDF_READONLY : 0)), name(n), minvalf(m), maxvalf(x), fun((identfun)f)
|
||
|
{ storage.f = s; }
|
||
|
// ID_SVAR
|
||
|
ident(int t, const char *n, char **s, void *f = NULL, int flags = 0)
|
||
|
: type(t), flags(flags), name(n), fun((identfun)f)
|
||
|
{ storage.s = s; }
|
||
|
// ID_ALIAS
|
||
|
ident(int t, const char *n, char *a, int flags)
|
||
|
: type(t), valtype(VAL_STR), flags(flags), name(n), code(NULL), stack(NULL)
|
||
|
{ val.s = a; }
|
||
|
ident(int t, const char *n, int a, int flags)
|
||
|
: type(t), valtype(VAL_INT), flags(flags), name(n), code(NULL), stack(NULL)
|
||
|
{ val.i = a; }
|
||
|
ident(int t, const char *n, float a, int flags)
|
||
|
: type(t), valtype(VAL_FLOAT), flags(flags), name(n), code(NULL), stack(NULL)
|
||
|
{ val.f = a; }
|
||
|
ident(int t, const char *n, int flags)
|
||
|
: type(t), valtype(VAL_NULL), flags(flags), name(n), code(NULL), stack(NULL)
|
||
|
{}
|
||
|
ident(int t, const char *n, const tagval &v, int flags)
|
||
|
: type(t), valtype(v.type), flags(flags), name(n), code(NULL), stack(NULL)
|
||
|
{ val = v; }
|
||
|
// ID_COMMAND
|
||
|
ident(int t, const char *n, const char *args, uint argmask, int numargs, void *f = NULL, int flags = 0)
|
||
|
: type(t), numargs(numargs), flags(flags), name(n), args(args), argmask(argmask), fun((identfun)f)
|
||
|
{}
|
||
|
|
||
|
void changed() { if(fun) fun(this); }
|
||
|
|
||
|
void setval(const tagval &v)
|
||
|
{
|
||
|
valtype = v.type;
|
||
|
val = v;
|
||
|
}
|
||
|
|
||
|
void setval(const identstack &v)
|
||
|
{
|
||
|
valtype = v.valtype;
|
||
|
val = v.val;
|
||
|
}
|
||
|
|
||
|
void forcenull()
|
||
|
{
|
||
|
if(valtype==VAL_STR) delete[] val.s;
|
||
|
valtype = VAL_NULL;
|
||
|
}
|
||
|
|
||
|
float getfloat() const;
|
||
|
int getint() const;
|
||
|
double getnumber() const;
|
||
|
const char *getstr() const;
|
||
|
void getval(tagval &r) const;
|
||
|
void getcstr(tagval &v) const;
|
||
|
void getcval(tagval &v) const;
|
||
|
};
|
||
|
|
||
|
extern void addident(ident *id);
|
||
|
|
||
|
extern tagval *commandret;
|
||
|
extern const char *intstr(int v);
|
||
|
extern void intret(int v);
|
||
|
extern const char *floatstr(float v);
|
||
|
extern void floatret(float v);
|
||
|
extern const char *numberstr(double v);
|
||
|
extern void numberret(double v);
|
||
|
extern void stringret(char *s);
|
||
|
extern void result(tagval &v);
|
||
|
extern void result(const char *s);
|
||
|
|
||
|
static inline int parseint(const char *s)
|
||
|
{
|
||
|
return int(strtoul(s, NULL, 0));
|
||
|
}
|
||
|
|
||
|
#define PARSEFLOAT(name, type) \
|
||
|
static inline type parse##name(const char *s) \
|
||
|
{ \
|
||
|
/* not all platforms (windows) can parse hexadecimal integers via strtod */ \
|
||
|
char *end; \
|
||
|
double val = strtod(s, &end); \
|
||
|
return val || end==s || (*end!='x' && *end!='X') ? type(val) : type(parseint(s)); \
|
||
|
}
|
||
|
PARSEFLOAT(float, float)
|
||
|
PARSEFLOAT(number, double)
|
||
|
|
||
|
static inline void intformat(char *buf, int v, int len = 20) { nformatstring(buf, len, "%d", v); }
|
||
|
static inline void floatformat(char *buf, float v, int len = 20) { nformatstring(buf, len, v==int(v) ? "%.1f" : "%.7g", v); }
|
||
|
static inline void numberformat(char *buf, double v, int len = 20)
|
||
|
{
|
||
|
int i = int(v);
|
||
|
if(v == i) nformatstring(buf, len, "%d", i);
|
||
|
else nformatstring(buf, len, "%.7g", v);
|
||
|
}
|
||
|
|
||
|
static inline const char *getstr(const identval &v, int type)
|
||
|
{
|
||
|
switch(type)
|
||
|
{
|
||
|
case VAL_STR: case VAL_MACRO: case VAL_CSTR: return v.s;
|
||
|
case VAL_INT: return intstr(v.i);
|
||
|
case VAL_FLOAT: return floatstr(v.f);
|
||
|
default: return "";
|
||
|
}
|
||
|
}
|
||
|
inline const char *tagval::getstr() const { return ::getstr(*this, type); }
|
||
|
inline const char *ident::getstr() const { return ::getstr(val, valtype); }
|
||
|
|
||
|
#define GETNUMBER(name, ret) \
|
||
|
static inline ret get##name(const identval &v, int type) \
|
||
|
{ \
|
||
|
switch(type) \
|
||
|
{ \
|
||
|
case VAL_FLOAT: return ret(v.f); \
|
||
|
case VAL_INT: return ret(v.i); \
|
||
|
case VAL_STR: case VAL_MACRO: case VAL_CSTR: return parse##name(v.s); \
|
||
|
default: return ret(0); \
|
||
|
} \
|
||
|
} \
|
||
|
inline ret tagval::get##name() const { return ::get##name(*this, type); } \
|
||
|
inline ret ident::get##name() const { return ::get##name(val, valtype); }
|
||
|
GETNUMBER(int, int)
|
||
|
GETNUMBER(float, float)
|
||
|
GETNUMBER(number, double)
|
||
|
|
||
|
static inline void getval(const identval &v, int type, tagval &r)
|
||
|
{
|
||
|
switch(type)
|
||
|
{
|
||
|
case VAL_STR: case VAL_MACRO: case VAL_CSTR: r.setstr(newstring(v.s)); break;
|
||
|
case VAL_INT: r.setint(v.i); break;
|
||
|
case VAL_FLOAT: r.setfloat(v.f); break;
|
||
|
default: r.setnull(); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void tagval::getval(tagval &r) const { ::getval(*this, type, r); }
|
||
|
inline void ident::getval(tagval &r) const { ::getval(val, valtype, r); }
|
||
|
|
||
|
inline void ident::getcstr(tagval &v) const
|
||
|
{
|
||
|
switch(valtype)
|
||
|
{
|
||
|
case VAL_MACRO: v.setmacro(val.code); break;
|
||
|
case VAL_STR: case VAL_CSTR: v.setcstr(val.s); break;
|
||
|
case VAL_INT: v.setstr(newstring(intstr(val.i))); break;
|
||
|
case VAL_FLOAT: v.setstr(newstring(floatstr(val.f))); break;
|
||
|
default: v.setcstr(""); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void ident::getcval(tagval &v) const
|
||
|
{
|
||
|
switch(valtype)
|
||
|
{
|
||
|
case VAL_MACRO: v.setmacro(val.code); break;
|
||
|
case VAL_STR: case VAL_CSTR: v.setcstr(val.s); break;
|
||
|
case VAL_INT: v.setint(val.i); break;
|
||
|
case VAL_FLOAT: v.setfloat(val.f); break;
|
||
|
default: v.setnull(); break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// nasty macros for registering script functions, abuses globals to avoid excessive infrastructure
|
||
|
#define KEYWORD(name, type) UNUSED static bool __dummy_##type = addcommand(#name, (identfun)NULL, NULL, type)
|
||
|
#define COMMANDKN(name, type, fun, nargs) UNUSED static bool __dummy_##fun = addcommand(#name, (identfun)fun, nargs, type)
|
||
|
#define COMMANDK(name, type, nargs) COMMANDKN(name, type, name, nargs)
|
||
|
#define COMMANDN(name, fun, nargs) COMMANDKN(name, ID_COMMAND, fun, nargs)
|
||
|
#define COMMAND(name, nargs) COMMANDN(name, name, nargs)
|
||
|
|
||
|
#define _VAR(name, global, min, cur, max, persist) int global = variable(#name, min, cur, max, &global, NULL, persist)
|
||
|
#define VARN(name, global, min, cur, max) _VAR(name, global, min, cur, max, 0)
|
||
|
#define VARNP(name, global, min, cur, max) _VAR(name, global, min, cur, max, IDF_PERSIST)
|
||
|
#define VARNR(name, global, min, cur, max) _VAR(name, global, min, cur, max, IDF_OVERRIDE)
|
||
|
#define VAR(name, min, cur, max) _VAR(name, name, min, cur, max, 0)
|
||
|
#define VARP(name, min, cur, max) _VAR(name, name, min, cur, max, IDF_PERSIST)
|
||
|
#define VARR(name, min, cur, max) _VAR(name, name, min, cur, max, IDF_OVERRIDE)
|
||
|
#define _VARF(name, global, min, cur, max, body, persist) void var_##name(ident *id); int global = variable(#name, min, cur, max, &global, var_##name, persist); void var_##name(ident *id) { body; }
|
||
|
#define VARFN(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, 0)
|
||
|
#define VARF(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, 0)
|
||
|
#define VARFP(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, IDF_PERSIST)
|
||
|
#define VARFR(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, IDF_OVERRIDE)
|
||
|
#define VARFNP(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, IDF_PERSIST)
|
||
|
#define VARFNR(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, IDF_OVERRIDE)
|
||
|
#define _VARM(name, min, cur, max, scale, persist) int name = cur * scale; _VARF(name, _##name, min, cur, max, { name = _##name * scale; }, persist)
|
||
|
#define VARMP(name, min, cur, max, scale) _VARM(name, min, cur, max, scale, IDF_PERSIST)
|
||
|
#define VARMR(name, min, cur, max, scale) _VARM(name, min, cur, max, scale, IDF_OVERRIDE)
|
||
|
|
||
|
#define _HVAR(name, global, min, cur, max, persist) int global = variable(#name, min, cur, max, &global, NULL, persist | IDF_HEX)
|
||
|
#define HVARN(name, global, min, cur, max) _HVAR(name, global, min, cur, max, 0)
|
||
|
#define HVARNP(name, global, min, cur, max) _HVAR(name, global, min, cur, max, IDF_PERSIST)
|
||
|
#define HVARNR(name, global, min, cur, max) _HVAR(name, global, min, cur, max, IDF_OVERRIDE)
|
||
|
#define HVAR(name, min, cur, max) _HVAR(name, name, min, cur, max, 0)
|
||
|
#define HVARP(name, min, cur, max) _HVAR(name, name, min, cur, max, IDF_PERSIST)
|
||
|
#define HVARR(name, min, cur, max) _HVAR(name, name, min, cur, max, IDF_OVERRIDE)
|
||
|
#define _HVARF(name, global, min, cur, max, body, persist) void var_##name(ident *id); int global = variable(#name, min, cur, max, &global, var_##name, persist | IDF_HEX); void var_##name(ident *id) { body; }
|
||
|
#define HVARFN(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, 0)
|
||
|
#define HVARF(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, 0)
|
||
|
#define HVARFP(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, IDF_PERSIST)
|
||
|
#define HVARFR(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, IDF_OVERRIDE)
|
||
|
#define HVARFNP(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, IDF_PERSIST)
|
||
|
#define HVARFNR(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, IDF_OVERRIDE)
|
||
|
|
||
|
#define _CVAR(name, cur, init, body, persist) bvec name = bvec::hexcolor(cur); _HVARF(name, _##name, 0, cur, 0xFFFFFF, { init; name = bvec::hexcolor(_##name); body; }, persist)
|
||
|
#define CVARP(name, cur) _CVAR(name, cur, , , IDF_PERSIST)
|
||
|
#define CVARR(name, cur) _CVAR(name, cur, , , IDF_OVERRIDE)
|
||
|
#define CVARFP(name, cur, body) _CVAR(name, cur, , body, IDF_PERSIST)
|
||
|
#define CVARFR(name, cur, body) _CVAR(name, cur, , body, IDF_OVERRIDE)
|
||
|
#define _CVAR0(name, cur, body, persist) _CVAR(name, cur, { if(!_##name) _##name = cur; }, body, persist)
|
||
|
#define CVAR0P(name, cur) _CVAR0(name, cur, , IDF_PERSIST)
|
||
|
#define CVAR0R(name, cur) _CVAR0(name, cur, , IDF_OVERRIDE)
|
||
|
#define CVAR0FP(name, cur, body) _CVAR0(name, cur, body, IDF_PERSIST)
|
||
|
#define CVAR0FR(name, cur, body) _CVAR0(name, cur, body, IDF_OVERRIDE)
|
||
|
#define _CVAR1(name, cur, body, persist) _CVAR(name, cur, { if(_##name <= 255) _##name |= (_##name<<8) | (_##name<<16); }, body, persist)
|
||
|
#define CVAR1P(name, cur) _CVAR1(name, cur, , IDF_PERSIST)
|
||
|
#define CVAR1R(name, cur) _CVAR1(name, cur, , IDF_OVERRIDE)
|
||
|
#define CVAR1FP(name, cur, body) _CVAR1(name, cur, body, IDF_PERSIST)
|
||
|
#define CVAR1FR(name, cur, body) _CVAR1(name, cur, body, IDF_OVERRIDE)
|
||
|
|
||
|
#define _FVAR(name, global, min, cur, max, persist) float global = fvariable(#name, min, cur, max, &global, NULL, persist)
|
||
|
#define FVARN(name, global, min, cur, max) _FVAR(name, global, min, cur, max, 0)
|
||
|
#define FVARNP(name, global, min, cur, max) _FVAR(name, global, min, cur, max, IDF_PERSIST)
|
||
|
#define FVARNR(name, global, min, cur, max) _FVAR(name, global, min, cur, max, IDF_OVERRIDE)
|
||
|
#define FVAR(name, min, cur, max) _FVAR(name, name, min, cur, max, 0)
|
||
|
#define FVARP(name, min, cur, max) _FVAR(name, name, min, cur, max, IDF_PERSIST)
|
||
|
#define FVARR(name, min, cur, max) _FVAR(name, name, min, cur, max, IDF_OVERRIDE)
|
||
|
#define _FVARF(name, global, min, cur, max, body, persist) void var_##name(ident *id); float global = fvariable(#name, min, cur, max, &global, var_##name, persist); void var_##name(ident *id) { body; }
|
||
|
#define FVARFN(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, 0)
|
||
|
#define FVARF(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, 0)
|
||
|
#define FVARFP(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, IDF_PERSIST)
|
||
|
#define FVARFR(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, IDF_OVERRIDE)
|
||
|
#define FVARFNP(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, IDF_PERSIST)
|
||
|
#define FVARFNR(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, IDF_OVERRIDE)
|
||
|
|
||
|
#define _SVAR(name, global, cur, persist) char *global = svariable(#name, cur, &global, NULL, persist)
|
||
|
#define SVARN(name, global, cur) _SVAR(name, global, cur, 0)
|
||
|
#define SVARNP(name, global, cur) _SVAR(name, global, cur, IDF_PERSIST)
|
||
|
#define SVARNR(name, global, cur) _SVAR(name, global, cur, IDF_OVERRIDE)
|
||
|
#define SVAR(name, cur) _SVAR(name, name, cur, 0)
|
||
|
#define SVARP(name, cur) _SVAR(name, name, cur, IDF_PERSIST)
|
||
|
#define SVARR(name, cur) _SVAR(name, name, cur, IDF_OVERRIDE)
|
||
|
#define _SVARF(name, global, cur, body, persist) void var_##name(ident *id); char *global = svariable(#name, cur, &global, var_##name, persist); void var_##name(ident *id) { body; }
|
||
|
#define SVARFN(name, global, cur, body) _SVARF(name, global, cur, body, 0)
|
||
|
#define SVARF(name, cur, body) _SVARF(name, name, cur, body, 0)
|
||
|
#define SVARFP(name, cur, body) _SVARF(name, name, cur, body, IDF_PERSIST)
|
||
|
#define SVARFR(name, cur, body) _SVARF(name, name, cur, body, IDF_OVERRIDE)
|
||
|
#define SVARFNP(name, global, cur, body) _SVARF(name, global, cur, body, IDF_PERSIST)
|
||
|
#define SVARFNR(name, global, cur, body) _SVARF(name, global, cur, body, IDF_OVERRIDE)
|
||
|
|
||
|
// anonymous inline commands, uses nasty template trick with line numbers to keep names unique
|
||
|
#define ICOMMANDNAME(name) _icmd_##name
|
||
|
#define ICOMMANDSNAME _icmds_
|
||
|
#define ICOMMANDKNS(name, type, cmdname, nargs, proto, b) template<int N> struct cmdname; template<> struct cmdname<__LINE__> { static bool init; static void run proto; }; bool cmdname<__LINE__>::init = addcommand(name, (identfun)cmdname<__LINE__>::run, nargs, type); void cmdname<__LINE__>::run proto \
|
||
|
{ b; }
|
||
|
#define ICOMMANDKN(name, type, cmdname, nargs, proto, b) ICOMMANDKNS(#name, type, cmdname, nargs, proto, b)
|
||
|
#define ICOMMANDK(name, type, nargs, proto, b) ICOMMANDKN(name, type, ICOMMANDNAME(name), nargs, proto, b)
|
||
|
#define ICOMMANDKS(name, type, nargs, proto, b) ICOMMANDKNS(name, type, ICOMMANDSNAME, nargs, proto, b)
|
||
|
#define ICOMMANDNS(name, cmdname, nargs, proto, b) ICOMMANDKNS(name, ID_COMMAND, cmdname, nargs, proto, b)
|
||
|
#define ICOMMANDN(name, cmdname, nargs, proto, b) ICOMMANDNS(#name, cmdname, nargs, proto, b)
|
||
|
#define ICOMMAND(name, nargs, proto, b) ICOMMANDN(name, ICOMMANDNAME(name), nargs, proto, b)
|
||
|
#define ICOMMANDS(name, nargs, proto, b) ICOMMANDNS(name, ICOMMANDSNAME, nargs, proto, b)
|
||
|
|