1 // script binding functionality
2 
3 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 };
4 
5 enum
6 {
7     CODE_START = 0,
8     CODE_OFFSET,
9     CODE_NULL, CODE_TRUE, CODE_FALSE, CODE_NOT,
10     CODE_POP,
11     CODE_ENTER, CODE_ENTER_RESULT,
12     CODE_EXIT, CODE_RESULT_ARG,
13     CODE_VAL, CODE_VALI,
14     CODE_DUP,
15     CODE_MACRO,
16     CODE_BOOL,
17     CODE_BLOCK, CODE_EMPTY,
18     CODE_COMPILE, CODE_COND,
19     CODE_FORCE,
20     CODE_RESULT,
21     CODE_IDENT, CODE_IDENTU, CODE_IDENTARG,
22     CODE_COM, CODE_COMD, CODE_COMC, CODE_COMV,
23     CODE_CONC, CODE_CONCW, CODE_CONCM, CODE_DOWN,
24     CODE_SVAR, CODE_SVARM, CODE_SVAR1,
25     CODE_IVAR, CODE_IVAR1, CODE_IVAR2, CODE_IVAR3,
26     CODE_FVAR, CODE_FVAR1,
27     CODE_LOOKUP, CODE_LOOKUPU, CODE_LOOKUPARG,
28     CODE_LOOKUPM, CODE_LOOKUPMU, CODE_LOOKUPMARG,
29     CODE_ALIAS, CODE_ALIASU, CODE_ALIASARG, CODE_CALL, CODE_CALLU, CODE_CALLARG,
30     CODE_PRINT,
31     CODE_LOCAL,
32     CODE_DO, CODE_DOARGS,
33     CODE_JUMP, CODE_JUMP_TRUE, CODE_JUMP_FALSE, CODE_JUMP_RESULT_TRUE, CODE_JUMP_RESULT_FALSE,
34 
35     CODE_OP_MASK = 0x3F,
36     CODE_RET = 6,
37     CODE_RET_MASK = 0xC0,
38 
39     /* return type flags */
40     RET_NULL   = VAL_NULL<<CODE_RET,
41     RET_STR    = VAL_STR<<CODE_RET,
42     RET_INT    = VAL_INT<<CODE_RET,
43     RET_FLOAT  = VAL_FLOAT<<CODE_RET,
44 };
45 
46 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 };
47 
48 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 };
49 
50 struct ident;
51 
52 struct identval
53 {
54     union
55     {
56         int i;      // ID_VAR, VAL_INT
57         float f;    // ID_FVAR, VAL_FLOAT
58         char *s;    // ID_SVAR, VAL_STR
59         const uint *code; // VAL_CODE
60         ident *id;  // VAL_IDENT
61         const char *cstr; // VAL_CSTR
62     };
63 };
64 
65 struct tagval : identval
66 {
67     int type;
68 
setinttagval69     void setint(int val) { type = VAL_INT; i = val; }
setfloattagval70     void setfloat(float val) { type = VAL_FLOAT; f = val; }
setnumbertagval71     void setnumber(double val) { i = int(val); if(val == i) type = VAL_INT; else { type = VAL_FLOAT; f = val; } }
setstrtagval72     void setstr(char *val) { type = VAL_STR; s = val; }
setnulltagval73     void setnull() { type = VAL_NULL; i = 0; }
setcodetagval74     void setcode(const uint *val) { type = VAL_CODE; code = val; }
setmacrotagval75     void setmacro(const uint *val) { type = VAL_MACRO; code = val; }
setcstrtagval76     void setcstr(const char *val) { type = VAL_CSTR; cstr = val; }
setidenttagval77     void setident(ident *val) { type = VAL_IDENT; id = val; }
78 
79     const char *getstr() const;
80     int getint() const;
81     float getfloat() const;
82     double getnumber() const;
83     bool getbool() const;
84     void getval(tagval &r) const;
85 
86     void cleanup();
87 };
88 
89 struct identstack
90 {
91     identval val;
92     int valtype;
93     identstack *next;
94 };
95 
96 union identvalptr
97 {
98     void *p;  // ID_*VAR
99     int *i;   // ID_VAR
100     float *f; // ID_FVAR
101     char **s; // ID_SVAR
102 };
103 
104 typedef void (__cdecl *identfun)(ident *id);
105 
106 struct ident
107 {
108     int type;           // one of ID_* above
109     const char *name;
110     union
111     {
112         int minval;    // ID_VAR
113         float minvalf; // ID_FVAR
114         int valtype;   // ID_ALIAS
115         int numargs;   // ID_COMMAND
116     };
117     union
118     {
119         int maxval;    // ID_VAR
120         float maxvalf; // ID_FVAR
121         uint *code;    // ID_ALIAS
122     };
123     union
124     {
125         const char *args;    // ID_COMMAND
126         identval val;        // ID_ALIAS
127         identvalptr storage; // ID_VAR, ID_FVAR, ID_SVAR
128     };
129     union
130     {
131         identval overrideval; // ID_VAR, ID_FVAR, ID_SVAR
132         identstack *stack;    // ID_ALIAS
133         uint argmask;         // ID_COMMAND
134     };
135     identfun fun; // ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND
136     int flags, index;
137 
identident138     ident() {}
139     // ID_VAR
140     ident(int t, const char *n, int m, int x, int *s, void *f = NULL, int flags = 0)
typeident141         : type(t), name(n), minval(m), maxval(x), fun((identfun)f), flags(flags | (m > x ? IDF_READONLY : 0))
142     { storage.i = s; }
143     // ID_FVAR
144     ident(int t, const char *n, float m, float x, float *s, void *f = NULL, int flags = 0)
typeident145         : type(t), name(n), minvalf(m), maxvalf(x), fun((identfun)f), flags(flags | (m > x ? IDF_READONLY : 0))
146     { storage.f = s; }
147     // ID_SVAR
148     ident(int t, const char *n, char **s, void *f = NULL, int flags = 0)
typeident149         : type(t), name(n), fun((identfun)f), flags(flags)
150     { storage.s = s; }
151     // ID_ALIAS
identident152     ident(int t, const char *n, char *a, int flags)
153         : type(t), name(n), valtype(VAL_STR), code(NULL), stack(NULL), flags(flags)
154     { val.s = a; }
identident155     ident(int t, const char *n, int a, int flags)
156         : type(t), name(n), valtype(VAL_INT), code(NULL), stack(NULL), flags(flags)
157     { val.i = a; }
identident158     ident(int t, const char *n, float a, int flags)
159         : type(t), name(n), valtype(VAL_FLOAT), code(NULL), stack(NULL), flags(flags)
160     { val.f = a; }
identident161     ident(int t, const char *n, int flags)
162         : type(t), name(n), valtype(VAL_NULL), code(NULL), stack(NULL), flags(flags)
163     {}
identident164     ident(int t, const char *n, const tagval &v, int flags)
165         : type(t), name(n), valtype(v.type), code(NULL), stack(NULL), flags(flags)
166     { val = v; }
167     // ID_COMMAND
168     ident(int t, const char *n, const char *args, uint argmask, int numargs, void *f = NULL, int flags = 0)
typeident169         : type(t), name(n), numargs(numargs), args(args), argmask(argmask), fun((identfun)f), flags(flags)
170     {}
171 
changedident172     void changed() { if(fun) fun(this); }
173 
setvalident174     void setval(const tagval &v)
175     {
176         valtype = v.type;
177         val = v;
178     }
179 
setvalident180     void setval(const identstack &v)
181     {
182         valtype = v.valtype;
183         val = v.val;
184     }
185 
forcenullident186     void forcenull()
187     {
188         if(valtype==VAL_STR) delete[] val.s;
189         valtype = VAL_NULL;
190     }
191 
192     float getfloat() const;
193     int getint() const;
194     double getnumber() const;
195     const char *getstr() const;
196     void getval(tagval &r) const;
197     void getcstr(tagval &v) const;
198     void getcval(tagval &v) const;
199 };
200 
201 extern void addident(ident *id);
202 
203 extern tagval *commandret;
204 extern const char *intstr(int v);
205 extern void intret(int v);
206 extern const char *floatstr(float v);
207 extern void floatret(float v);
208 extern const char *numberstr(double v);
209 extern void numberret(double v);
210 extern void stringret(char *s);
211 extern void result(tagval &v);
212 extern void result(const char *s);
213 
parseint(const char * s)214 static inline int parseint(const char *s)
215 {
216     return int(strtoul(s, NULL, 0));
217 }
218 
219 #define PARSEFLOAT(name, type) \
220     static inline type parse##name(const char *s) \
221     { \
222         /* not all platforms (windows) can parse hexadecimal integers via strtod */ \
223         char *end; \
224         double val = strtod(s, &end); \
225         return val || end==s || (*end!='x' && *end!='X') ? type(val) : type(parseint(s)); \
226     }
PARSEFLOAT(float,float)227 PARSEFLOAT(float, float)
228 PARSEFLOAT(number, double)
229 
230 static inline void intformat(char *buf, int v, int len = 20) { nformatstring(buf, len, "%d", v); }
231 static inline void floatformat(char *buf, float v, int len = 20) { nformatstring(buf, len, v==int(v) ? "%.1f" : "%.7g", v); }
232 static inline void numberformat(char *buf, double v, int len = 20)
233 {
234     int i = int(v);
235     if(v == i) nformatstring(buf, len, "%d", i);
236     else nformatstring(buf, len, "%.7g", v);
237 }
238 
getstr(const identval & v,int type)239 static inline const char *getstr(const identval &v, int type)
240 {
241     switch(type)
242     {
243         case VAL_STR: case VAL_MACRO: case VAL_CSTR: return v.s;
244         case VAL_INT: return intstr(v.i);
245         case VAL_FLOAT: return floatstr(v.f);
246         default: return "";
247     }
248 }
getstr()249 inline const char *tagval::getstr() const { return ::getstr(*this, type); }
getstr()250 inline const char *ident::getstr() const { return ::getstr(val, valtype); }
251 
252 #define GETNUMBER(name, ret) \
253     static inline ret get##name(const identval &v, int type) \
254     { \
255         switch(type) \
256         { \
257             case VAL_FLOAT: return ret(v.f); \
258             case VAL_INT: return ret(v.i); \
259             case VAL_STR: case VAL_MACRO: case VAL_CSTR: return parse##name(v.s); \
260             default: return ret(0); \
261         } \
262     } \
263     inline ret tagval::get##name() const { return ::get##name(*this, type); } \
264     inline ret ident::get##name() const { return ::get##name(val, valtype); }
GETNUMBER(int,int)265 GETNUMBER(int, int)
266 GETNUMBER(float, float)
267 GETNUMBER(number, double)
268 
269 static inline void getval(const identval &v, int type, tagval &r)
270 {
271     switch(type)
272     {
273         case VAL_STR: case VAL_MACRO: case VAL_CSTR: r.setstr(newstring(v.s)); break;
274         case VAL_INT: r.setint(v.i); break;
275         case VAL_FLOAT: r.setfloat(v.f); break;
276         default: r.setnull(); break;
277     }
278 }
279 
getval(tagval & r)280 inline void tagval::getval(tagval &r) const { ::getval(*this, type, r); }
getval(tagval & r)281 inline void ident::getval(tagval &r) const { ::getval(val, valtype, r); }
282 
getcstr(tagval & v)283 inline void ident::getcstr(tagval &v) const
284 {
285     switch(valtype)
286     {
287         case VAL_MACRO: v.setmacro(val.code); break;
288         case VAL_STR: case VAL_CSTR: v.setcstr(val.s); break;
289         case VAL_INT: v.setstr(newstring(intstr(val.i))); break;
290         case VAL_FLOAT: v.setstr(newstring(floatstr(val.f))); break;
291         default: v.setcstr(""); break;
292     }
293 }
294 
getcval(tagval & v)295 inline void ident::getcval(tagval &v) const
296 {
297     switch(valtype)
298     {
299         case VAL_MACRO: v.setmacro(val.code); break;
300         case VAL_STR: case VAL_CSTR: v.setcstr(val.s); break;
301         case VAL_INT: v.setint(val.i); break;
302         case VAL_FLOAT: v.setfloat(val.f); break;
303         default: v.setnull(); break;
304     }
305 }
306 
307 // nasty macros for registering script functions, abuses globals to avoid excessive infrastructure
308 #define KEYWORD(name, type) UNUSED static bool __dummy_##type = addcommand(#name, (identfun)NULL, NULL, type)
309 #define COMMANDKN(name, type, fun, nargs) UNUSED static bool __dummy_##fun = addcommand(#name, (identfun)fun, nargs, type)
310 #define COMMANDK(name, type, nargs) COMMANDKN(name, type, name, nargs)
311 #define COMMANDN(name, fun, nargs) COMMANDKN(name, ID_COMMAND, fun, nargs)
312 #define COMMAND(name, nargs) COMMANDN(name, name, nargs)
313 
314 #define _VAR(name, global, min, cur, max, persist)  int global = variable(#name, min, cur, max, &global, NULL, persist)
315 #define VARN(name, global, min, cur, max) _VAR(name, global, min, cur, max, 0)
316 #define VARNP(name, global, min, cur, max) _VAR(name, global, min, cur, max, IDF_PERSIST)
317 #define VARNR(name, global, min, cur, max) _VAR(name, global, min, cur, max, IDF_OVERRIDE)
318 #define VAR(name, min, cur, max) _VAR(name, name, min, cur, max, 0)
319 #define VARP(name, min, cur, max) _VAR(name, name, min, cur, max, IDF_PERSIST)
320 #define VARR(name, min, cur, max) _VAR(name, name, min, cur, max, IDF_OVERRIDE)
321 #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; }
322 #define VARFN(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, 0)
323 #define VARF(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, 0)
324 #define VARFP(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, IDF_PERSIST)
325 #define VARFR(name, min, cur, max, body) _VARF(name, name, min, cur, max, body, IDF_OVERRIDE)
326 #define VARFNP(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, IDF_PERSIST)
327 #define VARFNR(name, global, min, cur, max, body) _VARF(name, global, min, cur, max, body, IDF_OVERRIDE)
328 #define _VARM(name, min, cur, max, scale, persist) int name = cur * scale; _VARF(name, _##name, min, cur, max, { name = _##name * scale; }, persist)
329 #define VARMP(name, min, cur, max, scale) _VARM(name, min, cur, max, scale, IDF_PERSIST)
330 #define VARMR(name, min, cur, max, scale) _VARM(name, min, cur, max, scale, IDF_OVERRIDE)
331 
332 #define _HVAR(name, global, min, cur, max, persist)  int global = variable(#name, min, cur, max, &global, NULL, persist | IDF_HEX)
333 #define HVARN(name, global, min, cur, max) _HVAR(name, global, min, cur, max, 0)
334 #define HVARNP(name, global, min, cur, max) _HVAR(name, global, min, cur, max, IDF_PERSIST)
335 #define HVARNR(name, global, min, cur, max) _HVAR(name, global, min, cur, max, IDF_OVERRIDE)
336 #define HVAR(name, min, cur, max) _HVAR(name, name, min, cur, max, 0)
337 #define HVARP(name, min, cur, max) _HVAR(name, name, min, cur, max, IDF_PERSIST)
338 #define HVARR(name, min, cur, max) _HVAR(name, name, min, cur, max, IDF_OVERRIDE)
339 #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; }
340 #define HVARFN(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, 0)
341 #define HVARF(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, 0)
342 #define HVARFP(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, IDF_PERSIST)
343 #define HVARFR(name, min, cur, max, body) _HVARF(name, name, min, cur, max, body, IDF_OVERRIDE)
344 #define HVARFNP(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, IDF_PERSIST)
345 #define HVARFNR(name, global, min, cur, max, body) _HVARF(name, global, min, cur, max, body, IDF_OVERRIDE)
346 
347 #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)
348 #define CVARP(name, cur) _CVAR(name, cur, , , IDF_PERSIST)
349 #define CVARR(name, cur) _CVAR(name, cur, , , IDF_OVERRIDE)
350 #define CVARFP(name, cur, body) _CVAR(name, cur, , body, IDF_PERSIST)
351 #define CVARFR(name, cur, body) _CVAR(name, cur, , body, IDF_OVERRIDE)
352 #define _CVAR0(name, cur, body, persist) _CVAR(name, cur, { if(!_##name) _##name = cur; }, body, persist)
353 #define CVAR0P(name, cur) _CVAR0(name, cur, , IDF_PERSIST)
354 #define CVAR0R(name, cur) _CVAR0(name, cur, , IDF_OVERRIDE)
355 #define CVAR0FP(name, cur, body) _CVAR0(name, cur, body, IDF_PERSIST)
356 #define CVAR0FR(name, cur, body) _CVAR0(name, cur, body, IDF_OVERRIDE)
357 #define _CVAR1(name, cur, body, persist) _CVAR(name, cur, { if(_##name <= 255) _##name |= (_##name<<8) | (_##name<<16); }, body, persist)
358 #define CVAR1P(name, cur) _CVAR1(name, cur, , IDF_PERSIST)
359 #define CVAR1R(name, cur) _CVAR1(name, cur, , IDF_OVERRIDE)
360 #define CVAR1FP(name, cur, body) _CVAR1(name, cur, body, IDF_PERSIST)
361 #define CVAR1FR(name, cur, body) _CVAR1(name, cur, body, IDF_OVERRIDE)
362 
363 #define _FVAR(name, global, min, cur, max, persist) float global = fvariable(#name, min, cur, max, &global, NULL, persist)
364 #define FVARN(name, global, min, cur, max) _FVAR(name, global, min, cur, max, 0)
365 #define FVARNP(name, global, min, cur, max) _FVAR(name, global, min, cur, max, IDF_PERSIST)
366 #define FVARNR(name, global, min, cur, max) _FVAR(name, global, min, cur, max, IDF_OVERRIDE)
367 #define FVAR(name, min, cur, max) _FVAR(name, name, min, cur, max, 0)
368 #define FVARP(name, min, cur, max) _FVAR(name, name, min, cur, max, IDF_PERSIST)
369 #define FVARR(name, min, cur, max) _FVAR(name, name, min, cur, max, IDF_OVERRIDE)
370 #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; }
371 #define FVARFN(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, 0)
372 #define FVARF(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, 0)
373 #define FVARFP(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, IDF_PERSIST)
374 #define FVARFR(name, min, cur, max, body) _FVARF(name, name, min, cur, max, body, IDF_OVERRIDE)
375 #define FVARFNP(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, IDF_PERSIST)
376 #define FVARFNR(name, global, min, cur, max, body) _FVARF(name, global, min, cur, max, body, IDF_OVERRIDE)
377 
378 #define _SVAR(name, global, cur, persist) char *global = svariable(#name, cur, &global, NULL, persist)
379 #define SVARN(name, global, cur) _SVAR(name, global, cur, 0)
380 #define SVARNP(name, global, cur) _SVAR(name, global, cur, IDF_PERSIST)
381 #define SVARNR(name, global, cur) _SVAR(name, global, cur, IDF_OVERRIDE)
382 #define SVAR(name, cur) _SVAR(name, name, cur, 0)
383 #define SVARP(name, cur) _SVAR(name, name, cur, IDF_PERSIST)
384 #define SVARR(name, cur) _SVAR(name, name, cur, IDF_OVERRIDE)
385 #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; }
386 #define SVARFN(name, global, cur, body) _SVARF(name, global, cur, body, 0)
387 #define SVARF(name, cur, body) _SVARF(name, name, cur, body, 0)
388 #define SVARFP(name, cur, body) _SVARF(name, name, cur, body, IDF_PERSIST)
389 #define SVARFR(name, cur, body) _SVARF(name, name, cur, body, IDF_OVERRIDE)
390 #define SVARFNP(name, global, cur, body) _SVARF(name, global, cur, body, IDF_PERSIST)
391 #define SVARFNR(name, global, cur, body) _SVARF(name, global, cur, body, IDF_OVERRIDE)
392 
393 // anonymous inline commands, uses nasty template trick with line numbers to keep names unique
394 #define ICOMMANDNAME(name) _icmd_##name
395 #define ICOMMANDSNAME _icmds_
396 #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 \
397     { b; }
398 #define ICOMMANDKN(name, type, cmdname, nargs, proto, b) ICOMMANDKNS(#name, type, cmdname, nargs, proto, b)
399 #define ICOMMANDK(name, type, nargs, proto, b) ICOMMANDKN(name, type, ICOMMANDNAME(name), nargs, proto, b)
400 #define ICOMMANDKS(name, type, nargs, proto, b) ICOMMANDKNS(name, type, ICOMMANDSNAME, nargs, proto, b)
401 #define ICOMMANDNS(name, cmdname, nargs, proto, b) ICOMMANDKNS(name, ID_COMMAND, cmdname, nargs, proto, b)
402 #define ICOMMANDN(name, cmdname, nargs, proto, b) ICOMMANDNS(#name, cmdname, nargs, proto, b)
403 #define ICOMMAND(name, nargs, proto, b) ICOMMANDN(name, ICOMMANDNAME(name), nargs, proto, b)
404 #define ICOMMANDS(name, nargs, proto, b) ICOMMANDNS(name, ICOMMANDSNAME, nargs, proto, b)
405 
406