1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
// 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)
|