summaryrefslogtreecommitdiff
path: root/src/engine/command.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/command.cpp')
-rw-r--r--src/engine/command.cpp5030
1 files changed, 2515 insertions, 2515 deletions
diff --git a/src/engine/command.cpp b/src/engine/command.cpp
index 0029e4d..012b8c1 100644
--- a/src/engine/command.cpp
+++ b/src/engine/command.cpp
@@ -11,186 +11,186 @@ int identflags = 0;
enum
{
- MAXARGS = 25,
- MAXCOMARGS = 12
+ MAXARGS = 25,
+ MAXCOMARGS = 12
};
VARN(numargs, _numargs, MAXARGS, 0, 0);
static inline void freearg(tagval &v)
{
- switch(v.type)
- {
- case VAL_STR: delete[] v.s; break;
- case VAL_CODE: if(v.code[-1] == CODE_START) delete[] (uchar *)&v.code[-1]; break;
- }
+ switch(v.type)
+ {
+ case VAL_STR: delete[] v.s; break;
+ case VAL_CODE: if(v.code[-1] == CODE_START) delete[] (uchar *)&v.code[-1]; break;
+ }
}
static inline void forcenull(tagval &v)
{
- switch(v.type)
- {
- case VAL_NULL: return;
- }
- freearg(v);
- v.setnull();
+ switch(v.type)
+ {
+ case VAL_NULL: return;
+ }
+ freearg(v);
+ v.setnull();
}
static inline float forcefloat(tagval &v)
{
- float f = 0.0f;
- switch(v.type)
- {
- case VAL_INT: f = v.i; break;
- case VAL_STR: f = parsefloat(v.s); break;
- case VAL_MACRO: f = parsefloat(v.s); break;
- case VAL_FLOAT: return v.f;
- }
- freearg(v);
- v.setfloat(f);
- return f;
+ float f = 0.0f;
+ switch(v.type)
+ {
+ case VAL_INT: f = v.i; break;
+ case VAL_STR: f = parsefloat(v.s); break;
+ case VAL_MACRO: f = parsefloat(v.s); break;
+ case VAL_FLOAT: return v.f;
+ }
+ freearg(v);
+ v.setfloat(f);
+ return f;
}
static inline int forceint(tagval &v)
{
- int i = 0;
- switch(v.type)
- {
- case VAL_FLOAT: i = v.f; break;
- case VAL_STR: i = parseint(v.s); break;
- case VAL_MACRO: i = parseint(v.s); break;
- case VAL_INT: return v.i;
- }
- freearg(v);
- v.setint(i);
- return i;
+ int i = 0;
+ switch(v.type)
+ {
+ case VAL_FLOAT: i = v.f; break;
+ case VAL_STR: i = parseint(v.s); break;
+ case VAL_MACRO: i = parseint(v.s); break;
+ case VAL_INT: return v.i;
+ }
+ freearg(v);
+ v.setint(i);
+ return i;
}
static inline const char *forcestr(tagval &v)
{
- const char *s = "";
- switch(v.type)
- {
- case VAL_FLOAT: s = floatstr(v.f); break;
- case VAL_INT: s = intstr(v.i); break;
- case VAL_STR:
- [[fallthrough]];
- case VAL_MACRO: return v.s;
- }
- freearg(v);
- v.setstr(newstring(s));
- return s;
+ const char *s = "";
+ switch(v.type)
+ {
+ case VAL_FLOAT: s = floatstr(v.f); break;
+ case VAL_INT: s = intstr(v.i); break;
+ case VAL_STR:
+ [[fallthrough]];
+ case VAL_MACRO: return v.s;
+ }
+ freearg(v);
+ v.setstr(newstring(s));
+ return s;
}
static inline void forcearg(tagval &v, int type)
{
- switch(type)
- {
- case RET_STR: if(v.type != VAL_STR) forcestr(v); break;
- case RET_INT: if(v.type != VAL_INT) forceint(v); break;
- case RET_FLOAT: if(v.type != VAL_FLOAT) forcefloat(v); break;
- }
+ switch(type)
+ {
+ case RET_STR: if(v.type != VAL_STR) forcestr(v); break;
+ case RET_INT: if(v.type != VAL_INT) forceint(v); break;
+ case RET_FLOAT: if(v.type != VAL_FLOAT) forcefloat(v); break;
+ }
}
static inline ident *forceident(tagval &v)
{
- switch(v.type)
- {
- case VAL_IDENT: return v.id;
- case VAL_MACRO:
- {
- ident *id = newident(v.s, IDF_UNKNOWN);
- v.setident(id);
- return id;
- }
- case VAL_STR:
- {
- ident *id = newident(v.s, IDF_UNKNOWN);
- delete[] v.s;
- v.setident(id);
- return id;
- }
- }
- freearg(v);
- v.setident(dummyident);
- return dummyident;
+ switch(v.type)
+ {
+ case VAL_IDENT: return v.id;
+ case VAL_MACRO:
+ {
+ ident *id = newident(v.s, IDF_UNKNOWN);
+ v.setident(id);
+ return id;
+ }
+ case VAL_STR:
+ {
+ ident *id = newident(v.s, IDF_UNKNOWN);
+ delete[] v.s;
+ v.setident(id);
+ return id;
+ }
+ }
+ freearg(v);
+ v.setident(dummyident);
+ return dummyident;
}
void tagval::cleanup()
{
- freearg(*this);
+ freearg(*this);
}
static inline void freeargs(tagval *args, int &oldnum, int newnum)
{
- for(int i = newnum; i < oldnum; i++) freearg(args[i]);
- oldnum = newnum;
+ for(int i = newnum; i < oldnum; i++) freearg(args[i]);
+ oldnum = newnum;
}
static inline void cleancode(ident &id)
{
- if(id.code)
- {
- id.code[0] -= 0x100;
- if(int(id.code[0]) < 0x100) delete[] id.code;
- id.code = NULL;
- }
+ if(id.code)
+ {
+ id.code[0] -= 0x100;
+ if(int(id.code[0]) < 0x100) delete[] id.code;
+ id.code = NULL;
+ }
}
struct nullval : tagval
{
- nullval() { setnull(); }
+ nullval() { setnull(); }
} nullval;
tagval noret = nullval, *commandret = &noret;
void clear_command()
{
- enumerate(idents, ident, i,
- {
- if(i.type==ID_ALIAS)
- {
- DELETEA(i.name);
- i.forcenull();
- DELETEA(i.code);
- }
- });
+ enumerate(idents, ident, i,
+ {
+ if(i.type==ID_ALIAS)
+ {
+ DELETEA(i.name);
+ i.forcenull();
+ DELETEA(i.code);
+ }
+ });
}
void clearoverride(ident &i)
{
- if(!(i.flags&IDF_OVERRIDDEN)) return;
- switch(i.type)
- {
- case ID_ALIAS:
- if(i.valtype==VAL_STR)
- {
- if(!i.val.s[0]) break;
- delete[] i.val.s;
- }
- cleancode(i);
- i.valtype = VAL_STR;
- i.val.s = newstring("");
- break;
- case ID_VAR:
- *i.storage.i = i.overrideval.i;
- i.changed();
- break;
- case ID_FVAR:
- *i.storage.f = i.overrideval.f;
- i.changed();
- break;
- case ID_SVAR:
- delete[] *i.storage.s;
- *i.storage.s = i.overrideval.s;
- i.changed();
- break;
- }
- i.flags &= ~IDF_OVERRIDDEN;
+ if(!(i.flags&IDF_OVERRIDDEN)) return;
+ switch(i.type)
+ {
+ case ID_ALIAS:
+ if(i.valtype==VAL_STR)
+ {
+ if(!i.val.s[0]) break;
+ delete[] i.val.s;
+ }
+ cleancode(i);
+ i.valtype = VAL_STR;
+ i.val.s = newstring("");
+ break;
+ case ID_VAR:
+ *i.storage.i = i.overrideval.i;
+ i.changed();
+ break;
+ case ID_FVAR:
+ *i.storage.f = i.overrideval.f;
+ i.changed();
+ break;
+ case ID_SVAR:
+ delete[] *i.storage.s;
+ *i.storage.s = i.overrideval.s;
+ i.changed();
+ break;
+ }
+ i.flags &= ~IDF_OVERRIDDEN;
}
void clearoverrides()
{
- enumerate(idents, ident, i, clearoverride(i));
+ enumerate(idents, ident, i, clearoverride(i));
}
static bool initedidents = false;
@@ -198,32 +198,32 @@ static vector<ident> *identinits = NULL;
static inline ident *addident(const ident &id)
{
- if(!initedidents)
- {
- if(!identinits) identinits = new vector<ident>;
- identinits->add(id);
- return NULL;
- }
- ident &def = idents.access(id.name, id);
- def.index = identmap.length();
- return identmap.add(&def);
+ if(!initedidents)
+ {
+ if(!identinits) identinits = new vector<ident>;
+ identinits->add(id);
+ return NULL;
+ }
+ ident &def = idents.access(id.name, id);
+ def.index = identmap.length();
+ return identmap.add(&def);
}
static bool initidents()
{
- initedidents = true;
- for(int i = 0; i < MAXARGS; i++)
- {
- defformatstring(argname, "arg%d", i+1);
- newident(argname, IDF_ARG);
- }
- dummyident = newident("//dummy", IDF_UNKNOWN);
- if(identinits)
- {
- loopv(*identinits) addident((*identinits)[i]);
- DELETEP(identinits);
- }
- return true;
+ initedidents = true;
+ for(int i = 0; i < MAXARGS; i++)
+ {
+ defformatstring(argname, "arg%d", i+1);
+ newident(argname, IDF_ARG);
+ }
+ dummyident = newident("//dummy", IDF_UNKNOWN);
+ if(identinits)
+ {
+ loopv(*identinits) addident((*identinits)[i]);
+ DELETEP(identinits);
+ }
+ return true;
}
UNUSED static bool forceinitidents = initidents();
@@ -231,49 +231,49 @@ static const char *sourcefile = NULL, *sourcestr = NULL;
static const char *debugline(const char *p, const char *fmt)
{
- if(!sourcestr) return fmt;
- int num = 1;
- const char *line = sourcestr;
- for(;;)
- {
- const char *end = strchr(line, '\n');
- if(!end) end = line + strlen(line);
- if(p >= line && p <= end)
- {
- static string buf;
- if(sourcefile) formatstring(buf, "%s:%d: %s", sourcefile, num, fmt);
- else formatstring(buf, "%d: %s", num, fmt);
- return buf;
- }
- if(!*end) break;
- line = end + 1;
- num++;
- }
- return fmt;
+ if(!sourcestr) return fmt;
+ int num = 1;
+ const char *line = sourcestr;
+ for(;;)
+ {
+ const char *end = strchr(line, '\n');
+ if(!end) end = line + strlen(line);
+ if(p >= line && p <= end)
+ {
+ static string buf;
+ if(sourcefile) formatstring(buf, "%s:%d: %s", sourcefile, num, fmt);
+ else formatstring(buf, "%d: %s", num, fmt);
+ return buf;
+ }
+ if(!*end) break;
+ line = end + 1;
+ num++;
+ }
+ return fmt;
}
static struct identlink
{
- ident *id;
- identlink *next;
- int usedargs;
- identstack *argstack;
+ ident *id;
+ identlink *next;
+ int usedargs;
+ identstack *argstack;
} noalias = { NULL, NULL, (1<<MAXARGS)-1, NULL }, *aliasstack = &noalias;
VAR(dbgalias, 0, 4, 1000);
static void debugalias()
{
- if(!dbgalias) return;
- int total = 0, depth = 0;
- for(identlink *l = aliasstack; l != &noalias; l = l->next) total++;
- for(identlink *l = aliasstack; l != &noalias; l = l->next)
- {
- ident *id = l->id;
- ++depth;
- if(depth < dbgalias) conoutf(CON_ERROR, " %d) %s", total-depth+1, id->name);
- else if(l->next == &noalias) conoutf(CON_ERROR, depth == dbgalias ? " %d) %s" : " ..%d) %s", total-depth+1, id->name);
- }
+ if(!dbgalias) return;
+ int total = 0, depth = 0;
+ for(identlink *l = aliasstack; l != &noalias; l = l->next) total++;
+ for(identlink *l = aliasstack; l != &noalias; l = l->next)
+ {
+ ident *id = l->id;
+ ++depth;
+ if(depth < dbgalias) conoutf(CON_ERROR, " %d) %s", total-depth+1, id->name);
+ else if(l->next == &noalias) conoutf(CON_ERROR, depth == dbgalias ? " %d) %s" : " ..%d) %s", total-depth+1, id->name);
+ }
}
static int nodebug = 0;
@@ -282,294 +282,294 @@ static void debugcode(const char *fmt, ...) PRINTFARGS(1, 2);
static void debugcode(const char *fmt, ...)
{
- if(nodebug) return;
+ if(nodebug) return;
- va_list args;
- va_start(args, fmt);
- conoutfv(CON_ERROR, fmt, args);
- va_end(args);
+ va_list args;
+ va_start(args, fmt);
+ conoutfv(CON_ERROR, fmt, args);
+ va_end(args);
- debugalias();
+ debugalias();
}
static void debugcodeline(const char *p, const char *fmt, ...) PRINTFARGS(2, 3);
static void debugcodeline(const char *p, const char *fmt, ...)
{
- if(nodebug) return;
+ if(nodebug) return;
- va_list args;
- va_start(args, fmt);
- conoutfv(CON_ERROR, debugline(p, fmt), args);
- va_end(args);
+ va_list args;
+ va_start(args, fmt);
+ conoutfv(CON_ERROR, debugline(p, fmt), args);
+ va_end(args);
- debugalias();
+ debugalias();
}
ICOMMAND(nodebug, "e", (uint *body), { nodebug++; executeret(body, *commandret); nodebug--; });
void addident(ident *id)
{
- addident(*id);
+ addident(*id);
}
static inline void pusharg(ident &id, const tagval &v, identstack &stack)
{
- stack.val = id.val;
- stack.valtype = id.valtype;
- stack.next = id.stack;
- id.stack = &stack;
- id.setval(v);
- cleancode(id);
+ stack.val = id.val;
+ stack.valtype = id.valtype;
+ stack.next = id.stack;
+ id.stack = &stack;
+ id.setval(v);
+ cleancode(id);
}
static inline void poparg(ident &id)
{
- if(!id.stack) return;
- identstack *stack = id.stack;
- if(id.valtype == VAL_STR) delete[] id.val.s;
- id.setval(*stack);
- cleancode(id);
- id.stack = stack->next;
+ if(!id.stack) return;
+ identstack *stack = id.stack;
+ if(id.valtype == VAL_STR) delete[] id.val.s;
+ id.setval(*stack);
+ cleancode(id);
+ id.stack = stack->next;
}
ICOMMAND(push, "rte", (ident *id, tagval *v, uint *code),
{
- if(id->type != ID_ALIAS || id->index < MAXARGS) return;
- identstack stack;
- pusharg(*id, *v, stack);
- v->type = VAL_NULL;
- id->flags &= ~IDF_UNKNOWN;
- executeret(code, *commandret);
- poparg(*id);
+ if(id->type != ID_ALIAS || id->index < MAXARGS) return;
+ identstack stack;
+ pusharg(*id, *v, stack);
+ v->type = VAL_NULL;
+ id->flags &= ~IDF_UNKNOWN;
+ executeret(code, *commandret);
+ poparg(*id);
});
static inline void pushalias(ident &id, identstack &stack)
{
- if(id.type == ID_ALIAS && id.index >= MAXARGS)
- {
- pusharg(id, nullval, stack);
- id.flags &= ~IDF_UNKNOWN;
- }
+ if(id.type == ID_ALIAS && id.index >= MAXARGS)
+ {
+ pusharg(id, nullval, stack);
+ id.flags &= ~IDF_UNKNOWN;
+ }
}
static inline void popalias(ident &id)
{
- if(id.type == ID_ALIAS && id.index >= MAXARGS) poparg(id);
+ if(id.type == ID_ALIAS && id.index >= MAXARGS) poparg(id);
}
KEYWORD(local, ID_LOCAL);
static inline bool checknumber(const char *s)
{
- if(isdigit(s[0])) return true;
- else switch(s[0])
- {
- case '+': case '-': return isdigit(s[1]) || (s[1] == '.' && isdigit(s[2]));
- case '.': return isdigit(s[1]) != 0;
- default: return false;
- }
+ if(isdigit(s[0])) return true;
+ else switch(s[0])
+ {
+ case '+': case '-': return isdigit(s[1]) || (s[1] == '.' && isdigit(s[2]));
+ case '.': return isdigit(s[1]) != 0;
+ default: return false;
+ }
}
ident *newident(const char *name, int flags)
{
- ident *id = idents.access(name);
- if(!id)
- {
- if(checknumber(name))
- {
- debugcode("number %s is not a valid identifier name", name);
- return dummyident;
- }
- id = addident(ident(ID_ALIAS, newstring(name), flags));
- }
- return id;
+ ident *id = idents.access(name);
+ if(!id)
+ {
+ if(checknumber(name))
+ {
+ debugcode("number %s is not a valid identifier name", name);
+ return dummyident;
+ }
+ id = addident(ident(ID_ALIAS, newstring(name), flags));
+ }
+ return id;
}
ident *writeident(const char *name, int flags)
{
- ident *id = newident(name, flags);
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
- {
- pusharg(*id, nullval, aliasstack->argstack[id->index]);
- aliasstack->usedargs |= 1<<id->index;
- }
- return id;
+ ident *id = newident(name, flags);
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
+ {
+ pusharg(*id, nullval, aliasstack->argstack[id->index]);
+ aliasstack->usedargs |= 1<<id->index;
+ }
+ return id;
}
ident *readident(const char *name)
{
- ident *id = idents.access(name);
- if(id && id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
- return NULL;
- return id;
+ ident *id = idents.access(name);
+ if(id && id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
+ return NULL;
+ return id;
}
void resetvar(char *name)
{
- ident *id = idents.access(name);
- if(!id) return;
- if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
- else clearoverride(*id);
+ ident *id = idents.access(name);
+ if(!id) return;
+ if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
+ else clearoverride(*id);
}
COMMAND(resetvar, "s");
static inline void setarg(ident &id, tagval &v)
{
- if(aliasstack->usedargs&(1<<id.index))
- {
- if(id.valtype == VAL_STR) delete[] id.val.s;
- id.setval(v);
- cleancode(id);
- }
- else
- {
- pusharg(id, v, aliasstack->argstack[id.index]);
- aliasstack->usedargs |= 1<<id.index;
- }
+ if(aliasstack->usedargs&(1<<id.index))
+ {
+ if(id.valtype == VAL_STR) delete[] id.val.s;
+ id.setval(v);
+ cleancode(id);
+ }
+ else
+ {
+ pusharg(id, v, aliasstack->argstack[id.index]);
+ aliasstack->usedargs |= 1<<id.index;
+ }
}
static inline void setalias(ident &id, tagval &v)
{
- if(id.valtype == VAL_STR) delete[] id.val.s;
- id.setval(v);
- cleancode(id);
- id.flags = (id.flags & identflags) | identflags;
+ if(id.valtype == VAL_STR) delete[] id.val.s;
+ id.setval(v);
+ cleancode(id);
+ id.flags = (id.flags & identflags) | identflags;
}
static void setalias(const char *name, tagval &v)
{
- ident *id = idents.access(name);
- if(id)
- {
- if(id->type == ID_ALIAS)
- {
- if(id->index < MAXARGS) setarg(*id, v); else setalias(*id, v);
- }
- else
- {
- debugcode("cannot redefine builtin %s with an alias", id->name);
- freearg(v);
- }
- }
- else if(checknumber(name))
- {
- debugcode("cannot alias number %s", name);
- freearg(v);
- }
- else
- {
- addident(ident(ID_ALIAS, newstring(name), v, identflags));
- }
+ ident *id = idents.access(name);
+ if(id)
+ {
+ if(id->type == ID_ALIAS)
+ {
+ if(id->index < MAXARGS) setarg(*id, v); else setalias(*id, v);
+ }
+ else
+ {
+ debugcode("cannot redefine builtin %s with an alias", id->name);
+ freearg(v);
+ }
+ }
+ else if(checknumber(name))
+ {
+ debugcode("cannot alias number %s", name);
+ freearg(v);
+ }
+ else
+ {
+ addident(ident(ID_ALIAS, newstring(name), v, identflags));
+ }
}
void alias(const char *name, const char *str)
{
- tagval v;
- v.setstr(newstring(str));
- setalias(name, v);
+ tagval v;
+ v.setstr(newstring(str));
+ setalias(name, v);
}
void alias(const char *name, tagval &v)
{
- setalias(name, v);
+ setalias(name, v);
}
ICOMMAND(alias, "st", (const char *name, tagval *v),
{
- setalias(name, *v);
- v->type = VAL_NULL;
+ setalias(name, *v);
+ v->type = VAL_NULL;
});
// variable's and commands are registered through globals, see cube.h
int variable(const char *name, int min, int cur, int max, int *storage, identfun fun, int flags)
{
- addident(ident(ID_VAR, name, min, max, storage, (void *)fun, flags));
- return cur;
+ addident(ident(ID_VAR, name, min, max, storage, (void *)fun, flags));
+ return cur;
}
float fvariable(const char *name, float min, float cur, float max, float *storage, identfun fun, int flags)
{
- addident(ident(ID_FVAR, name, min, max, storage, (void *)fun, flags));
- return cur;
+ addident(ident(ID_FVAR, name, min, max, storage, (void *)fun, flags));
+ return cur;
}
char *svariable(const char *name, const char *cur, char **storage, identfun fun, int flags)
{
- addident(ident(ID_SVAR, name, storage, (void *)fun, flags));
- return newstring(cur);
+ addident(ident(ID_SVAR, name, storage, (void *)fun, flags));
+ return newstring(cur);
}
#define _GETVAR(id, vartype, name, retval) \
- ident *id = idents.access(name); \
- if(!id || id->type!=vartype) return retval;
+ ident *id = idents.access(name); \
+ if(!id || id->type!=vartype) return retval;
#define GETVAR(id, name, retval) _GETVAR(id, ID_VAR, name, retval)
#define OVERRIDEVAR(errorval, saveval, resetval, clearval) \
- if(identflags&IDF_OVERRIDDEN || id->flags&IDF_OVERRIDE) \
- { \
- if(id->flags&IDF_PERSIST) \
- { \
- debugcode("cannot override persistent variable %s", id->name); \
- errorval; \
- } \
- if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \
- else { clearval; } \
- } \
- else \
- { \
- if(id->flags&IDF_OVERRIDDEN) { resetval; id->flags &= ~IDF_OVERRIDDEN; } \
- clearval; \
- }
+ if(identflags&IDF_OVERRIDDEN || id->flags&IDF_OVERRIDE) \
+ { \
+ if(id->flags&IDF_PERSIST) \
+ { \
+ debugcode("cannot override persistent variable %s", id->name); \
+ errorval; \
+ } \
+ if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \
+ else { clearval; } \
+ } \
+ else \
+ { \
+ if(id->flags&IDF_OVERRIDDEN) { resetval; id->flags &= ~IDF_OVERRIDDEN; } \
+ clearval; \
+ }
void setvar(const char *name, int i, bool dofunc, bool doclamp)
{
- GETVAR(id, name, );
- OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
- if(doclamp) *id->storage.i = clamp(i, id->minval, id->maxval);
- else *id->storage.i = i;
- if(dofunc) id->changed();
+ GETVAR(id, name, );
+ OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
+ if(doclamp) *id->storage.i = clamp(i, id->minval, id->maxval);
+ else *id->storage.i = i;
+ if(dofunc) id->changed();
}
void setfvar(const char *name, float f, bool dofunc, bool doclamp)
{
- _GETVAR(id, ID_FVAR, name, );
- OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
- if(doclamp) *id->storage.f = clamp(f, id->minvalf, id->maxvalf);
- else *id->storage.f = f;
- if(dofunc) id->changed();
+ _GETVAR(id, ID_FVAR, name, );
+ OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
+ if(doclamp) *id->storage.f = clamp(f, id->minvalf, id->maxvalf);
+ else *id->storage.f = f;
+ if(dofunc) id->changed();
}
void setsvar(const char *name, const char *str, bool dofunc)
{
- _GETVAR(id, ID_SVAR, name, );
- OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] *id->storage.s);
- *id->storage.s = newstring(str);
- if(dofunc) id->changed();
+ _GETVAR(id, ID_SVAR, name, );
+ OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] *id->storage.s);
+ *id->storage.s = newstring(str);
+ if(dofunc) id->changed();
}
int getvar(const char *name)
{
- GETVAR(id, name, 0);
- return *id->storage.i;
+ GETVAR(id, name, 0);
+ return *id->storage.i;
}
int getvarmin(const char *name)
{
- GETVAR(id, name, 0);
- return id->minval;
+ GETVAR(id, name, 0);
+ return id->minval;
}
int getvarmax(const char *name)
{
- GETVAR(id, name, 0);
- return id->maxval;
+ GETVAR(id, name, 0);
+ return id->maxval;
}
float getfvarmin(const char *name)
{
- _GETVAR(id, ID_FVAR, name, 0);
- return id->minvalf;
+ _GETVAR(id, ID_FVAR, name, 0);
+ return id->minvalf;
}
float getfvarmax(const char *name)
{
- _GETVAR(id, ID_FVAR, name, 0);
- return id->maxvalf;
+ _GETVAR(id, ID_FVAR, name, 0);
+ return id->maxvalf;
}
ICOMMAND(getvarmin, "s", (char *s), intret(getvarmin(s)));
@@ -582,433 +582,433 @@ ident *getident(const char *name) { return idents.access(name); }
void touchvar(const char *name)
{
- ident *id = idents.access(name);
- if(id) switch(id->type)
- {
- case ID_VAR:
- case ID_FVAR:
- case ID_SVAR:
- id->changed();
- break;
- }
+ ident *id = idents.access(name);
+ if(id) switch(id->type)
+ {
+ case ID_VAR:
+ case ID_FVAR:
+ case ID_SVAR:
+ id->changed();
+ break;
+ }
}
const char *getalias(const char *name)
{
- ident *i = idents.access(name);
- return i && i->type==ID_ALIAS && (i->index >= MAXARGS || aliasstack->usedargs&(1<<i->index)) ? i->getstr() : "";
+ ident *i = idents.access(name);
+ return i && i->type==ID_ALIAS && (i->index >= MAXARGS || aliasstack->usedargs&(1<<i->index)) ? i->getstr() : "";
}
ICOMMAND(getalias, "s", (char *s), result(getalias(s)));
int clampvar(ident *id, int val, int minval, int maxval)
{
- if(val < minval) val = minval;
- else if(val > maxval) val = maxval;
- else return val;
- debugcode(id->flags&IDF_HEX ?
- (minval <= 255 ? "valid range for %s is %d..0x%X" : "valid range for %s is 0x%X..0x%X") :
- "valid range for %s is %d..%d",
- id->name, minval, maxval);
- return val;
+ if(val < minval) val = minval;
+ else if(val > maxval) val = maxval;
+ else return val;
+ debugcode(id->flags&IDF_HEX ?
+ (minval <= 255 ? "valid range for %s is %d..0x%X" : "valid range for %s is 0x%X..0x%X") :
+ "valid range for %s is %d..%d",
+ id->name, minval, maxval);
+ return val;
}
void setvarchecked(ident *id, int val)
{
- if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
+ if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
#ifndef STANDALONE
- else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
+ else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
#else
- else
+ else
#endif
- {
- OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
- if(val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval);
- *id->storage.i = val;
- id->changed(); // call trigger function if available
+ {
+ OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
+ if(val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval);
+ *id->storage.i = val;
+ id->changed(); // call trigger function if available
#ifndef STANDALONE
- if(id->flags&IDF_OVERRIDE && !(identflags&IDF_OVERRIDDEN)) game::vartrigger(id);
+ if(id->flags&IDF_OVERRIDE && !(identflags&IDF_OVERRIDDEN)) game::vartrigger(id);
#endif
- }
+ }
}
static inline void setvarchecked(ident *id, tagval *args, int numargs)
{
- int val = forceint(args[0]);
- if(id->flags&IDF_HEX && numargs > 1)
- {
- val = (val << 16) | (forceint(args[1])<<8);
- if(numargs > 2) val |= forceint(args[2]);
- }
- setvarchecked(id, val);
+ int val = forceint(args[0]);
+ if(id->flags&IDF_HEX && numargs > 1)
+ {
+ val = (val << 16) | (forceint(args[1])<<8);
+ if(numargs > 2) val |= forceint(args[2]);
+ }
+ setvarchecked(id, val);
}
float clampfvar(ident *id, float val, float minval, float maxval)
{
- if(val < minval) val = minval;
- else if(val > maxval) val = maxval;
- else return val;
- debugcode("valid range for %s is %s..%s", id->name, floatstr(minval), floatstr(maxval));
- return val;
+ if(val < minval) val = minval;
+ else if(val > maxval) val = maxval;
+ else return val;
+ debugcode("valid range for %s is %s..%s", id->name, floatstr(minval), floatstr(maxval));
+ return val;
}
void setfvarchecked(ident *id, float val)
{
- if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
+ if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
#ifndef STANDALONE
- else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
+ else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
#else
- else
+ else
#endif
- {
- OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
- if(val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf);
- *id->storage.f = val;
- id->changed();
+ {
+ OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
+ if(val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf);
+ *id->storage.f = val;
+ id->changed();
#ifndef STANDALONE
- if(id->flags&IDF_OVERRIDE && !(identflags&IDF_OVERRIDDEN)) game::vartrigger(id);
+ if(id->flags&IDF_OVERRIDE && !(identflags&IDF_OVERRIDDEN)) game::vartrigger(id);
#endif
- }
+ }
}
void setsvarchecked(ident *id, const char *val)
{
- if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
+ if(id->flags&IDF_READONLY) debugcode("variable %s is read-only", id->name);
#ifndef STANDALONE
- else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
+ else if(!(id->flags&IDF_OVERRIDE) || identflags&IDF_OVERRIDDEN || game::allowedittoggle())
#else
- else
+ else
#endif
- {
- OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] *id->storage.s);
- *id->storage.s = newstring(val);
- id->changed();
+ {
+ OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] *id->storage.s);
+ *id->storage.s = newstring(val);
+ id->changed();
#ifndef STANDALONE
- if(id->flags&IDF_OVERRIDE && !(identflags&IDF_OVERRIDDEN)) game::vartrigger(id);
+ if(id->flags&IDF_OVERRIDE && !(identflags&IDF_OVERRIDDEN)) game::vartrigger(id);
#endif
- }
+ }
}
ICOMMAND(set, "rt", (ident *id, tagval *v),
{
- switch(id->type)
- {
- case ID_ALIAS:
- if(id->index < MAXARGS) setarg(*id, *v); else setalias(*id, *v);
- v->type = VAL_NULL;
- break;
- case ID_VAR:
- setvarchecked(id, forceint(*v));
- break;
- case ID_FVAR:
- setfvarchecked(id, forcefloat(*v));
- break;
- case ID_SVAR:
- setsvarchecked(id, forcestr(*v));
- break;
- case ID_COMMAND:
- if(id->flags&IDF_EMUVAR)
- {
- execute(id, v, 1);
- v->type = VAL_NULL;
- break;
- }
- // fall through
- default:
- debugcode("cannot redefine builtin %s with an alias", id->name);
- break;
- }
+ switch(id->type)
+ {
+ case ID_ALIAS:
+ if(id->index < MAXARGS) setarg(*id, *v); else setalias(*id, *v);
+ v->type = VAL_NULL;
+ break;
+ case ID_VAR:
+ setvarchecked(id, forceint(*v));
+ break;
+ case ID_FVAR:
+ setfvarchecked(id, forcefloat(*v));
+ break;
+ case ID_SVAR:
+ setsvarchecked(id, forcestr(*v));
+ break;
+ case ID_COMMAND:
+ if(id->flags&IDF_EMUVAR)
+ {
+ execute(id, v, 1);
+ v->type = VAL_NULL;
+ break;
+ }
+ // fall through
+ default:
+ debugcode("cannot redefine builtin %s with an alias", id->name);
+ break;
+ }
});
bool addcommand(const char *name, identfun fun, const char *args)
{
- uint argmask = 0;
- int numargs = 0, flags = 0;
- bool limit = true;
- for(const char *fmt = args; *fmt; fmt++) switch(*fmt)
- {
- case 'i': case 'b': case 'f': case 't': case 'N': case 'D': if(numargs < MAXARGS) numargs++; break;
- case '$': flags |= IDF_EMUVAR; // fall through
- case 's': case 'e': case 'r': if(numargs < MAXARGS) { argmask |= 1<<numargs; numargs++; } break;
- case '1': case '2': case '3': case '4': if(numargs < MAXARGS) fmt -= *fmt-'0'+1; break;
- case 'C': case 'V': limit = false; break;
- default: fatal("builtin %s declared with illegal type: %s", name, args); break;
- }
- if(limit && numargs > MAXCOMARGS) fatal("builtin %s declared with too many args: %d", name, numargs);
- addident(ident(ID_COMMAND, name, args, argmask, numargs, (void *)fun, flags));
- return false;
+ uint argmask = 0;
+ int numargs = 0, flags = 0;
+ bool limit = true;
+ for(const char *fmt = args; *fmt; fmt++) switch(*fmt)
+ {
+ case 'i': case 'b': case 'f': case 't': case 'N': case 'D': if(numargs < MAXARGS) numargs++; break;
+ case '$': flags |= IDF_EMUVAR; // fall through
+ case 's': case 'e': case 'r': if(numargs < MAXARGS) { argmask |= 1<<numargs; numargs++; } break;
+ case '1': case '2': case '3': case '4': if(numargs < MAXARGS) fmt -= *fmt-'0'+1; break;
+ case 'C': case 'V': limit = false; break;
+ default: fatal("builtin %s declared with illegal type: %s", name, args); break;
+ }
+ if(limit && numargs > MAXCOMARGS) fatal("builtin %s declared with too many args: %d", name, numargs);
+ addident(ident(ID_COMMAND, name, args, argmask, numargs, (void *)fun, flags));
+ return false;
}
bool addkeyword(int type, const char *name)
{
- addident(ident(type, name, "", 0, 0, NULL));
- return true;
+ addident(ident(type, name, "", 0, 0, NULL));
+ return true;
}
const char *parsestring(const char *p)
{
- for(; *p; p++) switch(*p)
- {
- case '\r':
- case '\n':
- case '\"':
- return p;
- case '^':
- if(*++p) break;
- return p;
- }
- return p;
+ for(; *p; p++) switch(*p)
+ {
+ case '\r':
+ case '\n':
+ case '\"':
+ return p;
+ case '^':
+ if(*++p) break;
+ return p;
+ }
+ return p;
}
int unescapestring(char *dst, const char *src, const char *end)
{
- char *start = dst;
- while(src < end)
- {
- int c = *src++;
- if(c == '^')
- {
- if(src >= end) break;
- int e = *src++;
- switch(e)
- {
- case 'n': *dst++ = '\n'; break;
- case 't': *dst++ = '\t'; break;
- case 'f': *dst++ = '\f'; break;
- default: *dst++ = e; break;
- }
- }
- else *dst++ = c;
- }
- return dst - start;
+ char *start = dst;
+ while(src < end)
+ {
+ int c = *src++;
+ if(c == '^')
+ {
+ if(src >= end) break;
+ int e = *src++;
+ switch(e)
+ {
+ case 'n': *dst++ = '\n'; break;
+ case 't': *dst++ = '\t'; break;
+ case 'f': *dst++ = '\f'; break;
+ default: *dst++ = e; break;
+ }
+ }
+ else *dst++ = c;
+ }
+ return dst - start;
}
static char *conc(vector<char> &buf, tagval *v, int n, bool space, const char *prefix = NULL, int prefixlen = 0)
{
- if(prefix)
- {
- buf.put(prefix, prefixlen);
- if(space && n) buf.add(' ');
- }
- loopi(n)
- {
- const char *s = "";
- int len = 0;
- switch(v[i].type)
- {
- case VAL_INT: s = intstr(v[i].i); break;
- case VAL_FLOAT: s = floatstr(v[i].f); break;
- case VAL_STR: s = v[i].s; break;
- case VAL_MACRO: s = v[i].s; len = v[i].code[-1]>>8; goto haslen;
- }
- len = int(strlen(s));
- haslen:
- buf.put(s, len);
- if(i == n-1) break;
- if(space) buf.add(' ');
- }
- buf.add('\0');
- return buf.getbuf();
+ if(prefix)
+ {
+ buf.put(prefix, prefixlen);
+ if(space && n) buf.add(' ');
+ }
+ loopi(n)
+ {
+ const char *s = "";
+ int len = 0;
+ switch(v[i].type)
+ {
+ case VAL_INT: s = intstr(v[i].i); break;
+ case VAL_FLOAT: s = floatstr(v[i].f); break;
+ case VAL_STR: s = v[i].s; break;
+ case VAL_MACRO: s = v[i].s; len = v[i].code[-1]>>8; goto haslen;
+ }
+ len = int(strlen(s));
+ haslen:
+ buf.put(s, len);
+ if(i == n-1) break;
+ if(space) buf.add(' ');
+ }
+ buf.add('\0');
+ return buf.getbuf();
}
static char *conc(tagval *v, int n, bool space, const char *prefix, int prefixlen)
{
- static int vlen[MAXARGS];
- static char numbuf[3*MAXSTRLEN];
- int len = prefixlen, numlen = 0, i = 0;
- for(; i < n; i++) switch(v[i].type)
- {
- case VAL_MACRO: len += (vlen[i] = v[i].code[-1]>>8); break;
- case VAL_STR: len += (vlen[i] = int(strlen(v[i].s))); break;
- case VAL_INT:
- if(numlen + MAXSTRLEN > int(sizeof(numbuf))) goto overflow;
- intformat(&numbuf[numlen], v[i].i);
- numlen += (vlen[i] = strlen(&numbuf[numlen]));
- break;
- case VAL_FLOAT:
- if(numlen + MAXSTRLEN > int(sizeof(numbuf))) goto overflow;
- floatformat(&numbuf[numlen], v[i].f);
- numlen += (vlen[i] = strlen(&numbuf[numlen]));
- break;
- default: vlen[i] = 0; break;
- }
+ static int vlen[MAXARGS];
+ static char numbuf[3*MAXSTRLEN];
+ int len = prefixlen, numlen = 0, i = 0;
+ for(; i < n; i++) switch(v[i].type)
+ {
+ case VAL_MACRO: len += (vlen[i] = v[i].code[-1]>>8); break;
+ case VAL_STR: len += (vlen[i] = int(strlen(v[i].s))); break;
+ case VAL_INT:
+ if(numlen + MAXSTRLEN > int(sizeof(numbuf))) goto overflow;
+ intformat(&numbuf[numlen], v[i].i);
+ numlen += (vlen[i] = strlen(&numbuf[numlen]));
+ break;
+ case VAL_FLOAT:
+ if(numlen + MAXSTRLEN > int(sizeof(numbuf))) goto overflow;
+ floatformat(&numbuf[numlen], v[i].f);
+ numlen += (vlen[i] = strlen(&numbuf[numlen]));
+ break;
+ default: vlen[i] = 0; break;
+ }
overflow:
- if(space) len += max(prefix ? i : i-1, 0);
- char *buf = newstring(len + numlen);
- int offset = 0, numoffset = 0;
- if(prefix)
- {
- memcpy(buf, prefix, prefixlen);
- offset += prefixlen;
- if(space && i) buf[offset++] = ' ';
- }
- loopj(i)
- {
- if(v[j].type == VAL_INT || v[j].type == VAL_FLOAT)
- {
- memcpy(&buf[offset], &numbuf[numoffset], vlen[j]);
- numoffset += vlen[j];
- }
- else if(vlen[j]) memcpy(&buf[offset], v[j].s, vlen[j]);
- offset += vlen[j];
- if(j==i-1) break;
- if(space) buf[offset++] = ' ';
- }
- buf[offset] = '\0';
- if(i < n)
- {
- char *morebuf = conc(&v[i], n-i, space, buf, offset);
- delete[] buf;
- return morebuf;
- }
- return buf;
+ if(space) len += max(prefix ? i : i-1, 0);
+ char *buf = newstring(len + numlen);
+ int offset = 0, numoffset = 0;
+ if(prefix)
+ {
+ memcpy(buf, prefix, prefixlen);
+ offset += prefixlen;
+ if(space && i) buf[offset++] = ' ';
+ }
+ loopj(i)
+ {
+ if(v[j].type == VAL_INT || v[j].type == VAL_FLOAT)
+ {
+ memcpy(&buf[offset], &numbuf[numoffset], vlen[j]);
+ numoffset += vlen[j];
+ }
+ else if(vlen[j]) memcpy(&buf[offset], v[j].s, vlen[j]);
+ offset += vlen[j];
+ if(j==i-1) break;
+ if(space) buf[offset++] = ' ';
+ }
+ buf[offset] = '\0';
+ if(i < n)
+ {
+ char *morebuf = conc(&v[i], n-i, space, buf, offset);
+ delete[] buf;
+ return morebuf;
+ }
+ return buf;
}
static inline char *conc(tagval *v, int n, bool space)
{
- return conc(v, n, space, NULL, 0);
+ return conc(v, n, space, NULL, 0);
}
static inline char *conc(tagval *v, int n, bool space, const char *prefix)
{
- return conc(v, n, space, prefix, strlen(prefix));
+ return conc(v, n, space, prefix, strlen(prefix));
}
static inline void skipcomments(const char *&p)
{
- for(;;)
- {
- p += strspn(p, " \t\r");
- if(p[0]!='/' || p[1]!='/') break;
- p += strcspn(p, "\n\0");
- }
+ for(;;)
+ {
+ p += strspn(p, " \t\r");
+ if(p[0]!='/' || p[1]!='/') break;
+ p += strcspn(p, "\n\0");
+ }
}
static inline char *cutstring(const char *&p, int &len)
{
- p++;
- const char *end = parsestring(p);
- char *s = newstring(end - p);
- len = unescapestring(s, p, end);
- s[len] = '\0';
- p = end;
- if(*p=='\"') p++;
- return s;
+ p++;
+ const char *end = parsestring(p);
+ char *s = newstring(end - p);
+ len = unescapestring(s, p, end);
+ s[len] = '\0';
+ p = end;
+ if(*p=='\"') p++;
+ return s;
}
static inline const char *parseword(const char *p)
{
- const int maxbrak = 100;
- static char brakstack[maxbrak];
- int brakdepth = 0;
- for(;; p++)
- {
- p += strcspn(p, "\"/;()[] \t\r\n\0");
- switch(p[0])
- {
- case '"': case ';': case ' ': case '\t': case '\r': case '\n': case '\0': return p;
- case '/': if(p[1] == '/') return p; break;
- case '[': case '(': if(brakdepth >= maxbrak) return p; brakstack[brakdepth++] = p[0]; break;
- case ']': if(brakdepth <= 0 || brakstack[--brakdepth] != '[') return p; break;
- case ')': if(brakdepth <= 0 || brakstack[--brakdepth] != '(') return p; break;
- }
- }
- return p;
+ const int maxbrak = 100;
+ static char brakstack[maxbrak];
+ int brakdepth = 0;
+ for(;; p++)
+ {
+ p += strcspn(p, "\"/;()[] \t\r\n\0");
+ switch(p[0])
+ {
+ case '"': case ';': case ' ': case '\t': case '\r': case '\n': case '\0': return p;
+ case '/': if(p[1] == '/') return p; break;
+ case '[': case '(': if(brakdepth >= maxbrak) return p; brakstack[brakdepth++] = p[0]; break;
+ case ']': if(brakdepth <= 0 || brakstack[--brakdepth] != '[') return p; break;
+ case ')': if(brakdepth <= 0 || brakstack[--brakdepth] != '(') return p; break;
+ }
+ }
+ return p;
}
static inline char *cutword(const char *&p, int &len)
{
- const char *word = p;
- p = parseword(p);
- len = p-word;
- if(!len) return NULL;
- return newstring(word, len);
+ const char *word = p;
+ p = parseword(p);
+ len = p-word;
+ if(!len) return NULL;
+ return newstring(word, len);
}
static inline void compilestr(vector<uint> &code, const char *word, int len, bool macro = false)
{
- if(len <= 3 && !macro)
- {
- uint op = CODE_VALI|RET_STR;
- for(int i = 0; i < len; i++) op |= uint(uchar(word[i]))<<((i+1)*8);
- code.add(op);
- return;
- }
- code.add((macro ? CODE_MACRO : CODE_VAL|RET_STR)|(len<<8));
- code.put((const uint *)word, len/sizeof(uint));
- size_t endlen = len%sizeof(uint);
- union
- {
- char c[sizeof(uint)];
- uint u;
- } end;
- end.u = 0;
- memcpy(end.c, word + len - endlen, endlen);
- code.add(end.u);
+ if(len <= 3 && !macro)
+ {
+ uint op = CODE_VALI|RET_STR;
+ for(int i = 0; i < len; i++) op |= uint(uchar(word[i]))<<((i+1)*8);
+ code.add(op);
+ return;
+ }
+ code.add((macro ? CODE_MACRO : CODE_VAL|RET_STR)|(len<<8));
+ code.put((const uint *)word, len/sizeof(uint));
+ size_t endlen = len%sizeof(uint);
+ union
+ {
+ char c[sizeof(uint)];
+ uint u;
+ } end;
+ end.u = 0;
+ memcpy(end.c, word + len - endlen, endlen);
+ code.add(end.u);
}
static inline void compilestr(vector<uint> &code, const char *word = NULL)
{
- if(!word) { code.add(CODE_VALI|RET_STR); return; }
- compilestr(code, word, int(strlen(word)));
+ if(!word) { code.add(CODE_VALI|RET_STR); return; }
+ compilestr(code, word, int(strlen(word)));
}
static inline void compileint(vector<uint> &code, int i)
{
- if(i >= -0x800000 && i <= 0x7FFFFF)
- code.add(CODE_VALI|RET_INT|(i<<8));
- else
- {
- code.add(CODE_VAL|RET_INT);
- code.add(i);
- }
+ if(i >= -0x800000 && i <= 0x7FFFFF)
+ code.add(CODE_VALI|RET_INT|(i<<8));
+ else
+ {
+ code.add(CODE_VAL|RET_INT);
+ code.add(i);
+ }
}
static inline void compilenull(vector<uint> &code)
{
- code.add(CODE_VALI|RET_NULL);
+ code.add(CODE_VALI|RET_NULL);
}
static inline void compileblock(vector<uint> &code)
{
- int start = code.length();
- code.add(CODE_BLOCK);
- code.add(CODE_OFFSET|((start+2)<<8));
- code.add(CODE_EXIT);
- code[start] |= uint(code.length() - (start + 1))<<8;
+ int start = code.length();
+ code.add(CODE_BLOCK);
+ code.add(CODE_OFFSET|((start+2)<<8));
+ code.add(CODE_EXIT);
+ code[start] |= uint(code.length() - (start + 1))<<8;
}
static inline void compileident(vector<uint> &code, ident *id)
{
- code.add((id->index < MAXARGS ? CODE_IDENTARG : CODE_IDENT)|(id->index<<8));
+ code.add((id->index < MAXARGS ? CODE_IDENTARG : CODE_IDENT)|(id->index<<8));
}
static inline void compileident(vector<uint> &code, const char *word = NULL)
{
- compileident(code, word ? newident(word, IDF_UNKNOWN) : dummyident);
+ compileident(code, word ? newident(word, IDF_UNKNOWN) : dummyident);
}
static inline void compileint(vector<uint> &code, const char *word = NULL)
{
- return compileint(code, word ? parseint(word) : 0);
+ return compileint(code, word ? parseint(word) : 0);
}
static inline void compilefloat(vector<uint> &code, float f)
{
- if(int(f) == f && f >= -0x800000 && f <= 0x7FFFFF)
- code.add(CODE_VALI|RET_FLOAT|(int(f)<<8));
- else
- {
- union { float f; uint u; } conv;
- conv.f = f;
- code.add(CODE_VAL|RET_FLOAT);
- code.add(conv.u);
- }
+ if(int(f) == f && f >= -0x800000 && f <= 0x7FFFFF)
+ code.add(CODE_VALI|RET_FLOAT|(int(f)<<8));
+ else
+ {
+ union { float f; uint u; } conv;
+ conv.f = f;
+ code.add(CODE_VAL|RET_FLOAT);
+ code.add(conv.u);
+ }
}
static inline void compilefloat(vector<uint> &code, const char *word = NULL)
{
- return compilefloat(code, word ? parsefloat(word) : 0.0f);
+ return compilefloat(code, word ? parsefloat(word) : 0.0f);
}
static bool compilearg(vector<uint> &code, const char *&p, int wordtype);
@@ -1016,641 +1016,641 @@ static void compilestatements(vector<uint> &code, const char *&p, int rettype, i
static inline void compileval(vector<uint> &code, int wordtype, char *word, int wordlen)
{
- switch(wordtype)
- {
- case VAL_STR: compilestr(code, word, wordlen, true); break;
- case VAL_ANY: compilestr(code, word, wordlen); break;
- case VAL_FLOAT: compilefloat(code, word); break;
- case VAL_INT: compileint(code, word); break;
- case VAL_CODE:
- {
- int start = code.length();
- code.add(CODE_BLOCK);
- code.add(CODE_OFFSET|((start+2)<<8));
- const char *p = word;
- if(p) compilestatements(code, p, VAL_ANY);
- code.add(CODE_EXIT|RET_STR);
- code[start] |= uint(code.length() - (start + 1))<<8;
- break;
- }
- case VAL_IDENT: compileident(code, word); break;
- default:
- break;
- }
+ switch(wordtype)
+ {
+ case VAL_STR: compilestr(code, word, wordlen, true); break;
+ case VAL_ANY: compilestr(code, word, wordlen); break;
+ case VAL_FLOAT: compilefloat(code, word); break;
+ case VAL_INT: compileint(code, word); break;
+ case VAL_CODE:
+ {
+ int start = code.length();
+ code.add(CODE_BLOCK);
+ code.add(CODE_OFFSET|((start+2)<<8));
+ const char *p = word;
+ if(p) compilestatements(code, p, VAL_ANY);
+ code.add(CODE_EXIT|RET_STR);
+ code[start] |= uint(code.length() - (start + 1))<<8;
+ break;
+ }
+ case VAL_IDENT: compileident(code, word); break;
+ default:
+ break;
+ }
}
static bool compileword(vector<uint> &code, const char *&p, int wordtype, char *&word, int &wordlen);
static void compilelookup(vector<uint> &code, const char *&p, int ltype)
{
- char *lookup = NULL;
- int lookuplen = 0;
- switch(*++p)
- {
- case '(':
- case '[':
- if(!compileword(code, p, VAL_STR, lookup, lookuplen)) goto invalid;
- break;
- case '$':
- compilelookup(code, p, VAL_STR);
- break;
- case '\"':
- lookup = cutstring(p, lookuplen);
- goto lookupid;
- default:
- {
- lookup = cutword(p, lookuplen);
- if(!lookup) goto invalid;
- lookupid:
- ident *id = newident(lookup, IDF_UNKNOWN);
- if(id) switch(id->type)
- {
- case ID_VAR: code.add(CODE_IVAR|((ltype >= VAL_ANY ? VAL_INT : ltype)<<CODE_RET)|(id->index<<8)); goto done;
- case ID_FVAR: code.add(CODE_FVAR|((ltype >= VAL_ANY ? VAL_FLOAT : ltype)<<CODE_RET)|(id->index<<8)); goto done;
- case ID_SVAR: code.add(CODE_SVAR|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
- case ID_ALIAS: code.add((id->index < MAXARGS ? CODE_LOOKUPARG : CODE_LOOKUP)|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
- case ID_COMMAND:
- {
- int comtype = CODE_COM, numargs = 0;
- code.add(CODE_ENTER);
- for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
- {
- case 's': compilestr(code, NULL, 0, true); numargs++; break;
- case 'i': compileint(code); numargs++; break;
- case 'b': compileint(code, INT_MIN); numargs++; break;
- case 'f': compilefloat(code); numargs++; break;
- case 't': compilenull(code); numargs++; break;
- case 'e': compileblock(code); numargs++; break;
- case 'r': compileident(code); numargs++; break;
- case '$': compileident(code, id); numargs++; break;
- case 'N': compileint(code, -1); numargs++; break;
+ char *lookup = NULL;
+ int lookuplen = 0;
+ switch(*++p)
+ {
+ case '(':
+ case '[':
+ if(!compileword(code, p, VAL_STR, lookup, lookuplen)) goto invalid;
+ break;
+ case '$':
+ compilelookup(code, p, VAL_STR);
+ break;
+ case '\"':
+ lookup = cutstring(p, lookuplen);
+ goto lookupid;
+ default:
+ {
+ lookup = cutword(p, lookuplen);
+ if(!lookup) goto invalid;
+ lookupid:
+ ident *id = newident(lookup, IDF_UNKNOWN);
+ if(id) switch(id->type)
+ {
+ case ID_VAR: code.add(CODE_IVAR|((ltype >= VAL_ANY ? VAL_INT : ltype)<<CODE_RET)|(id->index<<8)); goto done;
+ case ID_FVAR: code.add(CODE_FVAR|((ltype >= VAL_ANY ? VAL_FLOAT : ltype)<<CODE_RET)|(id->index<<8)); goto done;
+ case ID_SVAR: code.add(CODE_SVAR|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
+ case ID_ALIAS: code.add((id->index < MAXARGS ? CODE_LOOKUPARG : CODE_LOOKUP)|((ltype >= VAL_ANY ? VAL_STR : ltype)<<CODE_RET)|(id->index<<8)); goto done;
+ case ID_COMMAND:
+ {
+ int comtype = CODE_COM, numargs = 0;
+ code.add(CODE_ENTER);
+ for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
+ {
+ case 's': compilestr(code, NULL, 0, true); numargs++; break;
+ case 'i': compileint(code); numargs++; break;
+ case 'b': compileint(code, INT_MIN); numargs++; break;
+ case 'f': compilefloat(code); numargs++; break;
+ case 't': compilenull(code); numargs++; break;
+ case 'e': compileblock(code); numargs++; break;
+ case 'r': compileident(code); numargs++; break;
+ case '$': compileident(code, id); numargs++; break;
+ case 'N': compileint(code, -1); numargs++; break;
#ifndef STANDALONE
- case 'D': comtype = CODE_COMD; numargs++; break;
+ case 'D': comtype = CODE_COMD; numargs++; break;
#endif
- case 'C': comtype = CODE_COMC; numargs = 1; goto endfmt;
- case 'V': comtype = CODE_COMV; numargs = 2; goto endfmt;
- case '1': case '2': case '3': case '4': break;
- }
- endfmt:
- code.add(comtype|(ltype < VAL_ANY ? ltype<<CODE_RET : 0)|(id->index<<8));
- code.add(CODE_EXIT|(ltype < VAL_ANY ? ltype<<CODE_RET : 0));
- goto done;
- }
- default: goto invalid;
- }
- compilestr(code, lookup, lookuplen, true);
- break;
- }
- }
- code.add(CODE_LOOKUPU|((ltype < VAL_ANY ? ltype<<CODE_RET : 0)));
+ case 'C': comtype = CODE_COMC; numargs = 1; goto endfmt;
+ case 'V': comtype = CODE_COMV; numargs = 2; goto endfmt;
+ case '1': case '2': case '3': case '4': break;
+ }
+ endfmt:
+ code.add(comtype|(ltype < VAL_ANY ? ltype<<CODE_RET : 0)|(id->index<<8));
+ code.add(CODE_EXIT|(ltype < VAL_ANY ? ltype<<CODE_RET : 0));
+ goto done;
+ }
+ default: goto invalid;
+ }
+ compilestr(code, lookup, lookuplen, true);
+ break;
+ }
+ }
+ code.add(CODE_LOOKUPU|((ltype < VAL_ANY ? ltype<<CODE_RET : 0)));
done:
- delete[] lookup;
- switch(ltype)
- {
- case VAL_CODE: code.add(CODE_COMPILE); break;
- case VAL_IDENT: code.add(CODE_IDENTU); break;
- }
- return;
+ delete[] lookup;
+ switch(ltype)
+ {
+ case VAL_CODE: code.add(CODE_COMPILE); break;
+ case VAL_IDENT: code.add(CODE_IDENTU); break;
+ }
+ return;
invalid:
- switch(ltype)
- {
- case VAL_NULL: case VAL_ANY: compilenull(code); break;
- default: compileval(code, ltype, NULL, 0); break;
- }
+ switch(ltype)
+ {
+ case VAL_NULL: case VAL_ANY: compilenull(code); break;
+ default: compileval(code, ltype, NULL, 0); break;
+ }
}
static bool compileblockstr(vector<uint> &code, const char *str, const char *end, bool macro)
{
- int start = code.length();
- code.add(macro ? CODE_MACRO : CODE_VAL|RET_STR);
- char *buf = (char *)code.reserve((end-str)/sizeof(uint)+1).buf;
- int len = 0;
- while(str < end)
- {
- int n = strcspn(str, "\r/\"@]\0");
- memcpy(&buf[len], str, n);
- len += n;
- str += n;
- switch(*str)
- {
- case '\r': str++; break;
- case '\"':
- {
- const char *start = str;
- str = parsestring(str+1);
- if(*str=='\"') str++;
- memcpy(&buf[len], start, str-start);
- len += str-start;
- break;
- }
- case '/':
- if(str[1] == '/')
- {
- size_t comment = strcspn(str, "\n\0");
- if (iscubepunct(str[2]))
- {
- memcpy(&buf[len], str, comment);
- len += comment;
- }
- str += comment;
- }
- else buf[len++] = *str++;
- break;
- case '@':
- [[fallthrough]];
- case ']':
- if(str < end) { buf[len++] = *str++; break; }
- [[fallthrough]];
- case '\0': goto done;
- }
- }
+ int start = code.length();
+ code.add(macro ? CODE_MACRO : CODE_VAL|RET_STR);
+ char *buf = (char *)code.reserve((end-str)/sizeof(uint)+1).buf;
+ int len = 0;
+ while(str < end)
+ {
+ int n = strcspn(str, "\r/\"@]\0");
+ memcpy(&buf[len], str, n);
+ len += n;
+ str += n;
+ switch(*str)
+ {
+ case '\r': str++; break;
+ case '\"':
+ {
+ const char *start = str;
+ str = parsestring(str+1);
+ if(*str=='\"') str++;
+ memcpy(&buf[len], start, str-start);
+ len += str-start;
+ break;
+ }
+ case '/':
+ if(str[1] == '/')
+ {
+ size_t comment = strcspn(str, "\n\0");
+ if (iscubepunct(str[2]))
+ {
+ memcpy(&buf[len], str, comment);
+ len += comment;
+ }
+ str += comment;
+ }
+ else buf[len++] = *str++;
+ break;
+ case '@':
+ [[fallthrough]];
+ case ']':
+ if(str < end) { buf[len++] = *str++; break; }
+ [[fallthrough]];
+ case '\0': goto done;
+ }
+ }
done:
- memset(&buf[len], '\0', sizeof(uint)-len%sizeof(uint));
- code.advance(len/sizeof(uint)+1);
- code[start] |= len<<8;
- return true;
+ memset(&buf[len], '\0', sizeof(uint)-len%sizeof(uint));
+ code.advance(len/sizeof(uint)+1);
+ code[start] |= len<<8;
+ return true;
}
static bool compileblocksub(vector<uint> &code, const char *&p)
{
- char *lookup = NULL;
- int lookuplen = 0;
- switch(*p)
- {
- case '(':
- if(!compilearg(code, p, VAL_STR)) return false;
- break;
- case '[':
- if(!compilearg(code, p, VAL_STR)) return false;
- code.add(CODE_LOOKUPU|RET_STR);
- break;
- case '\"':
- lookup = cutstring(p, lookuplen);
- goto lookupid;
- default:
- {
- {
- const char *start = p;
- while(iscubealnum(*p) || *p=='_') p++;
- lookuplen = p-start;
- if(!lookuplen) return false;
- lookup = newstring(start, lookuplen);
- }
- lookupid:
- ident *id = newident(lookup, IDF_UNKNOWN);
- if(id) switch(id->type)
- {
- case ID_VAR: code.add(CODE_IVAR|RET_STR|(id->index<<8)); goto done;
- case ID_FVAR: code.add(CODE_FVAR|RET_STR|(id->index<<8)); goto done;
- case ID_SVAR: code.add(CODE_SVAR|RET_STR|(id->index<<8)); goto done;
- case ID_ALIAS: code.add((id->index < MAXARGS ? CODE_LOOKUPARG : CODE_LOOKUP)|RET_STR|(id->index<<8)); goto done;
- }
- compilestr(code, lookup, lookuplen, true);
- code.add(CODE_LOOKUPU|RET_STR);
- done:
- delete[] lookup;
- break;
- }
- }
- return true;
+ char *lookup = NULL;
+ int lookuplen = 0;
+ switch(*p)
+ {
+ case '(':
+ if(!compilearg(code, p, VAL_STR)) return false;
+ break;
+ case '[':
+ if(!compilearg(code, p, VAL_STR)) return false;
+ code.add(CODE_LOOKUPU|RET_STR);
+ break;
+ case '\"':
+ lookup = cutstring(p, lookuplen);
+ goto lookupid;
+ default:
+ {
+ {
+ const char *start = p;
+ while(iscubealnum(*p) || *p=='_') p++;
+ lookuplen = p-start;
+ if(!lookuplen) return false;
+ lookup = newstring(start, lookuplen);
+ }
+ lookupid:
+ ident *id = newident(lookup, IDF_UNKNOWN);
+ if(id) switch(id->type)
+ {
+ case ID_VAR: code.add(CODE_IVAR|RET_STR|(id->index<<8)); goto done;
+ case ID_FVAR: code.add(CODE_FVAR|RET_STR|(id->index<<8)); goto done;
+ case ID_SVAR: code.add(CODE_SVAR|RET_STR|(id->index<<8)); goto done;
+ case ID_ALIAS: code.add((id->index < MAXARGS ? CODE_LOOKUPARG : CODE_LOOKUP)|RET_STR|(id->index<<8)); goto done;
+ }
+ compilestr(code, lookup, lookuplen, true);
+ code.add(CODE_LOOKUPU|RET_STR);
+ done:
+ delete[] lookup;
+ break;
+ }
+ }
+ return true;
}
static void compileblock(vector<uint> &code, const char *&p, int wordtype)
{
- const char *line = p, *start = p;
- int concs = 0;
- for(int brak = 1; brak;)
- {
- p += strcspn(p, "@\"/[]\0");
- int c = *p++;
- switch(c)
- {
- case '\0':
- debugcodeline(line, "missing \"]\"");
- p--;
- goto done;
- case '\"':
- p = parsestring(p);
- if(*p=='\"') p++;
- break;
- case '/':
- if(*p=='/') p += strcspn(p, "\n\0");
- break;
- case '[': brak++; break;
- case ']': brak--; break;
- case '@':
- {
- const char *esc = p;
- while(*p == '@') p++;
- int level = p - (esc - 1);
- if(brak > level) continue;
- else if(brak < level) debugcodeline(line, "too many @s");
- if(!concs) code.add(CODE_ENTER);
- if(concs + 2 > MAXARGS)
- {
- code.add(CODE_CONCW|RET_STR|(concs<<8));
- concs = 1;
- }
- if(compileblockstr(code, start, esc-1, true)) concs++;
- if(compileblocksub(code, p)) concs++;
- if(!concs) code.pop();
- else start = p;
- break;
- }
- }
- }
+ const char *line = p, *start = p;
+ int concs = 0;
+ for(int brak = 1; brak;)
+ {
+ p += strcspn(p, "@\"/[]\0");
+ int c = *p++;
+ switch(c)
+ {
+ case '\0':
+ debugcodeline(line, "missing \"]\"");
+ p--;
+ goto done;
+ case '\"':
+ p = parsestring(p);
+ if(*p=='\"') p++;
+ break;
+ case '/':
+ if(*p=='/') p += strcspn(p, "\n\0");
+ break;
+ case '[': brak++; break;
+ case ']': brak--; break;
+ case '@':
+ {
+ const char *esc = p;
+ while(*p == '@') p++;
+ int level = p - (esc - 1);
+ if(brak > level) continue;
+ else if(brak < level) debugcodeline(line, "too many @s");
+ if(!concs) code.add(CODE_ENTER);
+ if(concs + 2 > MAXARGS)
+ {
+ code.add(CODE_CONCW|RET_STR|(concs<<8));
+ concs = 1;
+ }
+ if(compileblockstr(code, start, esc-1, true)) concs++;
+ if(compileblocksub(code, p)) concs++;
+ if(!concs) code.pop();
+ else start = p;
+ break;
+ }
+ }
+ }
done:
- if(p-1 > start)
- {
- if(!concs) switch(wordtype)
- {
- case VAL_CODE:
- {
- p = start;
- int inst = code.length();
- code.add(CODE_BLOCK);
- code.add(CODE_OFFSET|((inst+2)<<8));
- compilestatements(code, p, VAL_ANY, ']');
- code.add(CODE_EXIT);
- code[inst] |= uint(code.length() - (inst + 1))<<8;
- return;
- }
- case VAL_IDENT:
- {
- char *name = newstring(start, p-1-start);
- compileident(code, name);
- delete[] name;
- return;
- }
- }
- compileblockstr(code, start, p-1, concs > 0);
- if(concs > 1) concs++;
- }
- if(concs)
- {
- code.add(CODE_CONCM|(wordtype < VAL_ANY ? wordtype<<CODE_RET : RET_STR)|(concs<<8));
- code.add(CODE_EXIT|(wordtype < VAL_ANY ? wordtype<<CODE_RET : RET_STR));
- }
- switch(wordtype)
- {
- case VAL_CODE: if(!concs && p-1 <= start) compileblock(code); else code.add(CODE_COMPILE); break;
- case VAL_IDENT: if(!concs && p-1 <= start) compileident(code); else code.add(CODE_IDENTU); break;
- case VAL_STR: case VAL_NULL: case VAL_ANY:
- if(!concs && p-1 <= start) compilestr(code);
- break;
- default:
- if(!concs)
- {
- if(p-1 <= start) compileval(code, wordtype, NULL, 0);
- else code.add(CODE_FORCE|(wordtype<<CODE_RET));
- }
- break;
- }
+ if(p-1 > start)
+ {
+ if(!concs) switch(wordtype)
+ {
+ case VAL_CODE:
+ {
+ p = start;
+ int inst = code.length();
+ code.add(CODE_BLOCK);
+ code.add(CODE_OFFSET|((inst+2)<<8));
+ compilestatements(code, p, VAL_ANY, ']');
+ code.add(CODE_EXIT);
+ code[inst] |= uint(code.length() - (inst + 1))<<8;
+ return;
+ }
+ case VAL_IDENT:
+ {
+ char *name = newstring(start, p-1-start);
+ compileident(code, name);
+ delete[] name;
+ return;
+ }
+ }
+ compileblockstr(code, start, p-1, concs > 0);
+ if(concs > 1) concs++;
+ }
+ if(concs)
+ {
+ code.add(CODE_CONCM|(wordtype < VAL_ANY ? wordtype<<CODE_RET : RET_STR)|(concs<<8));
+ code.add(CODE_EXIT|(wordtype < VAL_ANY ? wordtype<<CODE_RET : RET_STR));
+ }
+ switch(wordtype)
+ {
+ case VAL_CODE: if(!concs && p-1 <= start) compileblock(code); else code.add(CODE_COMPILE); break;
+ case VAL_IDENT: if(!concs && p-1 <= start) compileident(code); else code.add(CODE_IDENTU); break;
+ case VAL_STR: case VAL_NULL: case VAL_ANY:
+ if(!concs && p-1 <= start) compilestr(code);
+ break;
+ default:
+ if(!concs)
+ {
+ if(p-1 <= start) compileval(code, wordtype, NULL, 0);
+ else code.add(CODE_FORCE|(wordtype<<CODE_RET));
+ }
+ break;
+ }
}
static bool compileword(vector<uint> &code, const char *&p, int wordtype, char *&word, int &wordlen)
{
- skipcomments(p);
- switch(*p)
- {
- case '\"': word = cutstring(p, wordlen); break;
- case '$': compilelookup(code, p, wordtype); return true;
- case '(':
- p++;
- code.add(CODE_ENTER);
- compilestatements(code, p, VAL_ANY, ')');
- code.add(CODE_EXIT|(wordtype < VAL_ANY ? wordtype<<CODE_RET : 0));
- switch(wordtype)
- {
- case VAL_CODE: code.add(CODE_COMPILE); break;
- case VAL_IDENT: code.add(CODE_IDENTU); break;
- }
- return true;
- case '[':
- p++;
- compileblock(code, p, wordtype);
- return true;
- default: word = cutword(p, wordlen); break;
- }
- return word!=NULL;
+ skipcomments(p);
+ switch(*p)
+ {
+ case '\"': word = cutstring(p, wordlen); break;
+ case '$': compilelookup(code, p, wordtype); return true;
+ case '(':
+ p++;
+ code.add(CODE_ENTER);
+ compilestatements(code, p, VAL_ANY, ')');
+ code.add(CODE_EXIT|(wordtype < VAL_ANY ? wordtype<<CODE_RET : 0));
+ switch(wordtype)
+ {
+ case VAL_CODE: code.add(CODE_COMPILE); break;
+ case VAL_IDENT: code.add(CODE_IDENTU); break;
+ }
+ return true;
+ case '[':
+ p++;
+ compileblock(code, p, wordtype);
+ return true;
+ default: word = cutword(p, wordlen); break;
+ }
+ return word!=NULL;
}
static inline bool compilearg(vector<uint> &code, const char *&p, int wordtype)
{
- char *word = NULL;
- int wordlen = 0;
- bool more = compileword(code, p, wordtype, word, wordlen);
- if(!more) return false;
- if(word)
- {
- compileval(code, wordtype, word, wordlen);
- delete[] word;
- }
- return true;
+ char *word = NULL;
+ int wordlen = 0;
+ bool more = compileword(code, p, wordtype, word, wordlen);
+ if(!more) return false;
+ if(word)
+ {
+ compileval(code, wordtype, word, wordlen);
+ delete[] word;
+ }
+ return true;
}
static void compilestatements(vector<uint> &code, const char *&p, int rettype, int brak)
{
- const char *line = p;
- char *idname = NULL;
- int idlen = 0;
- ident *id = NULL;
- int numargs = 0;
- for(;;)
- {
- skipcomments(p);
- idname = NULL;
- bool more = compileword(code, p, VAL_ANY, idname, idlen);
- if(!more) goto endstatement;
- skipcomments(p);
- if(p[0] == '=') switch(p[1])
- {
- case '/':
- if(p[2] != '/') break;
- [[fallthrough]];
- case ';':
- [[fallthrough]];
- case ' ':
- [[fallthrough]];
- case '\t':
- [[fallthrough]];
- case '\r':
- [[fallthrough]];
- case '\n':
- [[fallthrough]];
- case '\0':
- p++;
- if(idname)
- {
- id = newident(idname, IDF_UNKNOWN);
- if(id) switch(id->type)
- {
- case ID_ALIAS:
- if(!(more = compilearg(code, p, VAL_ANY))) compilestr(code);
- code.add((id->index < MAXARGS ? CODE_ALIASARG : CODE_ALIAS)|(id->index<<8));
- goto endcommand;
- case ID_VAR:
- if(!(more = compilearg(code, p, VAL_INT))) compileint(code);
- code.add(CODE_IVAR1|(id->index<<8));
- goto endcommand;
- case ID_FVAR:
- if(!(more = compilearg(code, p, VAL_FLOAT))) compilefloat(code);
- code.add(CODE_FVAR1|(id->index<<8));
- goto endcommand;
- case ID_SVAR:
- if(!(more = compilearg(code, p, VAL_STR))) compilestr(code);
- code.add(CODE_SVAR1|(id->index<<8));
- goto endcommand;
- case ID_COMMAND:
- if(id->flags&IDF_EMUVAR) goto compilecommand;
- break;
- }
- compilestr(code, idname, idlen, true);
- delete[] idname;
- }
- if(!(more = compilearg(code, p, VAL_ANY))) compilestr(code);
- code.add(CODE_ALIASU);
- goto endstatement;
- }
- compilecommand:
- numargs = 0;
- if(!idname)
- {
- noid:
- while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++;
- code.add(CODE_CALLU);
- }
- else
- {
- id = idents.access(idname);
- if(!id)
- {
- if(!checknumber(idname)) { compilestr(code, idname, idlen); delete[] idname; goto noid; }
- char *end = idname;
- int val = int(strtoul(idname, &end, 0));
- if(*end) compilestr(code, idname, idlen);
- else compileint(code, val);
- code.add(CODE_RESULT);
- }
- else switch(id->type)
- {
- case ID_ALIAS:
- while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++;
- code.add((id->index < MAXARGS ? CODE_CALLARG : CODE_CALL)|(id->index<<8));
- break;
- case ID_COMMAND:
- {
- int comtype = CODE_COM, fakeargs = 0;
- bool rep = false;
- for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
- {
- case 's':
- if(more) more = compilearg(code, p, VAL_STR);
- if(!more)
- {
- if(rep) break;
- compilestr(code, NULL, 0, true);
- fakeargs++;
- }
- else if(!fmt[1])
- {
- int numconc = 0;
- while(numargs + numconc < MAXARGS && (more = compilearg(code, p, VAL_STR))) numconc++;
- if(numconc > 0) code.add(CODE_CONC|RET_STR|((numconc+1)<<8));
- }
- numargs++;
- break;
- case 'i': if(more) more = compilearg(code, p, VAL_INT); if(!more) { if(rep) break; compileint(code); fakeargs++; } numargs++; break;
- case 'b': if(more) more = compilearg(code, p, VAL_INT); if(!more) { if(rep) break; compileint(code, INT_MIN); fakeargs++; } numargs++; break;
- case 'f': if(more) more = compilearg(code, p, VAL_FLOAT); if(!more) { if(rep) break; compilefloat(code); fakeargs++; } numargs++; break;
- case 't': if(more) more = compilearg(code, p, VAL_ANY); if(!more) { if(rep) break; compilenull(code); fakeargs++; } numargs++; break;
- case 'e': if(more) more = compilearg(code, p, VAL_CODE); if(!more) { if(rep) break; compileblock(code); fakeargs++; } numargs++; break;
- case 'r': if(more) more = compilearg(code, p, VAL_IDENT); if(!more) { if(rep) break; compileident(code); fakeargs++; } numargs++; break;
- case '$': compileident(code, id); numargs++; break;
- case 'N': compileint(code, numargs-fakeargs); numargs++; break;
+ const char *line = p;
+ char *idname = NULL;
+ int idlen = 0;
+ ident *id = NULL;
+ int numargs = 0;
+ for(;;)
+ {
+ skipcomments(p);
+ idname = NULL;
+ bool more = compileword(code, p, VAL_ANY, idname, idlen);
+ if(!more) goto endstatement;
+ skipcomments(p);
+ if(p[0] == '=') switch(p[1])
+ {
+ case '/':
+ if(p[2] != '/') break;
+ [[fallthrough]];
+ case ';':
+ [[fallthrough]];
+ case ' ':
+ [[fallthrough]];
+ case '\t':
+ [[fallthrough]];
+ case '\r':
+ [[fallthrough]];
+ case '\n':
+ [[fallthrough]];
+ case '\0':
+ p++;
+ if(idname)
+ {
+ id = newident(idname, IDF_UNKNOWN);
+ if(id) switch(id->type)
+ {
+ case ID_ALIAS:
+ if(!(more = compilearg(code, p, VAL_ANY))) compilestr(code);
+ code.add((id->index < MAXARGS ? CODE_ALIASARG : CODE_ALIAS)|(id->index<<8));
+ goto endcommand;
+ case ID_VAR:
+ if(!(more = compilearg(code, p, VAL_INT))) compileint(code);
+ code.add(CODE_IVAR1|(id->index<<8));
+ goto endcommand;
+ case ID_FVAR:
+ if(!(more = compilearg(code, p, VAL_FLOAT))) compilefloat(code);
+ code.add(CODE_FVAR1|(id->index<<8));
+ goto endcommand;
+ case ID_SVAR:
+ if(!(more = compilearg(code, p, VAL_STR))) compilestr(code);
+ code.add(CODE_SVAR1|(id->index<<8));
+ goto endcommand;
+ case ID_COMMAND:
+ if(id->flags&IDF_EMUVAR) goto compilecommand;
+ break;
+ }
+ compilestr(code, idname, idlen, true);
+ delete[] idname;
+ }
+ if(!(more = compilearg(code, p, VAL_ANY))) compilestr(code);
+ code.add(CODE_ALIASU);
+ goto endstatement;
+ }
+ compilecommand:
+ numargs = 0;
+ if(!idname)
+ {
+ noid:
+ while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++;
+ code.add(CODE_CALLU);
+ }
+ else
+ {
+ id = idents.access(idname);
+ if(!id)
+ {
+ if(!checknumber(idname)) { compilestr(code, idname, idlen); delete[] idname; goto noid; }
+ char *end = idname;
+ int val = int(strtoul(idname, &end, 0));
+ if(*end) compilestr(code, idname, idlen);
+ else compileint(code, val);
+ code.add(CODE_RESULT);
+ }
+ else switch(id->type)
+ {
+ case ID_ALIAS:
+ while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++;
+ code.add((id->index < MAXARGS ? CODE_CALLARG : CODE_CALL)|(id->index<<8));
+ break;
+ case ID_COMMAND:
+ {
+ int comtype = CODE_COM, fakeargs = 0;
+ bool rep = false;
+ for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
+ {
+ case 's':
+ if(more) more = compilearg(code, p, VAL_STR);
+ if(!more)
+ {
+ if(rep) break;
+ compilestr(code, NULL, 0, true);
+ fakeargs++;
+ }
+ else if(!fmt[1])
+ {
+ int numconc = 0;
+ while(numargs + numconc < MAXARGS && (more = compilearg(code, p, VAL_STR))) numconc++;
+ if(numconc > 0) code.add(CODE_CONC|RET_STR|((numconc+1)<<8));
+ }
+ numargs++;
+ break;
+ case 'i': if(more) more = compilearg(code, p, VAL_INT); if(!more) { if(rep) break; compileint(code); fakeargs++; } numargs++; break;
+ case 'b': if(more) more = compilearg(code, p, VAL_INT); if(!more) { if(rep) break; compileint(code, INT_MIN); fakeargs++; } numargs++; break;
+ case 'f': if(more) more = compilearg(code, p, VAL_FLOAT); if(!more) { if(rep) break; compilefloat(code); fakeargs++; } numargs++; break;
+ case 't': if(more) more = compilearg(code, p, VAL_ANY); if(!more) { if(rep) break; compilenull(code); fakeargs++; } numargs++; break;
+ case 'e': if(more) more = compilearg(code, p, VAL_CODE); if(!more) { if(rep) break; compileblock(code); fakeargs++; } numargs++; break;
+ case 'r': if(more) more = compilearg(code, p, VAL_IDENT); if(!more) { if(rep) break; compileident(code); fakeargs++; } numargs++; break;
+ case '$': compileident(code, id); numargs++; break;
+ case 'N': compileint(code, numargs-fakeargs); numargs++; break;
#ifndef STANDALONE
- case 'D': comtype = CODE_COMD; numargs++; break;
+ case 'D': comtype = CODE_COMD; numargs++; break;
#endif
- case 'C': comtype = CODE_COMC; if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++; numargs = 1; goto endfmt;
- case 'V': comtype = CODE_COMV; if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++; numargs = 2; goto endfmt;
- case '1': case '2': case '3': case '4':
- if(more && numargs < MAXARGS)
- {
- int numrep = *fmt-'0'+1;
- fmt -= numrep;
- rep = true;
- }
- else for(; numargs > MAXARGS; numargs--) code.add(CODE_POP);
- break;
- }
- endfmt:
- code.add(comtype|(rettype < VAL_ANY ? rettype<<CODE_RET : 0)|(id->index<<8));
- break;
- }
- case ID_LOCAL:
- if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_IDENT))) numargs++;
- if(more) while((more = compilearg(code, p, VAL_ANY))) code.add(CODE_POP);
- code.add(CODE_LOCAL);
- break;
- case ID_VAR:
- if(!(more = compilearg(code, p, VAL_INT))) code.add(CODE_PRINT|(id->index<<8));
- else if(!(id->flags&IDF_HEX) || !(more = compilearg(code, p, VAL_INT))) code.add(CODE_IVAR1|(id->index<<8));
- else if(!(more = compilearg(code, p, VAL_INT))) code.add(CODE_IVAR2|(id->index<<8));
- else code.add(CODE_IVAR3|(id->index<<8));
- break;
- case ID_FVAR:
- if(!(more = compilearg(code, p, VAL_FLOAT))) code.add(CODE_PRINT|(id->index<<8));
- else code.add(CODE_FVAR1|(id->index<<8));
- break;
- case ID_SVAR:
- if(!(more = compilearg(code, p, VAL_STR))) code.add(CODE_PRINT|(id->index<<8));
- else
- {
- int numconc = 0;
- while(numconc+1 < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numconc++;
- if(numconc > 0) code.add(CODE_CONC|RET_STR|((numconc+1)<<8));
- code.add(CODE_SVAR1|(id->index<<8));
- }
- break;
- }
- endcommand:
- delete[] idname;
- }
- endstatement:
- if(more) while(compilearg(code, p, VAL_ANY)) code.add(CODE_POP);
- p += strcspn(p, ")];/\n\0");
- int c = *p++;
- switch(c)
- {
- case '\0':
- if(c != brak) debugcodeline(line, "missing \"%c\"", brak);
- p--;
- return;
-
- case ')':
- case ']':
- if(c == brak) return;
- debugcodeline(line, "unexpected \"%c\"", c);
- break;
-
- case '/':
- if(*p == '/') p += strcspn(p, "\n\0");
- goto endstatement;
- }
- }
+ case 'C': comtype = CODE_COMC; if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++; numargs = 1; goto endfmt;
+ case 'V': comtype = CODE_COMV; if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numargs++; numargs = 2; goto endfmt;
+ case '1': case '2': case '3': case '4':
+ if(more && numargs < MAXARGS)
+ {
+ int numrep = *fmt-'0'+1;
+ fmt -= numrep;
+ rep = true;
+ }
+ else for(; numargs > MAXARGS; numargs--) code.add(CODE_POP);
+ break;
+ }
+ endfmt:
+ code.add(comtype|(rettype < VAL_ANY ? rettype<<CODE_RET : 0)|(id->index<<8));
+ break;
+ }
+ case ID_LOCAL:
+ if(more) while(numargs < MAXARGS && (more = compilearg(code, p, VAL_IDENT))) numargs++;
+ if(more) while((more = compilearg(code, p, VAL_ANY))) code.add(CODE_POP);
+ code.add(CODE_LOCAL);
+ break;
+ case ID_VAR:
+ if(!(more = compilearg(code, p, VAL_INT))) code.add(CODE_PRINT|(id->index<<8));
+ else if(!(id->flags&IDF_HEX) || !(more = compilearg(code, p, VAL_INT))) code.add(CODE_IVAR1|(id->index<<8));
+ else if(!(more = compilearg(code, p, VAL_INT))) code.add(CODE_IVAR2|(id->index<<8));
+ else code.add(CODE_IVAR3|(id->index<<8));
+ break;
+ case ID_FVAR:
+ if(!(more = compilearg(code, p, VAL_FLOAT))) code.add(CODE_PRINT|(id->index<<8));
+ else code.add(CODE_FVAR1|(id->index<<8));
+ break;
+ case ID_SVAR:
+ if(!(more = compilearg(code, p, VAL_STR))) code.add(CODE_PRINT|(id->index<<8));
+ else
+ {
+ int numconc = 0;
+ while(numconc+1 < MAXARGS && (more = compilearg(code, p, VAL_ANY))) numconc++;
+ if(numconc > 0) code.add(CODE_CONC|RET_STR|((numconc+1)<<8));
+ code.add(CODE_SVAR1|(id->index<<8));
+ }
+ break;
+ }
+ endcommand:
+ delete[] idname;
+ }
+ endstatement:
+ if(more) while(compilearg(code, p, VAL_ANY)) code.add(CODE_POP);
+ p += strcspn(p, ")];/\n\0");
+ int c = *p++;
+ switch(c)
+ {
+ case '\0':
+ if(c != brak) debugcodeline(line, "missing \"%c\"", brak);
+ p--;
+ return;
+
+ case ')':
+ case ']':
+ if(c == brak) return;
+ debugcodeline(line, "unexpected \"%c\"", c);
+ break;
+
+ case '/':
+ if(*p == '/') p += strcspn(p, "\n\0");
+ goto endstatement;
+ }
+ }
}
static void compilemain(vector<uint> &code, const char *p, int rettype = VAL_ANY)
{
- code.add(CODE_START);
- compilestatements(code, p, VAL_ANY);
- code.add(CODE_EXIT|(rettype < VAL_ANY ? rettype<<CODE_RET : 0));
+ code.add(CODE_START);
+ compilestatements(code, p, VAL_ANY);
+ code.add(CODE_EXIT|(rettype < VAL_ANY ? rettype<<CODE_RET : 0));
}
uint *compilecode(const char *p)
{
- vector<uint> buf;
- buf.reserve(64);
- compilemain(buf, p);
- uint *code = new uint[buf.length()];
- memcpy(code, buf.getbuf(), buf.length()*sizeof(uint));
- code[0] += 0x100;
- return code;
+ vector<uint> buf;
+ buf.reserve(64);
+ compilemain(buf, p);
+ uint *code = new uint[buf.length()];
+ memcpy(code, buf.getbuf(), buf.length()*sizeof(uint));
+ code[0] += 0x100;
+ return code;
}
void keepcode(uint *code)
{
- if(!code) return;
- switch(*code&CODE_OP_MASK)
- {
- case CODE_START:
- *code += 0x100;
- return;
- }
- switch(code[-1]&CODE_OP_MASK)
- {
- case CODE_START:
- code[-1] += 0x100;
- break;
- case CODE_OFFSET:
- code -= int(code[-1]>>8);
- *code += 0x100;
- break;
- }
+ if(!code) return;
+ switch(*code&CODE_OP_MASK)
+ {
+ case CODE_START:
+ *code += 0x100;
+ return;
+ }
+ switch(code[-1]&CODE_OP_MASK)
+ {
+ case CODE_START:
+ code[-1] += 0x100;
+ break;
+ case CODE_OFFSET:
+ code -= int(code[-1]>>8);
+ *code += 0x100;
+ break;
+ }
}
void freecode(uint *code)
{
- if(!code) return;
- switch(*code&CODE_OP_MASK)
- {
- case CODE_START:
- *code -= 0x100;
- if(int(*code) < 0x100) delete[] code;
- return;
- }
- switch(code[-1]&CODE_OP_MASK)
- {
- case CODE_START:
- code[-1] -= 0x100;
- if(int(code[-1]) < 0x100) delete[] &code[-1];
- break;
- case CODE_OFFSET:
- code -= int(code[-1]>>8);
- *code -= 0x100;
- if(int(*code) < 0x100) delete[] code;
- break;
- }
+ if(!code) return;
+ switch(*code&CODE_OP_MASK)
+ {
+ case CODE_START:
+ *code -= 0x100;
+ if(int(*code) < 0x100) delete[] code;
+ return;
+ }
+ switch(code[-1]&CODE_OP_MASK)
+ {
+ case CODE_START:
+ code[-1] -= 0x100;
+ if(int(code[-1]) < 0x100) delete[] &code[-1];
+ break;
+ case CODE_OFFSET:
+ code -= int(code[-1]>>8);
+ *code -= 0x100;
+ if(int(*code) < 0x100) delete[] code;
+ break;
+ }
}
void printvar(ident *id, int i)
{
- if(i < 0) conoutf(CON_INFO, id->index, "%s = %d", id->name, i);
- else if(id->flags&IDF_HEX && id->maxval==0xFFFFFF)
- conoutf(CON_INFO, id->index, "%s = 0x%.6X (%d, %d, %d)", id->name, i, (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF);
- else
- conoutf(CON_INFO, id->index, id->flags&IDF_HEX ? "%s = 0x%X" : "%s = %d", id->name, i);
+ if(i < 0) conoutf(CON_INFO, id->index, "%s = %d", id->name, i);
+ else if(id->flags&IDF_HEX && id->maxval==0xFFFFFF)
+ conoutf(CON_INFO, id->index, "%s = 0x%.6X (%d, %d, %d)", id->name, i, (i>>16)&0xFF, (i>>8)&0xFF, i&0xFF);
+ else
+ conoutf(CON_INFO, id->index, id->flags&IDF_HEX ? "%s = 0x%X" : "%s = %d", id->name, i);
}
void printfvar(ident *id, float f)
{
- conoutf(CON_INFO, id->index, "%s = %s", id->name, floatstr(f));
+ conoutf(CON_INFO, id->index, "%s = %s", id->name, floatstr(f));
}
void printsvar(ident *id, const char *s)
{
- conoutf(CON_INFO, id->index, strchr(s, '"') ? "%s = [%s]" : "%s = \"%s\"", id->name, s);
+ conoutf(CON_INFO, id->index, strchr(s, '"') ? "%s = [%s]" : "%s = \"%s\"", id->name, s);
}
template <class V>
static void printvar(ident *id, int type, V &val)
{
- switch(type)
- {
- case VAL_INT: printvar(id, val.getint()); break;
- case VAL_FLOAT: printfvar(id, val.getfloat()); break;
- default: printsvar(id, val.getstr()); break;
- }
+ switch(type)
+ {
+ case VAL_INT: printvar(id, val.getint()); break;
+ case VAL_FLOAT: printfvar(id, val.getfloat()); break;
+ default: printsvar(id, val.getstr()); break;
+ }
}
void printvar(ident *id)
{
- switch(id->type)
- {
- case ID_VAR: printvar(id, *id->storage.i); break;
- case ID_FVAR: printfvar(id, *id->storage.f); break;
- case ID_SVAR: printsvar(id, *id->storage.s); break;
- case ID_ALIAS: printvar(id, id->valtype, *id); break;
- case ID_COMMAND:
- if(id->flags&IDF_EMUVAR)
- {
- tagval result;
- executeret(id, NULL, 0, true, result);
- printvar(id, result.type, result);
- freearg(result);
- }
- break;
- }
+ switch(id->type)
+ {
+ case ID_VAR: printvar(id, *id->storage.i); break;
+ case ID_FVAR: printfvar(id, *id->storage.f); break;
+ case ID_SVAR: printsvar(id, *id->storage.s); break;
+ case ID_ALIAS: printvar(id, id->valtype, *id); break;
+ case ID_COMMAND:
+ if(id->flags&IDF_EMUVAR)
+ {
+ tagval result;
+ executeret(id, NULL, 0, true, result);
+ printvar(id, result.type, result);
+ freearg(result);
+ }
+ break;
+ }
}
ICOMMAND(printvar, "r", (ident *id), printvar(id));
@@ -1671,102 +1671,102 @@ typedef void (__cdecl *comfunv)(tagval *, int);
static const uint *skipcode(const uint *code, tagval &result)
{
- int depth = 0;
- for(;;)
- {
- uint op = *code++;
- switch(op&0xFF)
- {
- case CODE_MACRO:
- case CODE_VAL|RET_STR:
- {
- uint len = op>>8;
- code += len/sizeof(uint) + 1;
- continue;
- }
- case CODE_BLOCK:
- {
- uint len = op>>8;
- code += len;
- continue;
- }
- case CODE_ENTER:
- ++depth;
- continue;
- case CODE_EXIT|RET_NULL: case CODE_EXIT|RET_STR: case CODE_EXIT|RET_INT: case CODE_EXIT|RET_FLOAT:
- if(depth <= 0)
- {
- forcearg(result, op&CODE_RET_MASK);
- return code;
- }
- --depth;
- continue;
- }
- }
+ int depth = 0;
+ for(;;)
+ {
+ uint op = *code++;
+ switch(op&0xFF)
+ {
+ case CODE_MACRO:
+ case CODE_VAL|RET_STR:
+ {
+ uint len = op>>8;
+ code += len/sizeof(uint) + 1;
+ continue;
+ }
+ case CODE_BLOCK:
+ {
+ uint len = op>>8;
+ code += len;
+ continue;
+ }
+ case CODE_ENTER:
+ ++depth;
+ continue;
+ case CODE_EXIT|RET_NULL: case CODE_EXIT|RET_STR: case CODE_EXIT|RET_INT: case CODE_EXIT|RET_FLOAT:
+ if(depth <= 0)
+ {
+ forcearg(result, op&CODE_RET_MASK);
+ return code;
+ }
+ --depth;
+ continue;
+ }
+ }
}
static inline void callcommand(ident *id, tagval *args, int numargs, bool lookup = false)
{
- int i = -1, fakeargs = 0;
- bool rep = false;
- for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
- {
- case 'i': if(++i >= numargs) { if(rep) break; args[i].setint(0); fakeargs++; } else forceint(args[i]); break;
- case 'b': if(++i >= numargs) { if(rep) break; args[i].setint(INT_MIN); fakeargs++; } else forceint(args[i]); break;
- case 'f': if(++i >= numargs) { if(rep) break; args[i].setfloat(0.0f); fakeargs++; } else forcefloat(args[i]); break;
- case 's': if(++i >= numargs) { if(rep) break; args[i].setstr(newstring("")); fakeargs++; } else forcestr(args[i]); break;
- case 't': if(++i >= numargs) { if(rep) break; args[i].setnull(); fakeargs++; } break;
- case 'e':
- if(++i >= numargs)
- {
- if(rep) break;
- static uint buf[2] = { CODE_START + 0x100, CODE_EXIT };
- args[i].setcode(buf);
- fakeargs++;
- }
- else
- {
- vector<uint> buf;
- buf.reserve(64);
- compilemain(buf, numargs <= i ? "" : args[i].getstr());
- freearg(args[i]);
- args[i].setcode(buf.getbuf()+1);
- buf.disown();
- }
- break;
- case 'r': if(++i >= numargs) { if(rep) break; args[i].setident(dummyident); fakeargs++; } else forceident(args[i]); break;
- case '$': if(++i < numargs) freearg(args[i]); args[i].setident(id); break;
- case 'N': if(++i < numargs) freearg(args[i]); args[i].setint(lookup ? -1 : i-fakeargs); break;
+ int i = -1, fakeargs = 0;
+ bool rep = false;
+ for(const char *fmt = id->args; *fmt; fmt++) switch(*fmt)
+ {
+ case 'i': if(++i >= numargs) { if(rep) break; args[i].setint(0); fakeargs++; } else forceint(args[i]); break;
+ case 'b': if(++i >= numargs) { if(rep) break; args[i].setint(INT_MIN); fakeargs++; } else forceint(args[i]); break;
+ case 'f': if(++i >= numargs) { if(rep) break; args[i].setfloat(0.0f); fakeargs++; } else forcefloat(args[i]); break;
+ case 's': if(++i >= numargs) { if(rep) break; args[i].setstr(newstring("")); fakeargs++; } else forcestr(args[i]); break;
+ case 't': if(++i >= numargs) { if(rep) break; args[i].setnull(); fakeargs++; } break;
+ case 'e':
+ if(++i >= numargs)
+ {
+ if(rep) break;
+ static uint buf[2] = { CODE_START + 0x100, CODE_EXIT };
+ args[i].setcode(buf);
+ fakeargs++;
+ }
+ else
+ {
+ vector<uint> buf;
+ buf.reserve(64);
+ compilemain(buf, numargs <= i ? "" : args[i].getstr());
+ freearg(args[i]);
+ args[i].setcode(buf.getbuf()+1);
+ buf.disown();
+ }
+ break;
+ case 'r': if(++i >= numargs) { if(rep) break; args[i].setident(dummyident); fakeargs++; } else forceident(args[i]); break;
+ case '$': if(++i < numargs) freearg(args[i]); args[i].setident(id); break;
+ case 'N': if(++i < numargs) freearg(args[i]); args[i].setint(lookup ? -1 : i-fakeargs); break;
#ifndef STANDALONE
- case 'D': if(++i < numargs) freearg(args[i]); args[i].setint(addreleaseaction(conc(args, i, true, id->name)) ? 1 : 0); fakeargs++; break;
+ case 'D': if(++i < numargs) freearg(args[i]); args[i].setint(addreleaseaction(conc(args, i, true, id->name)) ? 1 : 0); fakeargs++; break;
#endif
- case 'C': { i = max(i+1, numargs); vector<char> buf; ((comfun1)id->fun)(conc(buf, args, i, true)); goto cleanup; }
- case 'V': i = max(i+1, numargs); ((comfunv)id->fun)(args, i); goto cleanup;
- case '1': case '2': case '3': case '4': if(i+1 < numargs) { fmt -= *fmt-'0'+1; rep = true; } break;
- }
- #define ARG(n) (id->argmask&(1<<n) ? (void *)args[n].s : (void *)&args[n].i)
- #define CALLCOM(n) \
- switch(n) \
- { \
- case 0: ((comfun)id->fun)(); break; \
- case 1: ((comfun1)id->fun)(ARG(0)); break; \
- case 2: ((comfun2)id->fun)(ARG(0), ARG(1)); break; \
- case 3: ((comfun3)id->fun)(ARG(0), ARG(1), ARG(2)); break; \
- case 4: ((comfun4)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3)); break; \
- case 5: ((comfun5)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4)); break; \
- case 6: ((comfun6)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5)); break; \
- case 7: ((comfun7)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6)); break; \
- case 8: ((comfun8)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7)); break; \
- case 9: ((comfun9)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8)); break; \
- case 10: ((comfun10)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8), ARG(9)); break; \
- case 11: ((comfun11)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8), ARG(9), ARG(10)); break; \
- case 12: ((comfun12)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8), ARG(9), ARG(10), ARG(11)); break; \
- }
- ++i;
- CALLCOM(i)
+ case 'C': { i = max(i+1, numargs); vector<char> buf; ((comfun1)id->fun)(conc(buf, args, i, true)); goto cleanup; }
+ case 'V': i = max(i+1, numargs); ((comfunv)id->fun)(args, i); goto cleanup;
+ case '1': case '2': case '3': case '4': if(i+1 < numargs) { fmt -= *fmt-'0'+1; rep = true; } break;
+ }
+ #define ARG(n) (id->argmask&(1<<n) ? (void *)args[n].s : (void *)&args[n].i)
+ #define CALLCOM(n) \
+ switch(n) \
+ { \
+ case 0: ((comfun)id->fun)(); break; \
+ case 1: ((comfun1)id->fun)(ARG(0)); break; \
+ case 2: ((comfun2)id->fun)(ARG(0), ARG(1)); break; \
+ case 3: ((comfun3)id->fun)(ARG(0), ARG(1), ARG(2)); break; \
+ case 4: ((comfun4)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3)); break; \
+ case 5: ((comfun5)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4)); break; \
+ case 6: ((comfun6)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5)); break; \
+ case 7: ((comfun7)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6)); break; \
+ case 8: ((comfun8)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7)); break; \
+ case 9: ((comfun9)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8)); break; \
+ case 10: ((comfun10)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8), ARG(9)); break; \
+ case 11: ((comfun11)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8), ARG(9), ARG(10)); break; \
+ case 12: ((comfun12)id->fun)(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), ARG(5), ARG(6), ARG(7), ARG(8), ARG(9), ARG(10), ARG(11)); break; \
+ }
+ ++i;
+ CALLCOM(i)
cleanup:
- loopk(i) freearg(args[k]);
- for(; i < numargs; i++) freearg(args[i]);
+ loopk(i) freearg(args[k]);
+ for(; i < numargs; i++) freearg(args[i]);
}
#define MAXRUNDEPTH 255
@@ -1774,725 +1774,725 @@ static int rundepth = 0;
static const uint *runcode(const uint *code, tagval &result)
{
- result.setnull();
- if(rundepth >= MAXRUNDEPTH)
- {
- debugcode("exceeded recursion limit");
- return skipcode(code, result);
- }
- ++rundepth;
- ident *id = NULL;
- int numargs = 0;
- tagval args[MAXARGS+1], *prevret = commandret;
- commandret = &result;
- for(;;)
- {
- uint op = *code++;
- switch(op&0xFF)
- {
- case CODE_START: case CODE_OFFSET: continue;
-
- case CODE_POP:
- freearg(args[--numargs]);
- continue;
- case CODE_ENTER:
- code = runcode(code, args[numargs++]);
- continue;
- case CODE_EXIT|RET_NULL: case CODE_EXIT|RET_STR: case CODE_EXIT|RET_INT: case CODE_EXIT|RET_FLOAT:
- forcearg(result, op&CODE_RET_MASK);
- goto exit;
- case CODE_PRINT:
- printvar(identmap[op>>8]);
- continue;
- case CODE_LOCAL:
- {
- identstack locals[MAXARGS];
- freearg(result);
- loopi(numargs) pushalias(*args[i].id, locals[i]);
- code = runcode(code, result);
- loopi(numargs) popalias(*args[i].id);
- goto exit;
- }
-
- case CODE_MACRO:
- {
- uint len = op>>8;
- args[numargs++].setmacro(code);
- code += len/sizeof(uint) + 1;
- continue;
- }
-
- case CODE_VAL|RET_STR:
- {
- uint len = op>>8;
- args[numargs++].setstr(newstring((const char *)code, len));
- code += len/sizeof(uint) + 1;
- continue;
- }
- case CODE_VALI|RET_STR:
- {
- char s[4] = { char((op>>8)&0xFF), char((op>>16)&0xFF), char((op>>24)&0xFF), '\0' };
- args[numargs++].setstr(newstring(s));
- continue;
- }
- case CODE_VAL|RET_NULL:
- case CODE_VALI|RET_NULL: args[numargs++].setnull(); continue;
- case CODE_VAL|RET_INT: args[numargs++].setint(int(*code++)); continue;
- case CODE_VALI|RET_INT: args[numargs++].setint(int(op)>>8); continue;
- case CODE_VAL|RET_FLOAT: args[numargs++].setfloat(*(const float *)code++); continue;
- case CODE_VALI|RET_FLOAT: args[numargs++].setfloat(float(int(op)>>8)); continue;
-
- case CODE_FORCE|RET_STR: forcestr(args[numargs-1]); continue;
- case CODE_FORCE|RET_INT: forceint(args[numargs-1]); continue;
- case CODE_FORCE|RET_FLOAT: forcefloat(args[numargs-1]); continue;
-
- case CODE_RESULT|RET_NULL: case CODE_RESULT|RET_STR: case CODE_RESULT|RET_INT: case CODE_RESULT|RET_FLOAT:
- litval:
- freearg(result);
- result = args[0];
- forcearg(result, op&CODE_RET_MASK);
- args[0].setnull();
- freeargs(args, numargs, 0);
- continue;
-
- case CODE_BLOCK:
- {
- uint len = op>>8;
- args[numargs++].setcode(code+1);
- code += len;
- continue;
- }
- case CODE_COMPILE:
- {
- tagval &arg = args[numargs-1];
- vector<uint> buf;
- switch(arg.type)
- {
- case VAL_INT: buf.reserve(8); buf.add(CODE_START); compileint(buf, arg.i); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
- case VAL_FLOAT: buf.reserve(8); buf.add(CODE_START); compilefloat(buf, arg.f); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
- case VAL_STR: case VAL_MACRO: buf.reserve(64); compilemain(buf, arg.s); freearg(arg); break;
- default: buf.reserve(8); buf.add(CODE_START); compilenull(buf); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
- }
- arg.setcode(buf.getbuf()+1);
- buf.disown();
- continue;
- }
-
- case CODE_IDENT:
- args[numargs++].setident(identmap[op>>8]);
- continue;
- case CODE_IDENTARG:
- {
- ident *id = identmap[op>>8];
- if(!(aliasstack->usedargs&(1<<id->index)))
- {
- pusharg(*id, nullval, aliasstack->argstack[id->index]);
- aliasstack->usedargs |= 1<<id->index;
- }
- args[numargs++].setident(id);
- continue;
- }
- case CODE_IDENTU:
- {
- tagval &arg = args[numargs-1];
- ident *id = arg.type == VAL_STR || arg.type == VAL_MACRO ? newident(arg.s, IDF_UNKNOWN) : dummyident;
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
- {
- pusharg(*id, nullval, aliasstack->argstack[id->index]);
- aliasstack->usedargs |= 1<<id->index;
- }
- freearg(arg);
- arg.setident(id);
- continue;
- }
-
- case CODE_LOOKUPU|RET_STR:
- #define LOOKUPU(aval, sval, ival, fval, nval) { \
- tagval &arg = args[numargs-1]; \
- if(arg.type != VAL_STR && arg.type != VAL_MACRO) continue; \
- id = idents.access(arg.s); \
- if(id) switch(id->type) \
- { \
- case ID_ALIAS: \
- if(id->flags&IDF_UNKNOWN) break; \
- freearg(arg); \
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) { nval; continue; } \
- aval; \
- continue; \
- case ID_SVAR: freearg(arg); sval; continue; \
- case ID_VAR: freearg(arg); ival; continue; \
- case ID_FVAR: freearg(arg); fval; continue; \
- case ID_COMMAND: \
- { \
- freearg(arg); \
- arg.setnull(); \
- commandret = &arg; \
- tagval buf[MAXARGS]; \
- callcommand(id, buf, 0, true); \
- forcearg(arg, op&CODE_RET_MASK); \
- commandret = &result; \
- continue; \
- } \
- default: freearg(arg); nval; continue; \
- } \
- debugcode("unknown alias lookup: %s", arg.s); \
- freearg(arg); \
- nval; \
- continue; \
- }
- LOOKUPU(arg.setstr(newstring(id->getstr())),
- arg.setstr(newstring(*id->storage.s)),
- arg.setstr(newstring(intstr(*id->storage.i))),
- arg.setstr(newstring(floatstr(*id->storage.f))),
- arg.setstr(newstring("")));
- case CODE_LOOKUP|RET_STR:
- #define LOOKUP(aval) { \
- id = identmap[op>>8]; \
- if(id->flags&IDF_UNKNOWN) debugcode("unknown alias lookup: %s", id->name); \
- aval; \
- continue; \
- }
- LOOKUP(args[numargs++].setstr(newstring(id->getstr())));
- case CODE_LOOKUPARG|RET_STR:
- #define LOOKUPARG(aval, nval) { \
- id = identmap[op>>8]; \
- if(!(aliasstack->usedargs&(1<<id->index))) { nval; continue; } \
- aval; \
- continue; \
- }
- LOOKUPARG(args[numargs++].setstr(newstring(id->getstr())), args[numargs++].setstr(newstring("")));
- case CODE_LOOKUPU|RET_INT:
- LOOKUPU(arg.setint(id->getint()),
- arg.setint(parseint(*id->storage.s)),
- arg.setint(*id->storage.i),
- arg.setint(int(*id->storage.f)),
- arg.setint(0));
- case CODE_LOOKUP|RET_INT:
- LOOKUP(args[numargs++].setint(id->getint()));
- case CODE_LOOKUPARG|RET_INT:
- LOOKUPARG(args[numargs++].setint(id->getint()), args[numargs++].setint(0));
- case CODE_LOOKUPU|RET_FLOAT:
- LOOKUPU(arg.setfloat(id->getfloat()),
- arg.setfloat(parsefloat(*id->storage.s)),
- arg.setfloat(float(*id->storage.i)),
- arg.setfloat(*id->storage.f),
- arg.setfloat(0.0f));
- case CODE_LOOKUP|RET_FLOAT:
- LOOKUP(args[numargs++].setfloat(id->getfloat()));
- case CODE_LOOKUPARG|RET_FLOAT:
- LOOKUPARG(args[numargs++].setfloat(id->getfloat()), args[numargs++].setfloat(0.0f));
- case CODE_LOOKUPU|RET_NULL:
- LOOKUPU(id->getval(arg),
- arg.setstr(newstring(*id->storage.s)),
- arg.setint(*id->storage.i),
- arg.setfloat(*id->storage.f),
- arg.setnull());
- case CODE_LOOKUP|RET_NULL:
- LOOKUP(id->getval(args[numargs++]));
- case CODE_LOOKUPARG|RET_NULL:
- LOOKUPARG(id->getval(args[numargs++]), args[numargs++].setnull());
-
- case CODE_SVAR|RET_STR: case CODE_SVAR|RET_NULL: args[numargs++].setstr(newstring(*identmap[op>>8]->storage.s)); continue;
- case CODE_SVAR|RET_INT: args[numargs++].setint(parseint(*identmap[op>>8]->storage.s)); continue;
- case CODE_SVAR|RET_FLOAT: args[numargs++].setfloat(parsefloat(*identmap[op>>8]->storage.s)); continue;
- case CODE_SVAR1: setsvarchecked(identmap[op>>8], args[0].s); freeargs(args, numargs, 0); continue;
-
- case CODE_IVAR|RET_INT: case CODE_IVAR|RET_NULL: args[numargs++].setint(*identmap[op>>8]->storage.i); continue;
- case CODE_IVAR|RET_STR: args[numargs++].setstr(newstring(intstr(*identmap[op>>8]->storage.i))); continue;
- case CODE_IVAR|RET_FLOAT: args[numargs++].setfloat(float(*identmap[op>>8]->storage.i)); continue;
- case CODE_IVAR1: setvarchecked(identmap[op>>8], args[0].i); numargs = 0; continue;
- case CODE_IVAR2: setvarchecked(identmap[op>>8], (args[0].i<<16)|(args[1].i<<8)); numargs = 0; continue;
- case CODE_IVAR3: setvarchecked(identmap[op>>8], (args[0].i<<16)|(args[1].i<<8)|args[2].i); numargs = 0; continue;
-
- case CODE_FVAR|RET_FLOAT: case CODE_FVAR|RET_NULL: args[numargs++].setfloat(*identmap[op>>8]->storage.f); continue;
- case CODE_FVAR|RET_STR: args[numargs++].setstr(newstring(floatstr(*identmap[op>>8]->storage.f))); continue;
- case CODE_FVAR|RET_INT: args[numargs++].setint(int(*identmap[op>>8]->storage.f)); continue;
- case CODE_FVAR1: setfvarchecked(identmap[op>>8], args[0].f); numargs = 0; continue;
-
- case CODE_COM|RET_NULL: case CODE_COM|RET_STR: case CODE_COM|RET_FLOAT: case CODE_COM|RET_INT:
- id = identmap[op>>8];
+ result.setnull();
+ if(rundepth >= MAXRUNDEPTH)
+ {
+ debugcode("exceeded recursion limit");
+ return skipcode(code, result);
+ }
+ ++rundepth;
+ ident *id = NULL;
+ int numargs = 0;
+ tagval args[MAXARGS+1], *prevret = commandret;
+ commandret = &result;
+ for(;;)
+ {
+ uint op = *code++;
+ switch(op&0xFF)
+ {
+ case CODE_START: case CODE_OFFSET: continue;
+
+ case CODE_POP:
+ freearg(args[--numargs]);
+ continue;
+ case CODE_ENTER:
+ code = runcode(code, args[numargs++]);
+ continue;
+ case CODE_EXIT|RET_NULL: case CODE_EXIT|RET_STR: case CODE_EXIT|RET_INT: case CODE_EXIT|RET_FLOAT:
+ forcearg(result, op&CODE_RET_MASK);
+ goto exit;
+ case CODE_PRINT:
+ printvar(identmap[op>>8]);
+ continue;
+ case CODE_LOCAL:
+ {
+ identstack locals[MAXARGS];
+ freearg(result);
+ loopi(numargs) pushalias(*args[i].id, locals[i]);
+ code = runcode(code, result);
+ loopi(numargs) popalias(*args[i].id);
+ goto exit;
+ }
+
+ case CODE_MACRO:
+ {
+ uint len = op>>8;
+ args[numargs++].setmacro(code);
+ code += len/sizeof(uint) + 1;
+ continue;
+ }
+
+ case CODE_VAL|RET_STR:
+ {
+ uint len = op>>8;
+ args[numargs++].setstr(newstring((const char *)code, len));
+ code += len/sizeof(uint) + 1;
+ continue;
+ }
+ case CODE_VALI|RET_STR:
+ {
+ char s[4] = { char((op>>8)&0xFF), char((op>>16)&0xFF), char((op>>24)&0xFF), '\0' };
+ args[numargs++].setstr(newstring(s));
+ continue;
+ }
+ case CODE_VAL|RET_NULL:
+ case CODE_VALI|RET_NULL: args[numargs++].setnull(); continue;
+ case CODE_VAL|RET_INT: args[numargs++].setint(int(*code++)); continue;
+ case CODE_VALI|RET_INT: args[numargs++].setint(int(op)>>8); continue;
+ case CODE_VAL|RET_FLOAT: args[numargs++].setfloat(*(const float *)code++); continue;
+ case CODE_VALI|RET_FLOAT: args[numargs++].setfloat(float(int(op)>>8)); continue;
+
+ case CODE_FORCE|RET_STR: forcestr(args[numargs-1]); continue;
+ case CODE_FORCE|RET_INT: forceint(args[numargs-1]); continue;
+ case CODE_FORCE|RET_FLOAT: forcefloat(args[numargs-1]); continue;
+
+ case CODE_RESULT|RET_NULL: case CODE_RESULT|RET_STR: case CODE_RESULT|RET_INT: case CODE_RESULT|RET_FLOAT:
+ litval:
+ freearg(result);
+ result = args[0];
+ forcearg(result, op&CODE_RET_MASK);
+ args[0].setnull();
+ freeargs(args, numargs, 0);
+ continue;
+
+ case CODE_BLOCK:
+ {
+ uint len = op>>8;
+ args[numargs++].setcode(code+1);
+ code += len;
+ continue;
+ }
+ case CODE_COMPILE:
+ {
+ tagval &arg = args[numargs-1];
+ vector<uint> buf;
+ switch(arg.type)
+ {
+ case VAL_INT: buf.reserve(8); buf.add(CODE_START); compileint(buf, arg.i); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
+ case VAL_FLOAT: buf.reserve(8); buf.add(CODE_START); compilefloat(buf, arg.f); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
+ case VAL_STR: case VAL_MACRO: buf.reserve(64); compilemain(buf, arg.s); freearg(arg); break;
+ default: buf.reserve(8); buf.add(CODE_START); compilenull(buf); buf.add(CODE_RESULT); buf.add(CODE_EXIT); break;
+ }
+ arg.setcode(buf.getbuf()+1);
+ buf.disown();
+ continue;
+ }
+
+ case CODE_IDENT:
+ args[numargs++].setident(identmap[op>>8]);
+ continue;
+ case CODE_IDENTARG:
+ {
+ ident *id = identmap[op>>8];
+ if(!(aliasstack->usedargs&(1<<id->index)))
+ {
+ pusharg(*id, nullval, aliasstack->argstack[id->index]);
+ aliasstack->usedargs |= 1<<id->index;
+ }
+ args[numargs++].setident(id);
+ continue;
+ }
+ case CODE_IDENTU:
+ {
+ tagval &arg = args[numargs-1];
+ ident *id = arg.type == VAL_STR || arg.type == VAL_MACRO ? newident(arg.s, IDF_UNKNOWN) : dummyident;
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index)))
+ {
+ pusharg(*id, nullval, aliasstack->argstack[id->index]);
+ aliasstack->usedargs |= 1<<id->index;
+ }
+ freearg(arg);
+ arg.setident(id);
+ continue;
+ }
+
+ case CODE_LOOKUPU|RET_STR:
+ #define LOOKUPU(aval, sval, ival, fval, nval) { \
+ tagval &arg = args[numargs-1]; \
+ if(arg.type != VAL_STR && arg.type != VAL_MACRO) continue; \
+ id = idents.access(arg.s); \
+ if(id) switch(id->type) \
+ { \
+ case ID_ALIAS: \
+ if(id->flags&IDF_UNKNOWN) break; \
+ freearg(arg); \
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) { nval; continue; } \
+ aval; \
+ continue; \
+ case ID_SVAR: freearg(arg); sval; continue; \
+ case ID_VAR: freearg(arg); ival; continue; \
+ case ID_FVAR: freearg(arg); fval; continue; \
+ case ID_COMMAND: \
+ { \
+ freearg(arg); \
+ arg.setnull(); \
+ commandret = &arg; \
+ tagval buf[MAXARGS]; \
+ callcommand(id, buf, 0, true); \
+ forcearg(arg, op&CODE_RET_MASK); \
+ commandret = &result; \
+ continue; \
+ } \
+ default: freearg(arg); nval; continue; \
+ } \
+ debugcode("unknown alias lookup: %s", arg.s); \
+ freearg(arg); \
+ nval; \
+ continue; \
+ }
+ LOOKUPU(arg.setstr(newstring(id->getstr())),
+ arg.setstr(newstring(*id->storage.s)),
+ arg.setstr(newstring(intstr(*id->storage.i))),
+ arg.setstr(newstring(floatstr(*id->storage.f))),
+ arg.setstr(newstring("")));
+ case CODE_LOOKUP|RET_STR:
+ #define LOOKUP(aval) { \
+ id = identmap[op>>8]; \
+ if(id->flags&IDF_UNKNOWN) debugcode("unknown alias lookup: %s", id->name); \
+ aval; \
+ continue; \
+ }
+ LOOKUP(args[numargs++].setstr(newstring(id->getstr())));
+ case CODE_LOOKUPARG|RET_STR:
+ #define LOOKUPARG(aval, nval) { \
+ id = identmap[op>>8]; \
+ if(!(aliasstack->usedargs&(1<<id->index))) { nval; continue; } \
+ aval; \
+ continue; \
+ }
+ LOOKUPARG(args[numargs++].setstr(newstring(id->getstr())), args[numargs++].setstr(newstring("")));
+ case CODE_LOOKUPU|RET_INT:
+ LOOKUPU(arg.setint(id->getint()),
+ arg.setint(parseint(*id->storage.s)),
+ arg.setint(*id->storage.i),
+ arg.setint(int(*id->storage.f)),
+ arg.setint(0));
+ case CODE_LOOKUP|RET_INT:
+ LOOKUP(args[numargs++].setint(id->getint()));
+ case CODE_LOOKUPARG|RET_INT:
+ LOOKUPARG(args[numargs++].setint(id->getint()), args[numargs++].setint(0));
+ case CODE_LOOKUPU|RET_FLOAT:
+ LOOKUPU(arg.setfloat(id->getfloat()),
+ arg.setfloat(parsefloat(*id->storage.s)),
+ arg.setfloat(float(*id->storage.i)),
+ arg.setfloat(*id->storage.f),
+ arg.setfloat(0.0f));
+ case CODE_LOOKUP|RET_FLOAT:
+ LOOKUP(args[numargs++].setfloat(id->getfloat()));
+ case CODE_LOOKUPARG|RET_FLOAT:
+ LOOKUPARG(args[numargs++].setfloat(id->getfloat()), args[numargs++].setfloat(0.0f));
+ case CODE_LOOKUPU|RET_NULL:
+ LOOKUPU(id->getval(arg),
+ arg.setstr(newstring(*id->storage.s)),
+ arg.setint(*id->storage.i),
+ arg.setfloat(*id->storage.f),
+ arg.setnull());
+ case CODE_LOOKUP|RET_NULL:
+ LOOKUP(id->getval(args[numargs++]));
+ case CODE_LOOKUPARG|RET_NULL:
+ LOOKUPARG(id->getval(args[numargs++]), args[numargs++].setnull());
+
+ case CODE_SVAR|RET_STR: case CODE_SVAR|RET_NULL: args[numargs++].setstr(newstring(*identmap[op>>8]->storage.s)); continue;
+ case CODE_SVAR|RET_INT: args[numargs++].setint(parseint(*identmap[op>>8]->storage.s)); continue;
+ case CODE_SVAR|RET_FLOAT: args[numargs++].setfloat(parsefloat(*identmap[op>>8]->storage.s)); continue;
+ case CODE_SVAR1: setsvarchecked(identmap[op>>8], args[0].s); freeargs(args, numargs, 0); continue;
+
+ case CODE_IVAR|RET_INT: case CODE_IVAR|RET_NULL: args[numargs++].setint(*identmap[op>>8]->storage.i); continue;
+ case CODE_IVAR|RET_STR: args[numargs++].setstr(newstring(intstr(*identmap[op>>8]->storage.i))); continue;
+ case CODE_IVAR|RET_FLOAT: args[numargs++].setfloat(float(*identmap[op>>8]->storage.i)); continue;
+ case CODE_IVAR1: setvarchecked(identmap[op>>8], args[0].i); numargs = 0; continue;
+ case CODE_IVAR2: setvarchecked(identmap[op>>8], (args[0].i<<16)|(args[1].i<<8)); numargs = 0; continue;
+ case CODE_IVAR3: setvarchecked(identmap[op>>8], (args[0].i<<16)|(args[1].i<<8)|args[2].i); numargs = 0; continue;
+
+ case CODE_FVAR|RET_FLOAT: case CODE_FVAR|RET_NULL: args[numargs++].setfloat(*identmap[op>>8]->storage.f); continue;
+ case CODE_FVAR|RET_STR: args[numargs++].setstr(newstring(floatstr(*identmap[op>>8]->storage.f))); continue;
+ case CODE_FVAR|RET_INT: args[numargs++].setint(int(*identmap[op>>8]->storage.f)); continue;
+ case CODE_FVAR1: setfvarchecked(identmap[op>>8], args[0].f); numargs = 0; continue;
+
+ case CODE_COM|RET_NULL: case CODE_COM|RET_STR: case CODE_COM|RET_FLOAT: case CODE_COM|RET_INT:
+ id = identmap[op>>8];
#ifndef STANDALONE
- callcom:
+ callcom:
#endif
- forcenull(result);
- CALLCOM(numargs)
- forceresult:
- freeargs(args, numargs, 0);
- forcearg(result, op&CODE_RET_MASK);
- continue;
+ forcenull(result);
+ CALLCOM(numargs)
+ forceresult:
+ freeargs(args, numargs, 0);
+ forcearg(result, op&CODE_RET_MASK);
+ continue;
#ifndef STANDALONE
- case CODE_COMD|RET_NULL: case CODE_COMD|RET_STR: case CODE_COMD|RET_FLOAT: case CODE_COMD|RET_INT:
- id = identmap[op>>8];
- args[numargs].setint(addreleaseaction(conc(args, numargs, true, id->name)) ? 1 : 0);
- numargs++;
- goto callcom;
+ case CODE_COMD|RET_NULL: case CODE_COMD|RET_STR: case CODE_COMD|RET_FLOAT: case CODE_COMD|RET_INT:
+ id = identmap[op>>8];
+ args[numargs].setint(addreleaseaction(conc(args, numargs, true, id->name)) ? 1 : 0);
+ numargs++;
+ goto callcom;
#endif
- case CODE_COMV|RET_NULL: case CODE_COMV|RET_STR: case CODE_COMV|RET_FLOAT: case CODE_COMV|RET_INT:
- id = identmap[op>>8];
- forcenull(result);
- ((comfunv)id->fun)(args, numargs);
- goto forceresult;
- case CODE_COMC|RET_NULL: case CODE_COMC|RET_STR: case CODE_COMC|RET_FLOAT: case CODE_COMC|RET_INT:
- id = identmap[op>>8];
- forcenull(result);
- {
- vector<char> buf;
- buf.reserve(MAXSTRLEN);
- ((comfun1)id->fun)(conc(buf, args, numargs, true));
- }
- goto forceresult;
-
- case CODE_CONC|RET_NULL: case CODE_CONC|RET_STR: case CODE_CONC|RET_FLOAT: case CODE_CONC|RET_INT:
- case CODE_CONCW|RET_NULL: case CODE_CONCW|RET_STR: case CODE_CONCW|RET_FLOAT: case CODE_CONCW|RET_INT:
- {
- int numconc = op>>8;
- char *s = conc(&args[numargs-numconc], numconc, (op&CODE_OP_MASK)==CODE_CONC);
- freeargs(args, numargs, numargs-numconc);
- args[numargs++].setstr(s);
- forcearg(args[numargs-1], op&CODE_RET_MASK);
- continue;
- }
-
- case CODE_CONCM|RET_NULL: case CODE_CONCM|RET_STR: case CODE_CONCM|RET_FLOAT: case CODE_CONCM|RET_INT:
- {
- int numconc = op>>8;
- char *s = conc(&args[numargs-numconc], numconc, false);
- freeargs(args, numargs, numargs-numconc);
- result.setstr(s);
- forcearg(result, op&CODE_RET_MASK);
- continue;
- }
-
- case CODE_ALIAS:
- setalias(*identmap[op>>8], args[--numargs]);
- freeargs(args, numargs, 0);
- continue;
- case CODE_ALIASARG:
- setarg(*identmap[op>>8], args[--numargs]);
- freeargs(args, numargs, 0);
- continue;
- case CODE_ALIASU:
- forcestr(args[0]);
- setalias(args[0].s, args[--numargs]);
- freeargs(args, numargs, 0);
- continue;
-
- case CODE_CALL|RET_NULL: case CODE_CALL|RET_STR: case CODE_CALL|RET_FLOAT: case CODE_CALL|RET_INT:
- #define CALLALIAS(offset) { \
- identstack argstack[MAXARGS]; \
- for(int i = 0; i < numargs-offset; i++) \
- pusharg(*identmap[i], args[i+offset], argstack[i]); \
- int oldargs = _numargs, newargs = numargs-offset; \
- _numargs = newargs; \
- int oldflags = identflags; \
- identflags |= id->flags&IDF_OVERRIDDEN; \
- identlink aliaslink = { id, aliasstack, (1<<newargs)-1, argstack }; \
- aliasstack = &aliaslink; \
- if(!id->code) id->code = compilecode(id->getstr()); \
- uint *code = id->code; \
- code[0] += 0x100; \
- runcode(code+1, result); \
- code[0] -= 0x100; \
- if(int(code[0]) < 0x100) delete[] code; \
- aliasstack = aliaslink.next; \
- identflags = oldflags; \
- for(int i = 0; i < newargs; i++) \
- poparg(*identmap[i]); \
- for(int argmask = aliaslink.usedargs&(~0U<<newargs), i = newargs; argmask; i++) \
- if(argmask&(1<<i)) { poparg(*identmap[i]); argmask &= ~(1<<i); } \
- forcearg(result, op&CODE_RET_MASK); \
- _numargs = oldargs; \
- numargs = 0; \
- }
- forcenull(result);
- id = identmap[op>>8];
- if(id->flags&IDF_UNKNOWN)
- {
- debugcode("unknown command: %s", id->name);
- goto forceresult;
- }
- CALLALIAS(0);
- continue;
- case CODE_CALLARG|RET_NULL: case CODE_CALLARG|RET_STR: case CODE_CALLARG|RET_FLOAT: case CODE_CALLARG|RET_INT:
- forcenull(result);
- id = identmap[op>>8];
- if(!(aliasstack->usedargs&(1<<id->index))) goto forceresult;
- CALLALIAS(0);
- continue;
-
- case CODE_CALLU|RET_NULL: case CODE_CALLU|RET_STR: case CODE_CALLU|RET_FLOAT: case CODE_CALLU|RET_INT:
- if(args[0].type != VAL_STR) goto litval;
- id = idents.access(args[0].s);
- if(!id)
- {
- noid:
- if(checknumber(args[0].s)) goto litval;
- debugcode("unknown command: %s", args[0].s);
- forcenull(result);
- goto forceresult;
- }
- forcenull(result);
- switch(id->type)
- {
- case ID_COMMAND:
- freearg(args[0]);
- callcommand(id, args+1, numargs-1);
- forcearg(result, op&CODE_RET_MASK);
- numargs = 0;
- continue;
- case ID_LOCAL:
- {
- identstack locals[MAXARGS];
- freearg(args[0]);
- loopj(numargs-1) pushalias(*forceident(args[j+1]), locals[j]);
- code = runcode(code, result);
- loopj(numargs-1) popalias(*args[j+1].id);
- goto exit;
- }
- case ID_VAR:
- if(numargs <= 1) printvar(id); else setvarchecked(id, &args[1], numargs-1);
- goto forceresult;
- case ID_FVAR:
- if(numargs <= 1) printvar(id); else setfvarchecked(id, forcefloat(args[1]));
- goto forceresult;
- case ID_SVAR:
- if(numargs <= 1) printvar(id); else setsvarchecked(id, forcestr(args[1]));
- goto forceresult;
- case ID_ALIAS:
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) goto forceresult;
- if(id->valtype==VAL_NULL) goto noid;
- freearg(args[0]);
- CALLALIAS(1);
- continue;
- default:
- goto forceresult;
- }
- }
- }
+ case CODE_COMV|RET_NULL: case CODE_COMV|RET_STR: case CODE_COMV|RET_FLOAT: case CODE_COMV|RET_INT:
+ id = identmap[op>>8];
+ forcenull(result);
+ ((comfunv)id->fun)(args, numargs);
+ goto forceresult;
+ case CODE_COMC|RET_NULL: case CODE_COMC|RET_STR: case CODE_COMC|RET_FLOAT: case CODE_COMC|RET_INT:
+ id = identmap[op>>8];
+ forcenull(result);
+ {
+ vector<char> buf;
+ buf.reserve(MAXSTRLEN);
+ ((comfun1)id->fun)(conc(buf, args, numargs, true));
+ }
+ goto forceresult;
+
+ case CODE_CONC|RET_NULL: case CODE_CONC|RET_STR: case CODE_CONC|RET_FLOAT: case CODE_CONC|RET_INT:
+ case CODE_CONCW|RET_NULL: case CODE_CONCW|RET_STR: case CODE_CONCW|RET_FLOAT: case CODE_CONCW|RET_INT:
+ {
+ int numconc = op>>8;
+ char *s = conc(&args[numargs-numconc], numconc, (op&CODE_OP_MASK)==CODE_CONC);
+ freeargs(args, numargs, numargs-numconc);
+ args[numargs++].setstr(s);
+ forcearg(args[numargs-1], op&CODE_RET_MASK);
+ continue;
+ }
+
+ case CODE_CONCM|RET_NULL: case CODE_CONCM|RET_STR: case CODE_CONCM|RET_FLOAT: case CODE_CONCM|RET_INT:
+ {
+ int numconc = op>>8;
+ char *s = conc(&args[numargs-numconc], numconc, false);
+ freeargs(args, numargs, numargs-numconc);
+ result.setstr(s);
+ forcearg(result, op&CODE_RET_MASK);
+ continue;
+ }
+
+ case CODE_ALIAS:
+ setalias(*identmap[op>>8], args[--numargs]);
+ freeargs(args, numargs, 0);
+ continue;
+ case CODE_ALIASARG:
+ setarg(*identmap[op>>8], args[--numargs]);
+ freeargs(args, numargs, 0);
+ continue;
+ case CODE_ALIASU:
+ forcestr(args[0]);
+ setalias(args[0].s, args[--numargs]);
+ freeargs(args, numargs, 0);
+ continue;
+
+ case CODE_CALL|RET_NULL: case CODE_CALL|RET_STR: case CODE_CALL|RET_FLOAT: case CODE_CALL|RET_INT:
+ #define CALLALIAS(offset) { \
+ identstack argstack[MAXARGS]; \
+ for(int i = 0; i < numargs-offset; i++) \
+ pusharg(*identmap[i], args[i+offset], argstack[i]); \
+ int oldargs = _numargs, newargs = numargs-offset; \
+ _numargs = newargs; \
+ int oldflags = identflags; \
+ identflags |= id->flags&IDF_OVERRIDDEN; \
+ identlink aliaslink = { id, aliasstack, (1<<newargs)-1, argstack }; \
+ aliasstack = &aliaslink; \
+ if(!id->code) id->code = compilecode(id->getstr()); \
+ uint *code = id->code; \
+ code[0] += 0x100; \
+ runcode(code+1, result); \
+ code[0] -= 0x100; \
+ if(int(code[0]) < 0x100) delete[] code; \
+ aliasstack = aliaslink.next; \
+ identflags = oldflags; \
+ for(int i = 0; i < newargs; i++) \
+ poparg(*identmap[i]); \
+ for(int argmask = aliaslink.usedargs&(~0U<<newargs), i = newargs; argmask; i++) \
+ if(argmask&(1<<i)) { poparg(*identmap[i]); argmask &= ~(1<<i); } \
+ forcearg(result, op&CODE_RET_MASK); \
+ _numargs = oldargs; \
+ numargs = 0; \
+ }
+ forcenull(result);
+ id = identmap[op>>8];
+ if(id->flags&IDF_UNKNOWN)
+ {
+ debugcode("unknown command: %s", id->name);
+ goto forceresult;
+ }
+ CALLALIAS(0);
+ continue;
+ case CODE_CALLARG|RET_NULL: case CODE_CALLARG|RET_STR: case CODE_CALLARG|RET_FLOAT: case CODE_CALLARG|RET_INT:
+ forcenull(result);
+ id = identmap[op>>8];
+ if(!(aliasstack->usedargs&(1<<id->index))) goto forceresult;
+ CALLALIAS(0);
+ continue;
+
+ case CODE_CALLU|RET_NULL: case CODE_CALLU|RET_STR: case CODE_CALLU|RET_FLOAT: case CODE_CALLU|RET_INT:
+ if(args[0].type != VAL_STR) goto litval;
+ id = idents.access(args[0].s);
+ if(!id)
+ {
+ noid:
+ if(checknumber(args[0].s)) goto litval;
+ debugcode("unknown command: %s", args[0].s);
+ forcenull(result);
+ goto forceresult;
+ }
+ forcenull(result);
+ switch(id->type)
+ {
+ case ID_COMMAND:
+ freearg(args[0]);
+ callcommand(id, args+1, numargs-1);
+ forcearg(result, op&CODE_RET_MASK);
+ numargs = 0;
+ continue;
+ case ID_LOCAL:
+ {
+ identstack locals[MAXARGS];
+ freearg(args[0]);
+ loopj(numargs-1) pushalias(*forceident(args[j+1]), locals[j]);
+ code = runcode(code, result);
+ loopj(numargs-1) popalias(*args[j+1].id);
+ goto exit;
+ }
+ case ID_VAR:
+ if(numargs <= 1) printvar(id); else setvarchecked(id, &args[1], numargs-1);
+ goto forceresult;
+ case ID_FVAR:
+ if(numargs <= 1) printvar(id); else setfvarchecked(id, forcefloat(args[1]));
+ goto forceresult;
+ case ID_SVAR:
+ if(numargs <= 1) printvar(id); else setsvarchecked(id, forcestr(args[1]));
+ goto forceresult;
+ case ID_ALIAS:
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) goto forceresult;
+ if(id->valtype==VAL_NULL) goto noid;
+ freearg(args[0]);
+ CALLALIAS(1);
+ continue;
+ default:
+ goto forceresult;
+ }
+ }
+ }
exit:
- commandret = prevret;
- --rundepth;
- return code;
+ commandret = prevret;
+ --rundepth;
+ return code;
}
void executeret(const uint *code, tagval &result)
{
- runcode(code, result);
+ runcode(code, result);
}
void executeret(const char *p, tagval &result)
{
- vector<uint> code;
- code.reserve(64);
- compilemain(code, p, VAL_ANY);
- runcode(code.getbuf()+1, result);
- if(int(code[0]) >= 0x100) code.disown();
+ vector<uint> code;
+ code.reserve(64);
+ compilemain(code, p, VAL_ANY);
+ runcode(code.getbuf()+1, result);
+ if(int(code[0]) >= 0x100) code.disown();
}
void executeret(ident *id, tagval *args, int numargs, bool lookup, tagval &result)
{
- result.setnull();
- ++rundepth;
- tagval *prevret = commandret;
- commandret = &result;
- if(rundepth > MAXRUNDEPTH) debugcode("exceeded recursion limit");
- else if(id) switch(id->type)
- {
- default:
- if(!id->fun) break;
- // fall-through
- case ID_COMMAND:
- if(numargs < id->numargs)
- {
- tagval buf[MAXARGS];
- memcpy(buf, args, numargs*sizeof(tagval));
- callcommand(id, buf, numargs, lookup);
- }
- else callcommand(id, args, numargs, lookup);
- numargs = 0;
- break;
- case ID_VAR:
- if(numargs <= 0) printvar(id); else setvarchecked(id, args, numargs);
- break;
- case ID_FVAR:
- if(numargs <= 0) printvar(id); else setfvarchecked(id, forcefloat(args[0]));
- break;
- case ID_SVAR:
- if(numargs <= 0) printvar(id); else setsvarchecked(id, forcestr(args[0]));
- break;
- case ID_ALIAS:
- if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) break;
- if(id->valtype==VAL_NULL) break;
- #define op RET_NULL
- CALLALIAS(0);
- #undef op
- break;
- }
- freeargs(args, numargs, 0);
- commandret = prevret;
- --rundepth;
+ result.setnull();
+ ++rundepth;
+ tagval *prevret = commandret;
+ commandret = &result;
+ if(rundepth > MAXRUNDEPTH) debugcode("exceeded recursion limit");
+ else if(id) switch(id->type)
+ {
+ default:
+ if(!id->fun) break;
+ // fall-through
+ case ID_COMMAND:
+ if(numargs < id->numargs)
+ {
+ tagval buf[MAXARGS];
+ memcpy(buf, args, numargs*sizeof(tagval));
+ callcommand(id, buf, numargs, lookup);
+ }
+ else callcommand(id, args, numargs, lookup);
+ numargs = 0;
+ break;
+ case ID_VAR:
+ if(numargs <= 0) printvar(id); else setvarchecked(id, args, numargs);
+ break;
+ case ID_FVAR:
+ if(numargs <= 0) printvar(id); else setfvarchecked(id, forcefloat(args[0]));
+ break;
+ case ID_SVAR:
+ if(numargs <= 0) printvar(id); else setsvarchecked(id, forcestr(args[0]));
+ break;
+ case ID_ALIAS:
+ if(id->index < MAXARGS && !(aliasstack->usedargs&(1<<id->index))) break;
+ if(id->valtype==VAL_NULL) break;
+ #define op RET_NULL
+ CALLALIAS(0);
+ #undef op
+ break;
+ }
+ freeargs(args, numargs, 0);
+ commandret = prevret;
+ --rundepth;
}
char *executestr(const uint *code)
{
- tagval result;
- runcode(code, result);
- if(result.type == VAL_NULL) return NULL;
- forcestr(result);
- return result.s;
+ tagval result;
+ runcode(code, result);
+ if(result.type == VAL_NULL) return NULL;
+ forcestr(result);
+ return result.s;
}
char *executestr(const char *p)
{
- tagval result;
- executeret(p, result);
- if(result.type == VAL_NULL) return NULL;
- forcestr(result);
- return result.s;
+ tagval result;
+ executeret(p, result);
+ if(result.type == VAL_NULL) return NULL;
+ forcestr(result);
+ return result.s;
}
char *executestr(ident *id, tagval *args, int numargs, bool lookup)
{
- tagval result;
- executeret(id, args, numargs, lookup, result);
- if(result.type == VAL_NULL) return NULL;
- forcestr(result);
- return result.s;
+ tagval result;
+ executeret(id, args, numargs, lookup, result);
+ if(result.type == VAL_NULL) return NULL;
+ forcestr(result);
+ return result.s;
}
char *execidentstr(const char *name, bool lookup)
{
- ident *id = idents.access(name);
- return id ? executestr(id, NULL, 0, lookup) : NULL;
+ ident *id = idents.access(name);
+ return id ? executestr(id, NULL, 0, lookup) : NULL;
}
int execute(const uint *code)
{
- tagval result;
- runcode(code, result);
- int i = result.getint();
- freearg(result);
- return i;
+ tagval result;
+ runcode(code, result);
+ int i = result.getint();
+ freearg(result);
+ return i;
}
int execute(const char *p)
{
- vector<uint> code;
- code.reserve(64);
- compilemain(code, p, VAL_INT);
- tagval result;
- runcode(code.getbuf()+1, result);
- if(int(code[0]) >= 0x100) code.disown();
- int i = result.getint();
- freearg(result);
- return i;
+ vector<uint> code;
+ code.reserve(64);
+ compilemain(code, p, VAL_INT);
+ tagval result;
+ runcode(code.getbuf()+1, result);
+ if(int(code[0]) >= 0x100) code.disown();
+ int i = result.getint();
+ freearg(result);
+ return i;
}
int execute(ident *id, tagval *args, int numargs, bool lookup)
{
- tagval result;
- executeret(id, args, numargs, lookup, result);
- int i = result.getint();
- freearg(result);
- return i;
+ tagval result;
+ executeret(id, args, numargs, lookup, result);
+ int i = result.getint();
+ freearg(result);
+ return i;
}
int execident(const char *name, int noid, bool lookup)
{
- ident *id = idents.access(name);
- return id ? execute(id, NULL, 0, lookup) : noid;
+ ident *id = idents.access(name);
+ return id ? execute(id, NULL, 0, lookup) : noid;
}
static inline bool getbool(const char *s)
{
- switch(s[0])
- {
- case '+': case '-':
- switch(s[1])
- {
- case '0': break;
- case '.': return !isdigit(s[2]) || parsefloat(s) != 0;
- default: return true;
- }
- // fall through
- case '0':
- {
- char *end;
- int val = int(strtoul((char *)s, &end, 0));
- if(val) return true;
- switch(*end)
- {
- case 'e': case '.': return parsefloat(s) != 0;
- default: return false;
- }
- }
- case '.': return !isdigit(s[1]) || parsefloat(s) != 0;
- case '\0': return false;
- default: return true;
- }
+ switch(s[0])
+ {
+ case '+': case '-':
+ switch(s[1])
+ {
+ case '0': break;
+ case '.': return !isdigit(s[2]) || parsefloat(s) != 0;
+ default: return true;
+ }
+ // fall through
+ case '0':
+ {
+ char *end;
+ int val = int(strtoul((char *)s, &end, 0));
+ if(val) return true;
+ switch(*end)
+ {
+ case 'e': case '.': return parsefloat(s) != 0;
+ default: return false;
+ }
+ }
+ case '.': return !isdigit(s[1]) || parsefloat(s) != 0;
+ case '\0': return false;
+ default: return true;
+ }
}
static inline bool getbool(const tagval &v)
{
- switch(v.type)
- {
- case VAL_FLOAT: return v.f!=0;
- case VAL_INT: return v.i!=0;
- case VAL_STR: case VAL_MACRO: return getbool(v.s);
- default: return false;
- }
+ switch(v.type)
+ {
+ case VAL_FLOAT: return v.f!=0;
+ case VAL_INT: return v.i!=0;
+ case VAL_STR: case VAL_MACRO: return getbool(v.s);
+ default: return false;
+ }
}
bool executebool(const uint *code)
{
- tagval result;
- runcode(code, result);
- bool b = getbool(result);
- freearg(result);
- return b;
+ tagval result;
+ runcode(code, result);
+ bool b = getbool(result);
+ freearg(result);
+ return b;
}
bool executebool(const char *p)
{
- tagval result;
- executeret(p, result);
- bool b = getbool(result);
- freearg(result);
- return b;
+ tagval result;
+ executeret(p, result);
+ bool b = getbool(result);
+ freearg(result);
+ return b;
}
bool executebool(ident *id, tagval *args, int numargs, bool lookup)
{
- tagval result;
- executeret(id, args, numargs, lookup, result);
- bool b = getbool(result);
- freearg(result);
- return b;
+ tagval result;
+ executeret(id, args, numargs, lookup, result);
+ bool b = getbool(result);
+ freearg(result);
+ return b;
}
bool execidentbool(const char *name, bool noid, bool lookup)
{
- ident *id = idents.access(name);
- return id ? executebool(id, NULL, 0, lookup) : noid;
+ ident *id = idents.access(name);
+ return id ? executebool(id, NULL, 0, lookup) : noid;
}
bool execfile(const char *cfgfile, bool msg)
{
- string s;
- copystring(s, cfgfile);
- char *buf = loadfile(path(s), NULL);
- if(!buf)
- {
- if(msg) conoutf(CON_ERROR, "could not read \"%s\"", cfgfile);
- return false;
- }
- const char *oldsourcefile = sourcefile, *oldsourcestr = sourcestr;
- sourcefile = cfgfile;
- sourcestr = buf;
- execute(buf);
- sourcefile = oldsourcefile;
- sourcestr = oldsourcestr;
- delete[] buf;
- return true;
+ string s;
+ copystring(s, cfgfile);
+ char *buf = loadfile(path(s), NULL);
+ if(!buf)
+ {
+ if(msg) conoutf(CON_ERROR, "could not read \"%s\"", cfgfile);
+ return false;
+ }
+ const char *oldsourcefile = sourcefile, *oldsourcestr = sourcestr;
+ sourcefile = cfgfile;
+ sourcestr = buf;
+ execute(buf);
+ sourcefile = oldsourcefile;
+ sourcestr = oldsourcestr;
+ delete[] buf;
+ return true;
}
ICOMMAND(exec, "sb", (char *file, int *msg), intret(execfile(file, *msg != 0) ? 1 : 0));
const char *escapestring(const char *s)
{
- static vector<char> strbuf[3];
- static int stridx = 0;
- stridx = (stridx + 1)%3;
- vector<char> &buf = strbuf[stridx];
- buf.setsize(0);
- buf.add('"');
- for(; *s; s++) switch(*s)
- {
- case '\n': buf.put("^n", 2); break;
- case '\t': buf.put("^t", 2); break;
- case '\f': buf.put("^f", 2); break;
- case '"': buf.put("^\"", 2); break;
- case '^': buf.put("^^", 2); break;
- default: buf.add(*s); break;
- }
- buf.put("\"\0", 2);
- return buf.getbuf();
+ static vector<char> strbuf[3];
+ static int stridx = 0;
+ stridx = (stridx + 1)%3;
+ vector<char> &buf = strbuf[stridx];
+ buf.setsize(0);
+ buf.add('"');
+ for(; *s; s++) switch(*s)
+ {
+ case '\n': buf.put("^n", 2); break;
+ case '\t': buf.put("^t", 2); break;
+ case '\f': buf.put("^f", 2); break;
+ case '"': buf.put("^\"", 2); break;
+ case '^': buf.put("^^", 2); break;
+ default: buf.add(*s); break;
+ }
+ buf.put("\"\0", 2);
+ return buf.getbuf();
}
ICOMMAND(escape, "s", (char *s), result(escapestring(s)));
ICOMMAND(unescape, "s", (char *s),
{
- int len = strlen(s);
- char *d = newstring(len);
- d[unescapestring(d, s, &s[len])] = '\0';
- stringret(d);
+ int len = strlen(s);
+ char *d = newstring(len);
+ d[unescapestring(d, s, &s[len])] = '\0';
+ stringret(d);
});
const char *escapeid(const char *s)
{
- const char *end = s + strcspn(s, "\"/;()[]@ \f\t\r\n\0");
- return *end ? escapestring(s) : s;
+ const char *end = s + strcspn(s, "\"/;()[]@ \f\t\r\n\0");
+ return *end ? escapestring(s) : s;
}
bool validateblock(const char *s)
{
- const int maxbrak = 100;
- static char brakstack[maxbrak];
- int brakdepth = 0;
- for(; *s; s++) switch(*s)
- {
- case '[': case '(': if(brakdepth >= maxbrak) return false; brakstack[brakdepth++] = *s; break;
- case ']': if(brakdepth <= 0 || brakstack[--brakdepth] != '[') return false; break;
- case ')': if(brakdepth <= 0 || brakstack[--brakdepth] != '(') return false; break;
- case '"': s = parsestring(s + 1); if(*s != '"') return false; break;
- case '/': if(s[1] == '/') return false; break;
- case '@': case '\f': return false;
- }
- return brakdepth == 0;
+ const int maxbrak = 100;
+ static char brakstack[maxbrak];
+ int brakdepth = 0;
+ for(; *s; s++) switch(*s)
+ {
+ case '[': case '(': if(brakdepth >= maxbrak) return false; brakstack[brakdepth++] = *s; break;
+ case ']': if(brakdepth <= 0 || brakstack[--brakdepth] != '[') return false; break;
+ case ')': if(brakdepth <= 0 || brakstack[--brakdepth] != '(') return false; break;
+ case '"': s = parsestring(s + 1); if(*s != '"') return false; break;
+ case '/': if(s[1] == '/') return false; break;
+ case '@': case '\f': return false;
+ }
+ return brakdepth == 0;
}
#ifndef STANDALONE
void writecfg(const char *name)
{
- stream *f = openutf8file(path(name && name[0] ? name : game::savedconfig(), true), "w");
- if(!f) return;
- f->printf("// automatically written on exit, DO NOT MODIFY\n// delete this file to have %s overwrite these settings\n// modify settings in game, or put settings in %s to override anything\n\n", game::defaultconfig(), game::autoexec());
- game::writeclientinfo(f);
- f->printf("\n");
- writecrosshairs(f);
- vector<ident *> ids;
- enumerate(idents, ident, id, ids.add(&id));
- ids.sortname();
- loopv(ids)
- {
- ident &id = *ids[i];
- if(id.flags&IDF_PERSIST) switch(id.type)
- {
- case ID_VAR: f->printf("%s %d\n", escapeid(id), *id.storage.i); break;
- case ID_FVAR: f->printf("%s %s\n", escapeid(id), floatstr(*id.storage.f)); break;
- case ID_SVAR: f->printf("%s %s\n", escapeid(id), escapestring(*id.storage.s)); break;
- }
- }
- f->printf("\n");
- writebinds(f);
- f->printf("\n");
- loopv(ids)
- {
- ident &id = *ids[i];
- if(id.type==ID_ALIAS && id.flags&IDF_PERSIST && !(id.flags&IDF_OVERRIDDEN)) switch(id.valtype)
- {
- case VAL_STR:
- if(!id.val.s[0]) break;
- if(!validateblock(id.val.s)) { f->printf("%s = %s\n", escapeid(id), escapestring(id.val.s)); break; }
- [[fallthrough]];
- case VAL_FLOAT:
- [[fallthrough]];
- case VAL_INT:
- f->printf("%s = [%s]\n", escapeid(id), id.getstr()); break;
- }
- }
- f->printf("\n");
- writecompletions(f);
- delete f;
+ stream *f = openutf8file(path(name && name[0] ? name : game::savedconfig(), true), "w");
+ if(!f) return;
+ f->printf("// automatically written on exit, DO NOT MODIFY\n// delete this file to have %s overwrite these settings\n// modify settings in game, or put settings in %s to override anything\n\n", game::defaultconfig(), game::autoexec());
+ game::writeclientinfo(f);
+ f->printf("\n");
+ writecrosshairs(f);
+ vector<ident *> ids;
+ enumerate(idents, ident, id, ids.add(&id));
+ ids.sortname();
+ loopv(ids)
+ {
+ ident &id = *ids[i];
+ if(id.flags&IDF_PERSIST) switch(id.type)
+ {
+ case ID_VAR: f->printf("%s %d\n", escapeid(id), *id.storage.i); break;
+ case ID_FVAR: f->printf("%s %s\n", escapeid(id), floatstr(*id.storage.f)); break;
+ case ID_SVAR: f->printf("%s %s\n", escapeid(id), escapestring(*id.storage.s)); break;
+ }
+ }
+ f->printf("\n");
+ writebinds(f);
+ f->printf("\n");
+ loopv(ids)
+ {
+ ident &id = *ids[i];
+ if(id.type==ID_ALIAS && id.flags&IDF_PERSIST && !(id.flags&IDF_OVERRIDDEN)) switch(id.valtype)
+ {
+ case VAL_STR:
+ if(!id.val.s[0]) break;
+ if(!validateblock(id.val.s)) { f->printf("%s = %s\n", escapeid(id), escapestring(id.val.s)); break; }
+ [[fallthrough]];
+ case VAL_FLOAT:
+ [[fallthrough]];
+ case VAL_INT:
+ f->printf("%s = [%s]\n", escapeid(id), id.getstr()); break;
+ }
+ }
+ f->printf("\n");
+ writecompletions(f);
+ delete f;
}
COMMAND(writecfg, "s");
@@ -2500,10 +2500,10 @@ COMMAND(writecfg, "s");
void changedvars()
{
- vector<ident *> ids;
- enumerate(idents, ident, id, if(id.flags&IDF_OVERRIDDEN) ids.add(&id));
- ids.sortname();
- loopv(ids) printvar(ids[i]);
+ vector<ident *> ids;
+ enumerate(idents, ident, id, if(id.flags&IDF_OVERRIDDEN) ids.add(&id));
+ ids.sortname();
+ loopv(ids) printvar(ids[i]);
}
COMMAND(changedvars, "");
@@ -2515,26 +2515,26 @@ static int retidx = 0;
const char *intstr(int v)
{
- retidx = (retidx + 1)%4;
- intformat(retbuf[retidx], v);
- return retbuf[retidx];
+ retidx = (retidx + 1)%4;
+ intformat(retbuf[retidx], v);
+ return retbuf[retidx];
}
void intret(int v)
{
- commandret->setint(v);
+ commandret->setint(v);
}
const char *floatstr(float v)
{
- retidx = (retidx + 1)%4;
- floatformat(retbuf[retidx], v);
- return retbuf[retidx];
+ retidx = (retidx + 1)%4;
+ floatformat(retbuf[retidx], v);
+ return retbuf[retidx];
}
void floatret(float v)
{
- commandret->setfloat(v);
+ commandret->setfloat(v);
}
#undef ICOMMANDNAME
@@ -2546,190 +2546,190 @@ ICOMMAND(?, "ttt", (tagval *cond, tagval *t, tagval *f), result(*(getbool(*cond)
ICOMMAND(pushif, "rte", (ident *id, tagval *v, uint *code),
{
- if(id->type != ID_ALIAS || id->index < MAXARGS) return;
- if(getbool(*v))
- {
- identstack stack;
- pusharg(*id, *v, stack);
- v->type = VAL_NULL;
- id->flags &= ~IDF_UNKNOWN;
- executeret(code, *commandret);
- poparg(*id);
- }
+ if(id->type != ID_ALIAS || id->index < MAXARGS) return;
+ if(getbool(*v))
+ {
+ identstack stack;
+ pusharg(*id, *v, stack);
+ v->type = VAL_NULL;
+ id->flags &= ~IDF_UNKNOWN;
+ executeret(code, *commandret);
+ poparg(*id);
+ }
});
void loopiter(ident *id, identstack &stack, const tagval &v)
{
- if(id->stack != &stack)
- {
- pusharg(*id, v, stack);
- id->flags &= ~IDF_UNKNOWN;
- }
- else
- {
- if(id->valtype == VAL_STR) delete[] id->val.s;
- cleancode(*id);
- id->setval(v);
- }
+ if(id->stack != &stack)
+ {
+ pusharg(*id, v, stack);
+ id->flags &= ~IDF_UNKNOWN;
+ }
+ else
+ {
+ if(id->valtype == VAL_STR) delete[] id->val.s;
+ cleancode(*id);
+ id->setval(v);
+ }
}
void loopend(ident *id, identstack &stack)
{
- if(id->stack == &stack) poparg(*id);
+ if(id->stack == &stack) poparg(*id);
}
static inline void setiter(ident &id, int i, identstack &stack)
{
- if(id.stack == &stack)
- {
- if(id.valtype != VAL_INT)
- {
- if(id.valtype == VAL_STR) delete[] id.val.s;
- cleancode(id);
- id.valtype = VAL_INT;
- }
- id.val.i = i;
- }
- else
- {
- tagval t;
- t.setint(i);
- pusharg(id, t, stack);
- id.flags &= ~IDF_UNKNOWN;
- }
+ if(id.stack == &stack)
+ {
+ if(id.valtype != VAL_INT)
+ {
+ if(id.valtype == VAL_STR) delete[] id.val.s;
+ cleancode(id);
+ id.valtype = VAL_INT;
+ }
+ id.val.i = i;
+ }
+ else
+ {
+ tagval t;
+ t.setint(i);
+ pusharg(id, t, stack);
+ id.flags &= ~IDF_UNKNOWN;
+ }
}
ICOMMAND(loop, "rie", (ident *id, int *n, uint *body),
{
- if(*n <= 0 || id->type!=ID_ALIAS) return;
- identstack stack;
- loopi(*n)
- {
- setiter(*id, i, stack);
- execute(body);
- }
- poparg(*id);
+ if(*n <= 0 || id->type!=ID_ALIAS) return;
+ identstack stack;
+ loopi(*n)
+ {
+ setiter(*id, i, stack);
+ execute(body);
+ }
+ poparg(*id);
});
ICOMMAND(loopwhile, "riee", (ident *id, int *n, uint *cond, uint *body),
{
- if(*n <= 0 || id->type!=ID_ALIAS) return;
- identstack stack;
- loopi(*n)
- {
- setiter(*id, i, stack);
- if(!executebool(cond)) break;
- execute(body);
- }
- poparg(*id);
+ if(*n <= 0 || id->type!=ID_ALIAS) return;
+ identstack stack;
+ loopi(*n)
+ {
+ setiter(*id, i, stack);
+ if(!executebool(cond)) break;
+ execute(body);
+ }
+ poparg(*id);
});
ICOMMAND(while, "ee", (uint *cond, uint *body), while(executebool(cond)) execute(body));
char *loopconc(ident *id, int n, uint *body, bool space)
{
- identstack stack;
- vector<char> s;
- loopi(n)
- {
- setiter(*id, i, stack);
- tagval v;
- executeret(body, v);
- const char *vstr = v.getstr();
- int len = strlen(vstr);
- if(space && i) s.add(' ');
- s.put(vstr, len);
- freearg(v);
- }
- if(n > 0) poparg(*id);
- s.add('\0');
- return newstring(s.getbuf(), s.length()-1);
+ identstack stack;
+ vector<char> s;
+ loopi(n)
+ {
+ setiter(*id, i, stack);
+ tagval v;
+ executeret(body, v);
+ const char *vstr = v.getstr();
+ int len = strlen(vstr);
+ if(space && i) s.add(' ');
+ s.put(vstr, len);
+ freearg(v);
+ }
+ if(n > 0) poparg(*id);
+ s.add('\0');
+ return newstring(s.getbuf(), s.length()-1);
}
ICOMMAND(loopconcat, "rie", (ident *id, int *n, uint *body),
{
- if(*n > 0 && id->type==ID_ALIAS) commandret->setstr(loopconc(id, *n, body, true));
+ if(*n > 0 && id->type==ID_ALIAS) commandret->setstr(loopconc(id, *n, body, true));
});
ICOMMAND(loopconcatword, "rie", (ident *id, int *n, uint *body),
{
- if(*n > 0 && id->type==ID_ALIAS) commandret->setstr(loopconc(id, *n, body, false));
+ if(*n > 0 && id->type==ID_ALIAS) commandret->setstr(loopconc(id, *n, body, false));
});
void concat(tagval *v, int n)
{
- commandret->setstr(conc(v, n, true));
+ commandret->setstr(conc(v, n, true));
}
COMMAND(concat, "V");
void concatword(tagval *v, int n)
{
- commandret->setstr(conc(v, n, false));
+ commandret->setstr(conc(v, n, false));
}
COMMAND(concatword, "V");
void append(ident *id, tagval *v, bool space)
{
- if(id->type != ID_ALIAS || v->type == VAL_NULL) return;
- if(id->valtype == VAL_NULL)
- {
- noprefix:
- if(id->index < MAXARGS) setarg(*id, *v); else setalias(*id, *v);
- v->type = VAL_NULL;
- }
- else
- {
- const char *prefix = id->getstr();
- if(!prefix[0]) goto noprefix;
- tagval r;
- r.setstr(conc(v, 1, space, prefix));
- if(id->index < MAXARGS) setarg(*id, r); else setalias(*id, r);
- }
+ if(id->type != ID_ALIAS || v->type == VAL_NULL) return;
+ if(id->valtype == VAL_NULL)
+ {
+ noprefix:
+ if(id->index < MAXARGS) setarg(*id, *v); else setalias(*id, *v);
+ v->type = VAL_NULL;
+ }
+ else
+ {
+ const char *prefix = id->getstr();
+ if(!prefix[0]) goto noprefix;
+ tagval r;
+ r.setstr(conc(v, 1, space, prefix));
+ if(id->index < MAXARGS) setarg(*id, r); else setalias(*id, r);
+ }
}
ICOMMAND(append, "rt", (ident *id, tagval *v), append(id, v, true));
ICOMMAND(appendword, "rt", (ident *id, tagval *v), append(id, v, false));
void result(tagval &v)
{
- *commandret = v;
- v.type = VAL_NULL;
+ *commandret = v;
+ v.type = VAL_NULL;
}
void stringret(char *s)
{
- commandret->setstr(s);
+ commandret->setstr(s);
}
void result(const char *s)
{
- commandret->setstr(newstring(s));
+ commandret->setstr(newstring(s));
}
ICOMMAND(result, "t", (tagval *v),
{
- *commandret = *v;
- v->type = VAL_NULL;
+ *commandret = *v;
+ v->type = VAL_NULL;
});
void format(tagval *args, int numargs)
{
- vector<char> s;
- const char *f = args[0].getstr();
- while(*f)
- {
- int c = *f++;
- if(c == '%')
- {
- int i = *f++;
- if(i >= '1' && i <= '9')
- {
- i -= '0';
- const char *sub = i < numargs ? args[i].getstr() : "";
- while(*sub) s.add(*sub++);
- }
- else s.add(i);
- }
- else s.add(c);
- }
- s.add('\0');
- result(s.getbuf());
+ vector<char> s;
+ const char *f = args[0].getstr();
+ while(*f)
+ {
+ int c = *f++;
+ if(c == '%')
+ {
+ int i = *f++;
+ if(i >= '1' && i <= '9')
+ {
+ i -= '0';
+ const char *sub = i < numargs ? args[i].getstr() : "";
+ while(*sub) s.add(*sub++);
+ }
+ else s.add(i);
+ }
+ else s.add(c);
+ }
+ s.add('\0');
+ result(s.getbuf());
}
COMMAND(format, "V");
@@ -2737,448 +2737,448 @@ static const char *liststart = NULL, *listend = NULL, *listquotestart = NULL, *l
static inline void skiplist(const char *&p)
{
- for(;;)
- {
- p += strspn(p, " \t\r\n");
- if(p[0]!='/' || p[1]!='/') break;
- p += strcspn(p, "\n\0");
- }
+ for(;;)
+ {
+ p += strspn(p, " \t\r\n");
+ if(p[0]!='/' || p[1]!='/') break;
+ p += strcspn(p, "\n\0");
+ }
}
static bool parselist(const char *&s, const char *&start = liststart, const char *&end = listend, const char *&quotestart = listquotestart, const char *&quoteend = listquoteend)
{
- skiplist(s);
- switch(*s)
- {
- case '"': quotestart = s++; start = s; s = parsestring(s); end = s; if(*s == '"') s++; quoteend = s; break;
- case '(': case '[':
- quotestart = s;
- start = s+1;
- for(int braktype = *s++, brak = 1;;)
- {
- s += strcspn(s, "\"/;()[]\0");
- int c = *s++;
- switch(c)
- {
- case '\0': s--; quoteend = end = s; return true;
- case '"': s = parsestring(s); if(*s == '"') s++; break;
- case '/': if(*s == '/') s += strcspn(s, "\n\0"); break;
- case '(': case '[': if(c == braktype) brak++; break;
- case ')': if(braktype == '(' && --brak <= 0) goto endblock; break;
- case ']': if(braktype == '[' && --brak <= 0) goto endblock; break;
- }
- }
- endblock:
- end = s-1;
- quoteend = s;
- break;
- case '\0': case ')': case ']': return false;
- default: quotestart = start = s; s = parseword(s); quoteend = end = s; break;
- }
- skiplist(s);
- if(*s == ';') s++;
- return true;
+ skiplist(s);
+ switch(*s)
+ {
+ case '"': quotestart = s++; start = s; s = parsestring(s); end = s; if(*s == '"') s++; quoteend = s; break;
+ case '(': case '[':
+ quotestart = s;
+ start = s+1;
+ for(int braktype = *s++, brak = 1;;)
+ {
+ s += strcspn(s, "\"/;()[]\0");
+ int c = *s++;
+ switch(c)
+ {
+ case '\0': s--; quoteend = end = s; return true;
+ case '"': s = parsestring(s); if(*s == '"') s++; break;
+ case '/': if(*s == '/') s += strcspn(s, "\n\0"); break;
+ case '(': case '[': if(c == braktype) brak++; break;
+ case ')': if(braktype == '(' && --brak <= 0) goto endblock; break;
+ case ']': if(braktype == '[' && --brak <= 0) goto endblock; break;
+ }
+ }
+ endblock:
+ end = s-1;
+ quoteend = s;
+ break;
+ case '\0': case ')': case ']': return false;
+ default: quotestart = start = s; s = parseword(s); quoteend = end = s; break;
+ }
+ skiplist(s);
+ if(*s == ';') s++;
+ return true;
}
void explodelist(const char *s, vector<char *> &elems, int limit)
{
- const char *start, *end;
- while((limit < 0 || elems.length() < limit) && parselist(s, start, end))
- elems.add(newstring(start, end-start));
+ const char *start, *end;
+ while((limit < 0 || elems.length() < limit) && parselist(s, start, end))
+ elems.add(newstring(start, end-start));
}
char *indexlist(const char *s, int pos)
{
- loopi(pos) if(!parselist(s)) return newstring("");
- const char *start, *end;
- return parselist(s, start, end) ? newstring(start, end-start) : newstring("");
+ loopi(pos) if(!parselist(s)) return newstring("");
+ const char *start, *end;
+ return parselist(s, start, end) ? newstring(start, end-start) : newstring("");
}
int listlen(const char *s)
{
- int n = 0;
- while(parselist(s)) n++;
- return n;
+ int n = 0;
+ while(parselist(s)) n++;
+ return n;
}
ICOMMAND(listlen, "s", (char *s), intret(listlen(s)));
void at(tagval *args, int numargs)
{
- if(!numargs) return;
- const char *start = args[0].getstr(), *end = start + strlen(start);
- for(int i = 1; i < numargs; i++)
- {
- const char *list = start;
- int pos = args[i].getint();
- for(; pos > 0; pos--) if(!parselist(list)) break;
- if(pos > 0 || !parselist(list, start, end)) start = end = "";
- }
- commandret->setstr(newstring(start, end-start));
+ if(!numargs) return;
+ const char *start = args[0].getstr(), *end = start + strlen(start);
+ for(int i = 1; i < numargs; i++)
+ {
+ const char *list = start;
+ int pos = args[i].getint();
+ for(; pos > 0; pos--) if(!parselist(list)) break;
+ if(pos > 0 || !parselist(list, start, end)) start = end = "";
+ }
+ commandret->setstr(newstring(start, end-start));
}
COMMAND(at, "si1V");
void substr(char *s, int *start, int *count, int *numargs)
{
- int len = strlen(s), offset = clamp(*start, 0, len);
- commandret->setstr(newstring(&s[offset], *numargs >= 3 ? clamp(*count, 0, len - offset) : len - offset));
+ int len = strlen(s), offset = clamp(*start, 0, len);
+ commandret->setstr(newstring(&s[offset], *numargs >= 3 ? clamp(*count, 0, len - offset) : len - offset));
}
COMMAND(substr, "siiN");
void chopstr(char *s, int *lim, char *ellipsis)
{
- int len = strlen(s), maxlen = abs(*lim);
- if(len > maxlen)
- {
- int elen = strlen(ellipsis);
- maxlen = max(maxlen, elen);
- char *chopped = newstring(maxlen);
- if(*lim < 0)
- {
- memcpy(chopped, ellipsis, elen);
- memcpy(&chopped[elen], &s[len - (maxlen - elen)], maxlen - elen);
- }
- else
- {
- memcpy(chopped, s, maxlen - elen);
- memcpy(&chopped[maxlen - elen], ellipsis, elen);
- }
- chopped[maxlen] = '\0';
- commandret->setstr(chopped);
- }
- else result(s);
+ int len = strlen(s), maxlen = abs(*lim);
+ if(len > maxlen)
+ {
+ int elen = strlen(ellipsis);
+ maxlen = max(maxlen, elen);
+ char *chopped = newstring(maxlen);
+ if(*lim < 0)
+ {
+ memcpy(chopped, ellipsis, elen);
+ memcpy(&chopped[elen], &s[len - (maxlen - elen)], maxlen - elen);
+ }
+ else
+ {
+ memcpy(chopped, s, maxlen - elen);
+ memcpy(&chopped[maxlen - elen], ellipsis, elen);
+ }
+ chopped[maxlen] = '\0';
+ commandret->setstr(chopped);
+ }
+ else result(s);
}
COMMAND(chopstr, "sis");
void sublist(const char *s, int *skip, int *count, int *numargs)
{
- int offset = max(*skip, 0), len = *numargs >= 3 ? max(*count, 0) : -1;
- loopi(offset) if(!parselist(s)) break;
- if(len < 0) { if(offset > 0) skiplist(s); commandret->setstr(newstring(s)); return; }
- const char *list = s, *start, *end, *qstart, *qend = s;
- if(len > 0 && parselist(s, start, end, list, qend)) while(--len > 0 && parselist(s, start, end, qstart, qend));
- commandret->setstr(newstring(list, qend - list));
+ int offset = max(*skip, 0), len = *numargs >= 3 ? max(*count, 0) : -1;
+ loopi(offset) if(!parselist(s)) break;
+ if(len < 0) { if(offset > 0) skiplist(s); commandret->setstr(newstring(s)); return; }
+ const char *list = s, *start, *end, *qstart, *qend = s;
+ if(len > 0 && parselist(s, start, end, list, qend)) while(--len > 0 && parselist(s, start, end, qstart, qend));
+ commandret->setstr(newstring(list, qend - list));
}
COMMAND(sublist, "siiN");
ICOMMAND(stripcolors, "s", (char *s),
{
- int len = strlen(s);
- char *d = newstring(len);
- filtertext(d, s, true, false, len);
- stringret(d);
+ int len = strlen(s);
+ char *d = newstring(len);
+ filtertext(d, s, true, false, len);
+ stringret(d);
});
static inline void setiter(ident &id, char *val, identstack &stack)
{
- if(id.stack == &stack)
- {
- if(id.valtype == VAL_STR) delete[] id.val.s;
- else id.valtype = VAL_STR;
- cleancode(id);
- id.val.s = val;
- }
- else
- {
- tagval t;
- t.setstr(val);
- pusharg(id, t, stack);
- id.flags &= ~IDF_UNKNOWN;
- }
+ if(id.stack == &stack)
+ {
+ if(id.valtype == VAL_STR) delete[] id.val.s;
+ else id.valtype = VAL_STR;
+ cleancode(id);
+ id.val.s = val;
+ }
+ else
+ {
+ tagval t;
+ t.setstr(val);
+ pusharg(id, t, stack);
+ id.flags &= ~IDF_UNKNOWN;
+ }
}
void listfind(ident *id, const char *list, const uint *body)
{
- if(id->type!=ID_ALIAS) { intret(-1); return; }
- identstack stack;
- int n = -1;
- for(const char *s = list, *start, *end; parselist(s, start, end);)
- {
- ++n;
- char *val = newstring(start, end-start);
- setiter(*id, val, stack);
- if(executebool(body)) { intret(n); goto found; }
- }
- intret(-1);
+ if(id->type!=ID_ALIAS) { intret(-1); return; }
+ identstack stack;
+ int n = -1;
+ for(const char *s = list, *start, *end; parselist(s, start, end);)
+ {
+ ++n;
+ char *val = newstring(start, end-start);
+ setiter(*id, val, stack);
+ if(executebool(body)) { intret(n); goto found; }
+ }
+ intret(-1);
found:
- if(n >= 0) poparg(*id);
+ if(n >= 0) poparg(*id);
}
COMMAND(listfind, "rse");
void looplist(ident *id, const char *list, const uint *body)
{
- if(id->type!=ID_ALIAS) return;
- identstack stack;
- int n = 0;
- for(const char *s = list, *start, *end; parselist(s, start, end); n++)
- {
- char *val = newstring(start, end-start);
- setiter(*id, val, stack);
- execute(body);
- }
- if(n) poparg(*id);
+ if(id->type!=ID_ALIAS) return;
+ identstack stack;
+ int n = 0;
+ for(const char *s = list, *start, *end; parselist(s, start, end); n++)
+ {
+ char *val = newstring(start, end-start);
+ setiter(*id, val, stack);
+ execute(body);
+ }
+ if(n) poparg(*id);
}
COMMAND(looplist, "rse");
void loopsublist(ident *id, const char *list, int *skip, int *count, const uint *body)
{
- if(id->type!=ID_ALIAS) return;
- identstack stack;
- int n = 0, offset = max(*skip, 0), len = *count < 0 ? INT_MAX : offset + *count;
- for(const char *s = list, *start, *end; parselist(s, start, end) && n < len; n++) if(n >= offset)
- {
- char *val = newstring(start, end-start);
- setiter(*id, val, stack);
- execute(body);
- }
- if(n) poparg(*id);
+ if(id->type!=ID_ALIAS) return;
+ identstack stack;
+ int n = 0, offset = max(*skip, 0), len = *count < 0 ? INT_MAX : offset + *count;
+ for(const char *s = list, *start, *end; parselist(s, start, end) && n < len; n++) if(n >= offset)
+ {
+ char *val = newstring(start, end-start);
+ setiter(*id, val, stack);
+ execute(body);
+ }
+ if(n) poparg(*id);
}
COMMAND(loopsublist, "rsiie");
void looplistconc(ident *id, const char *list, const uint *body, bool space)
{
- if(id->type!=ID_ALIAS) return;
- identstack stack;
- vector<char> r;
- int n = 0;
- for(const char *s = list, *start, *end; parselist(s, start, end); n++)
- {
- char *val = newstring(start, end-start);
- setiter(*id, val, stack);
-
- if(n && space) r.add(' ');
-
- tagval v;
- executeret(body, v);
- const char *vstr = v.getstr();
- int len = strlen(vstr);
- r.put(vstr, len);
- freearg(v);
- }
- if(n) poparg(*id);
- r.add('\0');
- commandret->setstr(newstring(r.getbuf(), r.length()-1));
+ if(id->type!=ID_ALIAS) return;
+ identstack stack;
+ vector<char> r;
+ int n = 0;
+ for(const char *s = list, *start, *end; parselist(s, start, end); n++)
+ {
+ char *val = newstring(start, end-start);
+ setiter(*id, val, stack);
+
+ if(n && space) r.add(' ');
+
+ tagval v;
+ executeret(body, v);
+ const char *vstr = v.getstr();
+ int len = strlen(vstr);
+ r.put(vstr, len);
+ freearg(v);
+ }
+ if(n) poparg(*id);
+ r.add('\0');
+ commandret->setstr(newstring(r.getbuf(), r.length()-1));
}
ICOMMAND(looplistconcat, "rse", (ident *id, char *list, uint *body), looplistconc(id, list, body, true));
ICOMMAND(looplistconcatword, "rse", (ident *id, char *list, uint *body), looplistconc(id, list, body, false));
void listfilter(ident *id, const char *list, const uint *body)
{
- if(id->type!=ID_ALIAS) return;
- identstack stack;
- vector<char> r;
- int n = 0;
- for(const char *s = list, *start, *end, *quotestart, *quoteend; parselist(s, start, end, quotestart, quoteend); n++)
- {
- char *val = newstring(start, end-start);
- setiter(*id, val, stack);
-
- if(executebool(body))
- {
- if(r.length()) r.add(' ');
- r.put(quotestart, quoteend-quotestart);
- }
- }
- if(n) poparg(*id);
- r.add('\0');
- commandret->setstr(newstring(r.getbuf(), r.length()-1));
+ if(id->type!=ID_ALIAS) return;
+ identstack stack;
+ vector<char> r;
+ int n = 0;
+ for(const char *s = list, *start, *end, *quotestart, *quoteend; parselist(s, start, end, quotestart, quoteend); n++)
+ {
+ char *val = newstring(start, end-start);
+ setiter(*id, val, stack);
+
+ if(executebool(body))
+ {
+ if(r.length()) r.add(' ');
+ r.put(quotestart, quoteend-quotestart);
+ }
+ }
+ if(n) poparg(*id);
+ r.add('\0');
+ commandret->setstr(newstring(r.getbuf(), r.length()-1));
}
COMMAND(listfilter, "rse");
void prettylist(const char *s, const char *conj)
{
- vector<char> p;
- const char *start, *end;
- for(int len = listlen(s), n = 0; parselist(s, start, end); n++)
- {
- p.put(start, end - start);
- if(n+1 < len)
- {
- if(len > 2 || !conj[0]) p.add(',');
- if(n+2 == len && conj[0])
- {
- p.add(' ');
- p.put(conj, strlen(conj));
- }
- p.add(' ');
- }
- }
- p.add('\0');
- result(p.getbuf());
+ vector<char> p;
+ const char *start, *end;
+ for(int len = listlen(s), n = 0; parselist(s, start, end); n++)
+ {
+ p.put(start, end - start);
+ if(n+1 < len)
+ {
+ if(len > 2 || !conj[0]) p.add(',');
+ if(n+2 == len && conj[0])
+ {
+ p.add(' ');
+ p.put(conj, strlen(conj));
+ }
+ p.add(' ');
+ }
+ }
+ p.add('\0');
+ result(p.getbuf());
}
COMMAND(prettylist, "ss");
int listincludes(const char *list, const char *needle, int needlelen)
{
- int offset = 0;
- for(const char *s = list, *start, *end; parselist(s, start, end);)
- {
- int len = end - start;
- if(needlelen == len && !strncmp(needle, start, len)) return offset;
- offset++;
- }
- return -1;
+ int offset = 0;
+ for(const char *s = list, *start, *end; parselist(s, start, end);)
+ {
+ int len = end - start;
+ if(needlelen == len && !strncmp(needle, start, len)) return offset;
+ offset++;
+ }
+ return -1;
}
ICOMMAND(indexof, "ss", (char *list, char *elem), intret(listincludes(list, elem, strlen(elem))));
char *listdel(const char *s, const char *del)
{
- vector<char> p;
- for(const char *start, *end, *qstart, *qend; parselist(s, start, end, qstart, qend);)
- {
- if(listincludes(del, start, end-start) < 0)
- {
- if(!p.empty()) p.add(' ');
- p.put(qstart, qend-qstart);
- }
- }
- p.add('\0');
- return newstring(p.getbuf(), p.length()-1);
+ vector<char> p;
+ for(const char *start, *end, *qstart, *qend; parselist(s, start, end, qstart, qend);)
+ {
+ if(listincludes(del, start, end-start) < 0)
+ {
+ if(!p.empty()) p.add(' ');
+ p.put(qstart, qend-qstart);
+ }
+ }
+ p.add('\0');
+ return newstring(p.getbuf(), p.length()-1);
}
ICOMMAND(listdel, "ss", (char *list, char *del), commandret->setstr(listdel(list, del)));
void listsplice(const char *s, const char *vals, int *skip, int *count)
{
- int offset = max(*skip, 0), len = max(*count, 0);
- const char *list = s, *start, *end, *qstart, *qend = s;
- loopi(offset) if(!parselist(s, start, end, qstart, qend)) break;
- vector<char> p;
- if(qend > list) p.put(list, qend-list);
- if(*vals)
- {
- if(!p.empty()) p.add(' ');
- p.put(vals, strlen(vals));
- }
- loopi(len) if(!parselist(s)) break;
- skiplist(s);
- switch(*s)
- {
- case '\0': case ')': case ']': break;
- default:
- if(!p.empty()) p.add(' ');
- p.put(s, strlen(s));
- break;
- }
- p.add('\0');
- commandret->setstr(newstring(p.getbuf(), p.length()-1));
+ int offset = max(*skip, 0), len = max(*count, 0);
+ const char *list = s, *start, *end, *qstart, *qend = s;
+ loopi(offset) if(!parselist(s, start, end, qstart, qend)) break;
+ vector<char> p;
+ if(qend > list) p.put(list, qend-list);
+ if(*vals)
+ {
+ if(!p.empty()) p.add(' ');
+ p.put(vals, strlen(vals));
+ }
+ loopi(len) if(!parselist(s)) break;
+ skiplist(s);
+ switch(*s)
+ {
+ case '\0': case ')': case ']': break;
+ default:
+ if(!p.empty()) p.add(' ');
+ p.put(s, strlen(s));
+ break;
+ }
+ p.add('\0');
+ commandret->setstr(newstring(p.getbuf(), p.length()-1));
}
COMMAND(listsplice, "ssii");
ICOMMAND(loopfiles, "rsse", (ident *id, char *dir, char *ext, uint *body),
{
- if(id->type!=ID_ALIAS) return;
- identstack stack;
- vector<char *> files;
- listfiles(dir, ext[0] ? ext : NULL, files);
- loopvrev(files)
- {
- char *file = files[i];
- bool redundant = false;
- loopj(i) if(!strcmp(files[j], file)) { redundant = true; break; }
- if(redundant) delete[] files.removeunordered(i);
- }
- loopv(files)
- {
- char *file = files[i];
- if(i)
- {
- if(id->valtype == VAL_STR) delete[] id->val.s;
- else id->valtype = VAL_STR;
- id->val.s = file;
- }
- else
- {
- tagval t;
- t.setstr(file);
- pusharg(*id, t, stack);
- id->flags &= ~IDF_UNKNOWN;
- }
- execute(body);
- }
- if(files.length()) poparg(*id);
+ if(id->type!=ID_ALIAS) return;
+ identstack stack;
+ vector<char *> files;
+ listfiles(dir, ext[0] ? ext : NULL, files);
+ loopvrev(files)
+ {
+ char *file = files[i];
+ bool redundant = false;
+ loopj(i) if(!strcmp(files[j], file)) { redundant = true; break; }
+ if(redundant) delete[] files.removeunordered(i);
+ }
+ loopv(files)
+ {
+ char *file = files[i];
+ if(i)
+ {
+ if(id->valtype == VAL_STR) delete[] id->val.s;
+ else id->valtype = VAL_STR;
+ id->val.s = file;
+ }
+ else
+ {
+ tagval t;
+ t.setstr(file);
+ pusharg(*id, t, stack);
+ id->flags &= ~IDF_UNKNOWN;
+ }
+ execute(body);
+ }
+ if(files.length()) poparg(*id);
});
void findfile_(char *name)
{
- string fname;
- copystring(fname, name);
- path(fname);
- intret(
+ string fname;
+ copystring(fname, name);
+ path(fname);
+ intret(
#ifndef STANDALONE
- findzipfile(fname) ||
+ findzipfile(fname) ||
#endif
- fileexists(fname, "e") || findfile(fname, "e") ? 1 : 0
- );
+ fileexists(fname, "e") || findfile(fname, "e") ? 1 : 0
+ );
}
COMMANDN(findfile, findfile_, "s");
struct sortitem
{
- const char *str, *quotestart, *quoteend;
+ const char *str, *quotestart, *quoteend;
};
struct sortfun
{
- ident *x, *y;
- uint *body;
-
- bool operator()(const sortitem &xval, const sortitem &yval)
- {
- if(x->valtype != VAL_MACRO) x->valtype = VAL_MACRO;
- cleancode(*x);
- x->val.code = (const uint *)xval.str;
- if(y->valtype != VAL_MACRO) y->valtype = VAL_MACRO;
- cleancode(*y);
- y->val.code = (const uint *)yval.str;
- return executebool(body);
- }
+ ident *x, *y;
+ uint *body;
+
+ bool operator()(const sortitem &xval, const sortitem &yval)
+ {
+ if(x->valtype != VAL_MACRO) x->valtype = VAL_MACRO;
+ cleancode(*x);
+ x->val.code = (const uint *)xval.str;
+ if(y->valtype != VAL_MACRO) y->valtype = VAL_MACRO;
+ cleancode(*y);
+ y->val.code = (const uint *)yval.str;
+ return executebool(body);
+ }
};
void sortlist(char *list, ident *x, ident *y, uint *body)
{
- if(x == y || x->type != ID_ALIAS || y->type != ID_ALIAS) return;
-
- vector<sortitem> items;
- int macrolen = strlen(list), total = 0;
- char *macros = newstring(list, macrolen);
- const char *curlist = list, *start, *end, *quotestart, *quoteend;
- while(parselist(curlist, start, end, quotestart, quoteend))
- {
- macros[end - list] = '\0';
- sortitem item = { &macros[start - list], quotestart, quoteend };
- items.add(item);
- total += int(quoteend - quotestart);
- }
-
- identstack xstack, ystack;
- pusharg(*x, nullval, xstack); x->flags &= ~IDF_UNKNOWN;
- pusharg(*y, nullval, ystack); y->flags &= ~IDF_UNKNOWN;
-
- sortfun f = { x, y, body };
- items.sort(f);
-
- poparg(*x);
- poparg(*y);
-
- char *sorted = macros;
- int sortedlen = total + max(items.length() - 1, 0);
- if(macrolen < sortedlen)
- {
- delete[] macros;
- sorted = newstring(sortedlen);
- }
-
- int offset = 0;
- loopv(items)
- {
- sortitem &item = items[i];
- int len = int(item.quoteend - item.quotestart);
- if(i) sorted[offset++] = ' ';
- memcpy(&sorted[offset], item.quotestart, len);
- offset += len;
- }
- sorted[offset] = '\0';
-
- commandret->setstr(sorted);
+ if(x == y || x->type != ID_ALIAS || y->type != ID_ALIAS) return;
+
+ vector<sortitem> items;
+ int macrolen = strlen(list), total = 0;
+ char *macros = newstring(list, macrolen);
+ const char *curlist = list, *start, *end, *quotestart, *quoteend;
+ while(parselist(curlist, start, end, quotestart, quoteend))
+ {
+ macros[end - list] = '\0';
+ sortitem item = { &macros[start - list], quotestart, quoteend };
+ items.add(item);
+ total += int(quoteend - quotestart);
+ }
+
+ identstack xstack, ystack;
+ pusharg(*x, nullval, xstack); x->flags &= ~IDF_UNKNOWN;
+ pusharg(*y, nullval, ystack); y->flags &= ~IDF_UNKNOWN;
+
+ sortfun f = { x, y, body };
+ items.sort(f);
+
+ poparg(*x);
+ poparg(*y);
+
+ char *sorted = macros;
+ int sortedlen = total + max(items.length() - 1, 0);
+ if(macrolen < sortedlen)
+ {
+ delete[] macros;
+ sorted = newstring(sortedlen);
+ }
+
+ int offset = 0;
+ loopv(items)
+ {
+ sortitem &item = items[i];
+ int len = int(item.quoteend - item.quotestart);
+ if(i) sorted[offset++] = ' ';
+ memcpy(&sorted[offset], item.quotestart, len);
+ offset += len;
+ }
+ sorted[offset] = '\0';
+
+ commandret->setstr(sorted);
}
COMMAND(sortlist, "srre");
@@ -3212,23 +3212,23 @@ ICOMMAND(<<, "ii", (int *a, int *b), intret(*b < 32 ? *a << max(*b, 0) : 0));
ICOMMAND(>>, "ii", (int *a, int *b), intret(*a >> clamp(*b, 0, 31)));
ICOMMAND(&&, "e1V", (tagval *args, int numargs),
{
- if(!numargs) intret(1);
- else loopi(numargs)
- {
- if(i) freearg(*commandret);
- executeret(args[i].code, *commandret);
- if(!getbool(*commandret)) break;
- }
+ if(!numargs) intret(1);
+ else loopi(numargs)
+ {
+ if(i) freearg(*commandret);
+ executeret(args[i].code, *commandret);
+ if(!getbool(*commandret)) break;
+ }
});
ICOMMAND(||, "e1V", (tagval *args, int numargs),
{
- if(!numargs) intret(0);
- else loopi(numargs)
- {
- if(i) freearg(*commandret);
- executeret(args[i].code, *commandret);
- if(getbool(*commandret)) break;
- }
+ if(!numargs) intret(0);
+ else loopi(numargs)
+ {
+ if(i) freearg(*commandret);
+ executeret(args[i].code, *commandret);
+ if(getbool(*commandret)) break;
+ }
});
ICOMMAND(div, "ii", (int *a, int *b), intret(*b ? *a / *b : 0));
@@ -3250,27 +3250,27 @@ ICOMMAND(log10, "f", (float *a), floatret(log10(*a)));
ICOMMAND(exp, "f", (float *a), floatret(exp(*a)));
ICOMMAND(min, "V", (tagval *args, int numargs),
{
- int val = numargs > 0 ? args[numargs - 1].getint() : 0;
- loopi(numargs - 1) val = min(val, args[i].getint());
- intret(val);
+ int val = numargs > 0 ? args[numargs - 1].getint() : 0;
+ loopi(numargs - 1) val = min(val, args[i].getint());
+ intret(val);
});
ICOMMAND(max, "V", (tagval *args, int numargs),
{
- int val = numargs > 0 ? args[numargs - 1].getint() : 0;
- loopi(numargs - 1) val = max(val, args[i].getint());
- intret(val);
+ int val = numargs > 0 ? args[numargs - 1].getint() : 0;
+ loopi(numargs - 1) val = max(val, args[i].getint());
+ intret(val);
});
ICOMMAND(minf, "V", (tagval *args, int numargs),
{
- float val = numargs > 0 ? args[numargs - 1].getfloat() : 0.0f;
- loopi(numargs - 1) val = min(val, args[i].getfloat());
- floatret(val);
+ float val = numargs > 0 ? args[numargs - 1].getfloat() : 0.0f;
+ loopi(numargs - 1) val = min(val, args[i].getfloat());
+ floatret(val);
});
ICOMMAND(maxf, "V", (tagval *args, int numargs),
{
- float val = numargs > 0 ? args[numargs - 1].getfloat() : 0.0f;
- loopi(numargs - 1) val = max(val, args[i].getfloat());
- floatret(val);
+ float val = numargs > 0 ? args[numargs - 1].getfloat() : 0.0f;
+ loopi(numargs - 1) val = max(val, args[i].getfloat());
+ floatret(val);
});
ICOMMAND(abs, "i", (int *n), intret(abs(*n)));
ICOMMAND(absf, "f", (float *n), floatret(fabs(*n)));
@@ -3279,50 +3279,50 @@ ICOMMAND(floor, "f", (float *n), floatret(floor(*n)));
ICOMMAND(ceil, "f", (float *n), floatret(ceil(*n)));
ICOMMAND(round, "ff", (float *n, float *k),
{
- double step = *k;
- double r = *n;
- if(step > 0)
- {
- r += step * (r < 0 ? -0.5 : 0.5);
- r -= fmod(r, step);
- }
- else r = r < 0 ? ceil(r - 0.5) : floor(r + 0.5);
- floatret(float(r));
+ double step = *k;
+ double r = *n;
+ if(step > 0)
+ {
+ r += step * (r < 0 ? -0.5 : 0.5);
+ r -= fmod(r, step);
+ }
+ else r = r < 0 ? ceil(r - 0.5) : floor(r + 0.5);
+ floatret(float(r));
});
ICOMMAND(cond, "ee2V", (tagval *args, int numargs),
{
- for(int i = 0; i < numargs; i += 2)
- {
- if(i+1 < numargs)
- {
- if(executebool(args[i].code))
- {
- executeret(args[i+1].code, *commandret);
- break;
- }
- }
- else
- {
- executeret(args[i].code, *commandret);
- break;
- }
- }
+ for(int i = 0; i < numargs; i += 2)
+ {
+ if(i+1 < numargs)
+ {
+ if(executebool(args[i].code))
+ {
+ executeret(args[i+1].code, *commandret);
+ break;
+ }
+ }
+ else
+ {
+ executeret(args[i].code, *commandret);
+ break;
+ }
+ }
});
#define CASECOMMAND(name, fmt, type, acc, compare) \
- ICOMMAND(name, fmt "te2V", (tagval *args, int numargs), \
- { \
- type val = acc; \
- int i; \
- for(i = 1; i+1 < numargs; i += 2) \
- { \
- if(compare) \
- { \
- executeret(args[i+1].code, *commandret); \
- return; \
- } \
- } \
- })
+ ICOMMAND(name, fmt "te2V", (tagval *args, int numargs), \
+ { \
+ type val = acc; \
+ int i; \
+ for(i = 1; i+1 < numargs; i += 2) \
+ { \
+ if(compare) \
+ { \
+ executeret(args[i+1].code, *commandret); \
+ return; \
+ } \
+ } \
+ })
CASECOMMAND(case, "i", int, args[0].getint(), args[i].type == VAL_NULL || args[i].getint() == val);
CASECOMMAND(casef, "f", float, args[0].getfloat(), args[i].type == VAL_NULL || args[i].getfloat() == val);
CASECOMMAND(cases, "s", const char *, args[0].getstr(), args[i].type == VAL_NULL || !strcmp(args[i].getstr(), val));
@@ -3330,19 +3330,19 @@ CASECOMMAND(cases, "s", const char *, args[0].getstr(), args[i].type == VAL_NULL
ICOMMAND(rnd, "ii", (int *a, int *b), intret(*a - *b > 0 ? rnd(*a - *b) + *b : *b));
ICOMMAND(rndstr, "i", (int *len),
{
- int n = clamp(*len, 0, 10000);
- char *s = newstring(n);
- for(int i = 0; i < n;)
- {
- uint r = randomMT();
- for(int j = min(i + 4, n); i < j; i++)
- {
- s[i] = (r%255) + 1;
- r /= 255;
- }
- }
- s[n] = '\0';
- stringret(s);
+ int n = clamp(*len, 0, 10000);
+ char *s = newstring(n);
+ for(int i = 0; i < n;)
+ {
+ uint r = randomMT();
+ for(int j = min(i + 4, n); i < j; i++)
+ {
+ s[i] = (r%255) + 1;
+ r /= 255;
+ }
+ }
+ s[n] = '\0';
+ stringret(s);
});
ICOMMAND(strcmp, "ss", (char *a, char *b), intret(strcmp(a,b)==0));
@@ -3363,80 +3363,80 @@ ICOMMAND(unistr, "i", (int *i), { char *s = newstring(1); s[0] = uni2cube(*i); s
int naturalsort(const char *a, const char *b)
{
- for(;;)
- {
- int ac = *a, bc = *b;
- if(!ac) return bc ? -1 : 0;
- else if(!bc) return 1;
- else if(isdigit(ac) && isdigit(bc))
- {
- while(*a == '0') a++;
- while(*b == '0') b++;
- const char *a0 = a, *b0 = b;
- while(isdigit(*a)) a++;
- while(isdigit(*b)) b++;
- int alen = a - a0, blen = b - b0;
- if(alen != blen) return alen - blen;
- int n = memcmp(a0, b0, alen);
- if(n < 0) return -1;
- else if(n > 0) return 1;
- }
- else if(ac != bc) return ac - bc;
- else { ++a; ++b; }
- }
+ for(;;)
+ {
+ int ac = *a, bc = *b;
+ if(!ac) return bc ? -1 : 0;
+ else if(!bc) return 1;
+ else if(isdigit(ac) && isdigit(bc))
+ {
+ while(*a == '0') a++;
+ while(*b == '0') b++;
+ const char *a0 = a, *b0 = b;
+ while(isdigit(*a)) a++;
+ while(isdigit(*b)) b++;
+ int alen = a - a0, blen = b - b0;
+ if(alen != blen) return alen - blen;
+ int n = memcmp(a0, b0, alen);
+ if(n < 0) return -1;
+ else if(n > 0) return 1;
+ }
+ else if(ac != bc) return ac - bc;
+ else { ++a; ++b; }
+ }
}
ICOMMAND(naturalsort, "ss", (char *a, char *b), intret(naturalsort(a,b)<=0));
#define STRMAPCOMMAND(name, map) \
- ICOMMAND(name, "s", (char *s), \
- { \
- int len = strlen(s); \
- char *m = newstring(len); \
- loopi(len) m[i] = map(s[i]); \
- m[len] = '\0'; \
- stringret(m); \
- })
+ ICOMMAND(name, "s", (char *s), \
+ { \
+ int len = strlen(s); \
+ char *m = newstring(len); \
+ loopi(len) m[i] = map(s[i]); \
+ m[len] = '\0'; \
+ stringret(m); \
+ })
STRMAPCOMMAND(strlower, cubelower);
STRMAPCOMMAND(strupper, cubeupper);
char *strreplace(const char *s, const char *oldval, const char *newval)
{
- vector<char> buf;
-
- int oldlen = strlen(oldval);
- if(!oldlen) return newstring(s);
- for(;;)
- {
- const char *found = strstr(s, oldval);
- if(found)
- {
- while(s < found) buf.add(*s++);
- for(const char *n = newval; *n; n++) buf.add(*n);
- s = found + oldlen;
- }
- else
- {
- while(*s) buf.add(*s++);
- buf.add('\0');
- return newstring(buf.getbuf(), buf.length());
- }
- }
+ vector<char> buf;
+
+ int oldlen = strlen(oldval);
+ if(!oldlen) return newstring(s);
+ for(;;)
+ {
+ const char *found = strstr(s, oldval);
+ if(found)
+ {
+ while(s < found) buf.add(*s++);
+ for(const char *n = newval; *n; n++) buf.add(*n);
+ s = found + oldlen;
+ }
+ else
+ {
+ while(*s) buf.add(*s++);
+ buf.add('\0');
+ return newstring(buf.getbuf(), buf.length());
+ }
+ }
}
ICOMMAND(strreplace, "sss", (char *s, char *o, char *n), commandret->setstr(strreplace(s, o, n)));
void strsplice(const char *s, const char *vals, int *skip, int *count)
{
- int slen = strlen(s), vlen = strlen(vals),
- offset = clamp(*skip, 0, slen),
- len = clamp(*count, 0, slen - offset);
- char *p = newstring(slen - len + vlen);
- if(offset) memcpy(p, s, offset);
- if(vlen) memcpy(&p[offset], vals, vlen);
- if(offset + len < slen) memcpy(&p[offset + vlen], &s[offset + len], slen - (offset + len));
- p[slen - len + vlen] = '\0';
- commandret->setstr(p);
+ int slen = strlen(s), vlen = strlen(vals),
+ offset = clamp(*skip, 0, slen),
+ len = clamp(*count, 0, slen - offset);
+ char *p = newstring(slen - len + vlen);
+ if(offset) memcpy(p, s, offset);
+ if(vlen) memcpy(&p[offset], vals, vlen);
+ if(offset + len < slen) memcpy(&p[offset + vlen], &s[offset + len], slen - (offset + len));
+ p[slen - len + vlen] = '\0';
+ commandret->setstr(p);
}
COMMAND(strsplice, "ssii");
@@ -3445,55 +3445,55 @@ ICOMMAND(getmillis, "i", (int *total), intret(*total ? totalmillis : lastmillis)
struct sleepcmd
{
- int delay, millis, flags;
- char *command;
+ int delay, millis, flags;
+ char *command;
};
vector<sleepcmd> sleepcmds;
void addsleep(int *msec, char *cmd)
{
- sleepcmd &s = sleepcmds.add();
- s.delay = max(*msec, 1);
- s.millis = lastmillis;
- s.command = newstring(cmd);
- s.flags = identflags;
+ sleepcmd &s = sleepcmds.add();
+ s.delay = max(*msec, 1);
+ s.millis = lastmillis;
+ s.command = newstring(cmd);
+ s.flags = identflags;
}
COMMANDN(sleep, addsleep, "is");
void checksleep(int millis)
{
- loopv(sleepcmds)
- {
- sleepcmd &s = sleepcmds[i];
- if(millis - s.millis >= s.delay)
- {
- char *cmd = s.command; // execute might create more sleep commands
- s.command = NULL;
- int oldflags = identflags;
- identflags = s.flags;
- execute(cmd);
- identflags = oldflags;
- delete[] cmd;
- if(sleepcmds.inrange(i) && !sleepcmds[i].command) sleepcmds.remove(i--);
- }
- }
+ loopv(sleepcmds)
+ {
+ sleepcmd &s = sleepcmds[i];
+ if(millis - s.millis >= s.delay)
+ {
+ char *cmd = s.command; // execute might create more sleep commands
+ s.command = NULL;
+ int oldflags = identflags;
+ identflags = s.flags;
+ execute(cmd);
+ identflags = oldflags;
+ delete[] cmd;
+ if(sleepcmds.inrange(i) && !sleepcmds[i].command) sleepcmds.remove(i--);
+ }
+ }
}
void clearsleep(bool clearoverrides)
{
- int len = 0;
- loopv(sleepcmds) if(sleepcmds[i].command)
- {
- if(clearoverrides && !(sleepcmds[i].flags&IDF_OVERRIDDEN)) sleepcmds[len++] = sleepcmds[i];
- else delete[] sleepcmds[i].command;
- }
- sleepcmds.shrink(len);
+ int len = 0;
+ loopv(sleepcmds) if(sleepcmds[i].command)
+ {
+ if(clearoverrides && !(sleepcmds[i].flags&IDF_OVERRIDDEN)) sleepcmds[len++] = sleepcmds[i];
+ else delete[] sleepcmds[i].command;
+ }
+ sleepcmds.shrink(len);
}
void clearsleep_(int *clearoverrides)
{
- clearsleep(*clearoverrides!=0 || identflags&IDF_OVERRIDDEN);
+ clearsleep(*clearoverrides!=0 || identflags&IDF_OVERRIDDEN);
}
COMMANDN(clearsleep, clearsleep_, "i");