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)
|