-
Notifications
You must be signed in to change notification settings - Fork 5
/
command.h
693 lines (620 loc) · 23.8 KB
/
command.h
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
/**
* @file command.h
* @brief Script binding functionality.
*
* This file describes the CubeScript API for binding and executing code from within
* the engine's CubeScript context.
*/
#ifndef COMMAND_H_
#define COMMAND_H_
enum
{
Value_Null = 0,
Value_Integer,
Value_Float,
Value_String,
Value_Any,
Value_Code,
Value_Macro,
Value_Ident,
Value_CString,
Value_CAny,
Value_Word,
Value_Pop,
Value_Cond,
};
enum
{
Id_Var, //0
Id_FloatVar,
Id_StringVar,
Id_Command,
Id_Alias,
Id_Local, //5
Id_Do,
Id_DoArgs,
Id_If,
Id_Result,
Id_Not, //10
Id_And,
Id_Or, //12
};
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, ValueInteger
float f; // Id_FloatVar, ValueFloat
char *s; // Id_StringVar, ValueString
const uint *code; // ValueCode
ident *id; // ValueIdent
const char *cstr; // ValueCString
};
};
struct tagval : identval
{
int type;
void setint(int val);
void setfloat(float val);
void setnumber(double val);
void setstr(char *val);
void setnull();
void setcode(const uint *val);
void setmacro(const uint *val);
void setcstr(const char *val);
void setident(ident *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;
};
typedef void (__cdecl *identfun)(ident *id);
/**
* @brief An object representing all Cubescript objects.
*
* This object defines all possible state for any object in Cubescript. Different
* types will have different members due to the union types, but the ident object
* is common to them regardless. This allows storage of CS objects in a uniform
* map consisting of one type.
*/
struct ident
{
//this pointer will point to different types depending upon the type of variable
union identvalptr /**< points to an ident's value */
{
void *p; /**< can point to any Id_*Var */
int *i; /**< points to an Id_Var (int) */
float *f; /**< points to an Id_FloatVar */
char **s; /**< points to a pointer to a Id_StringVar (C string) */
};
uchar type; /**< one of Id_* in Id_ enum */
union
{
uchar valtype; /**< if alias, points to Id_Alias's type */
uchar numargs; /**< if command, number of commands the Id_Command has */
};
ushort flags;
int index;
const char *name;
union
{
struct // Id_Var, Id_FloatVar, Id_StringVar
{
union //number var range union type
{
struct
{
int minval, /**< if an int variable, its min allowed value*/
maxval; /**< if an int variable, its max allowed value*/
}; // Id_Var
struct
{
float minvalf, /**< if a float variable, its min allowed value*/
maxvalf; /**< if a float variable, its max allowed value*/
}; // Id_FloatVar
};
identvalptr storage;
identval overrideval;
};
struct // Id_Alias
{
uint *code;
identval val;
identstack *stack;
};
struct // Id_Command
{
const char *args;
uint argmask;
};
};
identfun fun; /**< the pointer a command or variable points to (the on-change command for a var)*/
ident() {}
/**
* @brief Constructor for an ident for an int variable.
*/
ident(int t, const char *n, int m, int x, int *s, void *f = nullptr, int flags = 0)
: type(t), flags(flags | (m > x ? Idf_ReadOnly : 0)), name(n), minval(m), maxval(x), fun((identfun)f)
{ storage.i = s; }
/**
* @brief Constructor for an ident for a float variable.
*/
ident(int t, const char *n, float m, float x, float *s, void *f = nullptr, int flags = 0)
: type(t), flags(flags | (m > x ? Idf_ReadOnly : 0)), name(n), minvalf(m), maxvalf(x), fun((identfun)f)
{ storage.f = s; }
/**
* @brief Constructor for an ident for a string variable.
*/
ident(int t, const char *n, char **s, void *f = nullptr, 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(Value_String), flags(flags), name(n), code(nullptr), stack(nullptr)
{ val.s = a; }
ident(int t, const char *n, int a, int flags)
: type(t), valtype(Value_Integer), flags(flags), name(n), code(nullptr), stack(nullptr)
{ val.i = a; }
ident(int t, const char *n, float a, int flags)
: type(t), valtype(Value_Float), flags(flags), name(n), code(nullptr), stack(nullptr)
{ val.f = a; }
ident(int t, const char *n, int flags)
: type(t), valtype(Value_Null), flags(flags), name(n), code(nullptr), stack(nullptr)
{}
ident(int t, const char *n, const tagval &v, int flags)
: type(t), valtype(v.type), flags(flags), name(n), code(nullptr), stack(nullptr)
{ val = v; }
/**
* @brief Constructor for an ident for a C++ bound command.
*/
ident(int t, const char *n, const char *args, uint argmask, int numargs, void *f = nullptr, int flags = 0)
: type(t), numargs(numargs), flags(flags), name(n), args(args), argmask(argmask), fun((identfun)f)
{}
/**
* @brief Calls a change effect for this ident, if one exists.
*
* If there is no function pointed to by `fun` (it is null), then nothing
* will occur.
*/
void changed()
{
if(fun)
{
fun(this);
}
}
/**
* @brief Sets the value and type of value of this ident given a tagval
*
* Sets this ident's value type and value to the corresponding values from
* the passed tagval object.
*
* @param v the tagval to set values from
*/
void setval(const tagval &v)
{
valtype = v.type;
val = v;
}
/**
* @brief Sets the value and type of value of this ident given an identstack
*
* Sets this ident's value type and value to the corresponding values from
* the passed identstack object.
*
* @param v the identstack to set values from
*/
void setval(const identstack &v)
{
valtype = v.valtype;
val = v.val;
}
/**
* @brief Sets the value type of this ident to null.
*
* If a string is being stored inside this ident, it is freed.
*/
void forcenull()
{
if(valtype==Value_String)
{
delete[] val.s;
}
valtype = Value_Null;
}
/**
* @brief Returns the saved value of the ident as a float.
*
* Returns a float even if the ident is of another type, e.g. integer
*
* @return the float value of the ident
*/
float getfloat() const;
/**
* @brief Returns the saved value of the ident as an integer.
*
* Returns an int even if the ident is of another type, e.g. float
*/
int getint() const;
/**
* @brief Returns the saved value of the ident as a double.
*
* Returns a double even if the ident is of another type, e.g. integer
*
* @return the double value of the ident
*/
double getnumber() const;
const char *getstr() const;
void getval(tagval &r) const;
void getcstr(tagval &v) const;
void getcval(tagval &v) const;
};
/**
* @brief Returns an integer value from a Cubescript command.
*
* When writing a CS command, this function returns an integer value to the inheriting
* CS environment.
*
* @param v the value to return
*/
extern void intret(int v);
extern const char *floatstr(float v);
/**
* @brief Returns a float value from a Cubescript command.
*
* When writing a CS command, this function returns a float value to the inheriting
* CS environment.
*
* @param v the value to return
*/
extern void floatret(float v);
/**
* @brief Returns a string value from a Cubescript command.
*
* When writing a CS command, this function returns a string value to the inheriting
* CS environment.
*
* @param v the value to return
*/
extern void stringret(char *s);
/**
* @brief Returns an alias' name from a Cubescript command.
*
* When writing a CS command, this functions a string value representing the name
* of a Cubescript object to the inheriting CS environment.
*
* @param s the name of the ident to return
*/
extern void result(const char *s);
/**
* @brief Returns the string passed as an integer.
*
* Parses the entire string, returning the value of the passed value as an integer.
* The value of this value will always be greater than zero unless there is an
* overflow beyond the size of `int`. The output may be converted by a trailing
* radix digit as described in `strtoul`.
*
* @param s the string to turn into an integer
*/
inline int parseint(const char *s)
{
return static_cast<int>(std::strtoul(s, nullptr, 0));
}
/**
* @brief Registers an int variable in the Cubescript ident table.
*
* @param name the name of the aliased variable in Cubescript
* @param min the minimum value the variable can be set at
* @param cur the starting value of the variable
* @param max the maximum value the variable can be set at
* @param storage the pointer to the variable to be aliased to Cubescript
* @param fun a function pointer to be called upon modification of the variable
* @param flags the handling flags for the variable
*
* @return the value cur passed
*/
extern int variable(const char *name, int min, int cur, int max, int *storage, identfun fun, int flags);
/**
* @brief Registers a float variable in the Cubescript ident table.
*
* Adds a float variable to the Cubescript ident table. The name of the Cubescript
* variable does not necessarily need to correspond to the C++ variable's name.
*
* @param name the name of the aliased variable in Cubescript
* @param min the minimum value the variable can be set at
* @param cur the starting value of the variable
* @param max the maximum value the variable can be set at
* @param storage the pointer to the variable to be aliased to Cubescript
* @param fun a function pointer to be called upon modification of the variable
* @param flags the handling flags for the variable
*
* @return the value cur passed
*/
extern float fvariable(const char *name, float min, float cur, float max, float *storage, identfun fun, int flags);
/**
* @brief Registers a C string variable in the Cubescript ident table.
*
* @param name the name of the aliased variable in Cubescript
* @param cur the starting value of the variable
* @param storage the pointer to the pointer to the variable to be aliased to Cubescript
* @param fun a function pointer to be called upon modification of the variable
* @param flags the handling flags for the variable
*
* @return the value cur passed
*/
extern char *svariable(const char *name, const char *cur, char **storage, identfun fun, int flags);
/**
* @brief Sets a Cubescript integer value to the given value.
*
* @param name the name of the cubescript alias to change
* @param i the value to set
* @param dofunc whether to run the onchange function
* @param doclamp whether to clamp the value to the specified limits
*/
extern void setvar(const char *name, int i, bool dofunc = true, bool doclamp = true);
/**
* @brief Sets a Cubescript float value to the given value.
*
* @param name the name of the cubescript alias to change
* @param i the value to set
* @param dofunc whether to run the onchange function
* @param doclamp whether to clamp the value to the specified limits
*/
extern void setfvar(const char *name, float f, bool dofunc = true, bool doclamp = true);
/**
* @brief Sets a Cubescript string value to the given value.
*
* @param name the name of the cubescript alias to change
* @param i the value to set
* @param dofunc whether to run the onchange function
*/
extern void setsvar(const char *name, const char *str, bool dofunc = true);
/**
* @brief Registers a command in the Cubescript ident table.
*
* The arguments of the function passed are cast away, so they are reconstructed using
* the char * string passed to `narg`.
*
* @param name of the command in Cubescript
* @param fun a function pointer to be called when the command is executed
* @param narg string containing the arguments of the function
* @param type the type of the command to create
*/
extern bool addcommand(const char *name, identfun fun, const char *narg = "", int type = Id_Command);
extern std::queue<ident *> triggerqueue; /**< A queue of game events for the engine to process */
/**
* @brief Returns the pointer to the ident object with the given CS alias.
*
* @param the name of the cubescript object to get
*
* @return The address of the ident object.
*/
extern ident *getident(const char *name);
extern int execute(const uint *code);
/**
* @brief Executes the contents of the string passed.
*
* Parses and executes the line of Cubescript given.
*
* @param p the C string containing the code to execute
*
* @return an int from the results of the execution
*/
extern int execute(const char *p);
/**
* @brief Executes the contents of an ident, searched by name.
*
* Attempts to find in the ident table an ident with the given name, and
* if found executes it.
*
* @param name the name of the ident to look for
* @param noid the value to return if no ident is found
* @param lookup if a command, and parameters are of format 'N', sets to -1
*/
extern int execident(const char *name, int noid = 0, bool lookup = false);
extern bool executebool(const uint *code);
/**
* @brief Executes the contents of the referenced file.
*
* @param cfgfile the relative director of the file to execute
* @param msg whether to print to console a failure message
*
* @return true if the file was successfully loaded
* @return false if the file was not found
*/
extern bool execfile(const char *cfgfile, bool msg = true);
/**
* @brief Replaces C style excape characters with Cubescript ones
*
* The resulting string is also wrapped in quotes ("").
*
* @param s the string to convert
*
* @return a string containing the escaped changes
*/
extern const char *escapestring(const char *s);
/**
* @brief Prints out the formatted variable
*
* The param is intended to represent the value the ident object represents.
*
* @param id the ident object to print out
* @param i the value to print out the variable equalling.
*/
extern void printvar(const ident *id, int i);
/**
* @brief Modifies the value passed to fall within the boundaries passed.
*
* Clamps the value i to within minval and maxval. If hex is passed, warns in hex
* mode, otherwise decimal. If the values are not within bounds, issued aformentioned
* warning, refering to the passed name in the console message.
*
* @param hex toggles whether to display hex warning instead of decimal
* @param name the name
* @param i the value to clamp
* @param minval the lowest value to clamp to
* @param maxval the largest value to clamp to
*
* @return the clamped value
*/
extern int clampvar(bool hex, std::string name, int i, int minval, int maxval);
extern void loopiter(ident *id, identstack &stack, int i);
extern void loopend(ident *id, identstack &stack);
/**
* @brief Escapes a string unless it is null.
*
* If an empty string is passed, escapestring() is not called. Otherwise, the same
* behavior as in escapestring() is executed.
*
* @param s the string to convert
*
* @return a string containing the potentially applied escape changes
*/
const char *escapeid(const char *s);
/**
* @brief Writes out the state of the CubeScript idents to a file.
*
* @param savedconfig the path to write to if name is nullptr
* @param autoexec the path for the autoexec file for user modification, for display in top of file comment
* @param defaultconfig the path for the master copy of the configuration file, for display in top of file comment
* @param name the path to write to, if nullptr savedconfig is used instead
*/
extern void writecfg(const char *savedconfig, const char *autoexec = nullptr, const char *defaultconfig = nullptr, const char *name = nullptr);
/**
* @brief Processes the cubescript sleep queue.
*
* At most, one sleep command is removed from the queue per cycle. Removes
* queued sleep commands as they expire, which stops CS commands from executing
* for a certain period of time.
*
* @param millis the current timestamp
*/
extern void checksleep(int millis);
/**
* @brief Initializes the CubeScript preset argument idents.
*
* Intitializes the argument parameters (arg1, arg2, ..., arg<Max_Args>) as CS
* ident objects. Required to use of $argN variables.
* Also initializes the dummy ident, `//dummy`.
*
* @return always returns true
*/
extern bool initidents();
extern int identflags; /**< The flags to automatically set on ident objects */
/**
* @brief Clears all aliases from the ident map.
*
* All aliases, aka objects created from within CubeScript, have their contents
* (the names and code values associated with them) freed. Does not remove the
* ident object itself from the global ident map.
*/
extern void clear_command();
// nasty macros for registering script functions, abuses globals to avoid excessive infrastructure
//* note: many of the VARF comments are very repetitive, because the code itself is nearly duplicated too *//
/* how command registration works:
* In C++, all global variables must be initiated before main() is called
* Each of these macro kludges (which are placed at the global scope level) initializes some kind of global variable
* Because the macro kludges are the definition of global variables, at program initializiation, they must be run first
* The values of the variables themselves don't matter because they only exist to cheat and run before main()
* The macro kludges themselves register commands or values within some vector<>-s which keeps track of all cmds/vars
*/
/*
* Parameter Flags (exhaustive list, not exhaustive descriptions)
* i an integer parameter
* b a boolean parameter
* f a float parameter (sets to 0 if over parameter limit)
* F a float parameter (sets to value of previous parameter if over parameter limit)
* s a string parameter (sets to new allocated string "" if over parameter limit)
* S a string paremter (sets current string to "" if over parameter limit)
* t sets to null if over parameter limit
* T same as "t"
* e a code block parameter
* E a code block paremter (null)
* r an ident parameter
* $ an ident parameter
* N a number parameter
* D a bind parameter (e.g. player movement), adds a release action for the command
* C an ident parameter, ComC
* V a series of variadic parameter(s) (open ended series of values)
* 1 repeat one arg
* 2 repeat two args
* 3 repeat three args
* 4 repeat four args
*/
//integer var macros
//VAR_, _VARF, VARM_ are templates for "normal" macros that do not execute an inline function
#define VAR_(name, global, min, cur, max, persist) int global = variable(#name, min, cur, max, &global, nullptr, 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)
//variable with inline function to be executed on change (VARiable with Function = VARF)
#define VARF_(name, global, min, cur, max, body, persist) \
int global = variable(#name, min, cur, max, &global, [] (ident *) { body; }, persist); /* assign variable, needs fxn prototype declared above */
#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)
//hexadecimal var macros
#define HVAR_(name, global, min, cur, max, persist) int global = variable(#name, min, cur, max, &global, nullptr, persist | Idf_Hex)
#define HVARP(name, min, cur, max) HVAR_(name, name, min, cur, max, Idf_Persist)
//hex variable with function to be executed on change (Hexadecimal VARiable with Function = HVARF)
//the CVAR series of macros borrows the HVARF macro as it deals with hex colors
#define HVARF_(name, global, min, cur, max, body, persist) \
int global = variable(#name, min, cur, max, &global, [] (ident *) { body; }, persist | Idf_Hex); /* assign variable, needs fxn prototype declared above */
//color var macros
#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 CVAR0_(name, cur, body, persist) CVAR_(name, cur, { if(!_##name) _##name = cur; }, body, persist)
#define CVAR0R(name, cur) CVAR0_(name, cur, , Idf_Override)
#define CVAR1_(name, cur, body, persist) CVAR_(name, cur, { if(_##name <= 255) _##name |= (_##name<<8) | (_##name<<16); }, body, persist)
#define CVAR1R(name, cur) CVAR1_(name, cur, , Idf_Override)
#define CVAR1FR(name, cur, body) CVAR1_(name, cur, body, Idf_Override)
//float var macros
#define FVAR_(name, global, min, cur, max, persist) float global = fvariable(#name, min, cur, max, &global, nullptr, persist)
#define FVARNP(name, global, min, cur, max) FVAR_(name, global, min, cur, max, Idf_Persist)
#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)
//float variable with function to be executed on change (Float VARiable with Function = FVARF)
#define FVARF_(name, global, min, cur, max, body, persist) \
float global = fvariable(#name, min, cur, max, &global, [] (ident *) { body; }, persist); /* assign variable, needs fxn prototype declared above */ \
#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)
//string var macros
#define SVAR_(name, global, cur, persist) char *global = svariable(#name, cur, &global, nullptr, persist)
#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)
//string variable with function to be executed on change (Float VARiable with Function = FVARF)
#define SVARF_(name, global, cur, body, persist) \
char *global = svariable(#name, cur, &global, [] (ident *) { body; }, persist); /* assign variable, needs fxn prototype declared above */
#define SVARF(name, cur, body) SVARF_(name, name, cur, body, 0)
#define SVARFR(name, cur, body) SVARF_(name, name, cur, body, Idf_Override)
#endif /* COMMAND_H_ */