| // script binding functionality |
| |
| |
| enum { ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND, ID_CCOMMAND, ID_ALIAS }; |
| |
| enum { NO_OVERRIDE = INT_MAX, OVERRIDDEN = 0 }; |
| |
| enum { IDF_PERSIST = 1<<0, IDF_OVERRIDE = 1<<1, IDF_HEX = 1<<2, IDF_READONLY = 1<<3 }; |
| |
| struct identstack |
| { |
| char *action; |
| identstack *next; |
| }; |
| |
| union identval |
| { |
| int i; // ID_VAR |
| float f; // ID_FVAR |
| char *s; // ID_SVAR |
| }; |
| |
| union identvalptr |
| { |
| int *i; // ID_VAR |
| float *f; // ID_FVAR |
| char **s; // ID_SVAR |
| }; |
| |
| struct ident |
| { |
| int type; // one of ID_* above |
| const char *name; |
| union |
| { |
| int minval; // ID_VAR |
| float minvalf; // ID_FVAR |
| }; |
| union |
| { |
| int maxval; // ID_VAR |
| float maxvalf; // ID_FVAR |
| }; |
| int override; // either NO_OVERRIDE, OVERRIDDEN, or value |
| union |
| { |
| void (__cdecl *fun)(); // ID_VAR, ID_COMMAND, ID_CCOMMAND |
| identstack *stack; // ID_ALIAS |
| }; |
| union |
| { |
| const char *narg; // ID_COMMAND, ID_CCOMMAND |
| char *action; // ID_ALIAS |
| identval val; // ID_VAR, ID_FVAR, ID_SVAR |
| }; |
| union |
| { |
| void *self; // ID_COMMAND, ID_CCOMMAND |
| char *isexecuting; // ID_ALIAS |
| identval overrideval; // ID_VAR, ID_FVAR, ID_SVAR |
| }; |
| identvalptr storage; // ID_VAR, ID_FVAR, ID_SVAR |
| int flags; |
| |
| ident() {} |
| // ID_VAR |
| ident(int t, const char *n, int m, int c, int x, int *s, void *f = NULL, int flags = 0) |
| : type(t), name(n), minval(m), maxval(x), override(NO_OVERRIDE), fun((void (__cdecl *)())f), flags(flags | (m > x ? IDF_READONLY : 0)) |
| { val.i = c; storage.i = s; } |
| // ID_FVAR |
| ident(int t, const char *n, float m, float c, float x, float *s, void *f = NULL, int flags = 0) |
| : type(t), name(n), minvalf(m), maxvalf(x), override(NO_OVERRIDE), fun((void (__cdecl *)())f), flags(flags | (m > x ? IDF_READONLY : 0)) |
| { val.f = c; storage.f = s; } |
| // ID_SVAR |
| ident(int t, const char *n, char *c, char **s, void *f = NULL, int flags = 0) |
| : type(t), name(n), override(NO_OVERRIDE), fun((void (__cdecl *)())f), flags(flags) |
| { val.s = c; storage.s = s; } |
| // ID_ALIAS |
| ident(int t, const char *n, char *a, int flags) |
| : type(t), name(n), override(NO_OVERRIDE), stack(NULL), action(a), isexecuting(NULL), flags(flags) {} |
| // ID_COMMAND, ID_CCOMMAND |
| ident(int t, const char *n, const char *narg, void *f = NULL, void *s = NULL, int flags = 0) |
| : type(t), name(n), override(NO_OVERRIDE), fun((void (__cdecl *)(void))f), narg(narg), self(s), flags(flags) {} |
| |
| virtual ~ident() {} |
| |
| ident &operator=(const ident &o) { memcpy(this, &o, sizeof(ident)); return *this; } // force vtable copy, ugh |
| |
| virtual void changed() { if(fun) fun(); } |
| }; |
| |
| extern void addident(const char *name, ident *id); |
| extern const char *intstr(int v); |
| extern void intret(int v); |
| extern const char *floatstr(float v); |
| extern void floatret(float v); |
| extern void result(const char *s); |
| |
| static inline int parseint(const char *s) |
| { |
| return int(strtol(s, NULL, 0)); |
| } |
| |
| static inline float parsefloat(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') ? float(val) : float(parseint(s)); |
| } |
| |
| // nasty macros for registering script functions, abuses globals to avoid excessive infrastructure |
| #define COMMANDN(name, fun, nargs) static bool __dummy_##fun = addcommand(#name, (void (*)())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(); int global = variable(#name, min, cur, max, &global, var_##name, persist); void var_##name() { 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 _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(); int global = variable(#name, min, cur, max, &global, var_##name, persist | IDF_HEX); void var_##name() { 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 _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(); float global = fvariable(#name, min, cur, max, &global, var_##name, persist); void var_##name() { 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 _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(); char *global = svariable(#name, cur, &global, var_##name, persist); void var_##name() { 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) |
| |
| // new style macros, have the body inline, and allow binds to happen anywhere, even inside class constructors, and access the surrounding class |
| #define _CCOMMAND(idtype, tv, n, g, proto, b) \ |
| struct _ccmd_##n : ident \ |
| { \ |
| _ccmd_##n(void *self = NULL) : ident(idtype, #n, g, (void *)run, self) \ |
| { \ |
| addident(name, this); \ |
| } \ |
| static void run proto { b; } \ |
| } __ccmd_##n tv |
| #define CCOMMAND(n, g, proto, b) _CCOMMAND(ID_CCOMMAND, (this), n, g, proto, b) |
| |
| // anonymous inline commands, uses nasty template trick with line numbers to keep names unique |
| #define _ICOMMAND(cmdname, name, 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, (void (*)())cmdname<__LINE__>::run, nargs); void cmdname<__LINE__>::run proto \ |
| { b; } |
| #define ICOMMANDNAME(name) _icmd_##name |
| #define ICOMMAND(name, nargs, proto, b) _ICOMMAND(ICOMMANDNAME(name), #name, nargs, proto, b) |
| #define ICOMMANDSNAME _icmds_ |
| #define ICOMMANDS(name, nargs, proto, b) _ICOMMAND(ICOMMANDSNAME, name, nargs, proto, b) |
| |
| #define _IVAR(n, m, c, x, b, p) \ |
| struct var_##n : ident \ |
| { \ |
| var_##n() : ident(ID_VAR, #n, m, c, x, &val.i, NULL, p) \ |
| { \ |
| addident(name, this); \ |
| } \ |
| int operator()() { return val.i; } \ |
| b \ |
| } n |
| #define IVAR(n, m, c, x) _IVAR(n, m, c, x, , 0) |
| #define IVARF(n, m, c, x, b) _IVAR(n, m, c, x, void changed() { b; }, 0) |
| #define IVARP(n, m, c, x) _IVAR(n, m, c, x, , IDF_PERSIST) |
| #define IVARR(n, m, c, x) _IVAR(n, m, c, x, , IDF_OVERRIDE) |
| #define IVARFP(n, m, c, x, b) _IVAR(n, m, c, x, void changed() { b; }, IDF_PERSIST) |
| #define IVARFR(n, m, c, x, b) _IVAR(n, m, c, x, void changed() { b; }, IDF_OVERRIDE) |
| |