Start migrating commands / variables to ObjC++
FossilOrigin-Name: f4c57c1df00e1fed4dd28bbac2f4862e2a58ddfbfbddb17c56abab386d115ccb
This commit is contained in:
parent
0bbe1c8bee
commit
faf0a4096e
1 changed files with 388 additions and 287 deletions
675
src/command.mm
675
src/command.mm
|
@ -5,96 +5,137 @@
|
||||||
|
|
||||||
enum { ID_VAR, ID_COMMAND, ID_ALIAS };
|
enum { ID_VAR, ID_COMMAND, ID_ALIAS };
|
||||||
|
|
||||||
struct ident {
|
@interface Ident : OFObject
|
||||||
int type; // one of ID_* above
|
@property(nonatomic) int type; // one of ID_* above
|
||||||
char *name;
|
@property(nonatomic) char *name;
|
||||||
int min, max; // ID_VAR
|
@property(nonatomic) int min, max; // ID_VAR
|
||||||
int *storage; // ID_VAR
|
@property(nonatomic) int *storage; // ID_VAR
|
||||||
void (*fun)(); // ID_VAR, ID_COMMAND
|
@property(nonatomic) void (*fun)(); // ID_VAR, ID_COMMAND
|
||||||
int narg; // ID_VAR, ID_COMMAND
|
@property(nonatomic) int narg; // ID_VAR, ID_COMMAND
|
||||||
char *action; // ID_ALIAS
|
@property(nonatomic) char *action; // ID_ALIAS
|
||||||
bool persist;
|
@property(nonatomic) bool persist;
|
||||||
};
|
@end
|
||||||
|
|
||||||
|
@implementation Ident
|
||||||
|
@end
|
||||||
|
|
||||||
void
|
void
|
||||||
itoa(char *s, int i)
|
itoa(char *s, int i)
|
||||||
{
|
{
|
||||||
sprintf_s(s)("%d", i);
|
sprintf_s(s)("%d", i);
|
||||||
};
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
exchangestr(char *o, char *n)
|
exchangestr(char *o, char *n)
|
||||||
{
|
{
|
||||||
gp()->deallocstr(o);
|
gp()->deallocstr(o);
|
||||||
return newstring(n);
|
return newstring(n);
|
||||||
};
|
}
|
||||||
|
|
||||||
hashtable<ident> *idents = NULL; // contains ALL vars/commands/aliases
|
// contains ALL vars/commands/aliases
|
||||||
|
OFMutableDictionary<OFString *, Ident *> *idents;
|
||||||
|
|
||||||
void
|
void
|
||||||
alias(char *name, char *action)
|
alias(char *name, char *action)
|
||||||
{
|
{
|
||||||
ident *b = idents->access(name);
|
@autoreleasepool {
|
||||||
if (!b) {
|
Ident *b = idents[@(name)];
|
||||||
name = newstring(name);
|
|
||||||
ident b = {
|
|
||||||
ID_ALIAS, name, 0, 0, 0, 0, 0, newstring(action), true};
|
|
||||||
idents->access(name, &b);
|
|
||||||
} else {
|
|
||||||
if (b->type == ID_ALIAS)
|
|
||||||
b->action = exchangestr(b->action, action);
|
|
||||||
else
|
|
||||||
conoutf(
|
|
||||||
"cannot redefine builtin %s with an alias", name);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
COMMAND(alias, ARG_2STR);
|
if (!b) {
|
||||||
|
Ident *b = [[Ident alloc] init];
|
||||||
|
b.type = ID_ALIAS;
|
||||||
|
b.name = newstring(name);
|
||||||
|
b.action = newstring(action);
|
||||||
|
b.persist = true;
|
||||||
|
|
||||||
// variable's and commands are registered through globals, see cube.h
|
idents[@(name)] = b;
|
||||||
|
} else {
|
||||||
|
if (b.type == ID_ALIAS)
|
||||||
|
b.action = exchangestr(b.action, action);
|
||||||
|
else
|
||||||
|
conoutf(
|
||||||
|
"cannot redefine builtin %s with an alias",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND(alias, ARG_2STR)
|
||||||
|
|
||||||
int
|
int
|
||||||
variable(char *name, int min, int cur, int max, int *storage, void (*fun)(),
|
variable(char *name, int min, int cur, int max, int *storage, void (*fun)(),
|
||||||
bool persist)
|
bool persist)
|
||||||
{
|
{
|
||||||
if (!idents)
|
if (idents == nil)
|
||||||
idents = new hashtable<ident>;
|
idents = [[OFMutableDictionary alloc] init];
|
||||||
ident v = {ID_VAR, name, min, max, storage, fun, 0, 0, persist};
|
|
||||||
idents->access(name, &v);
|
@autoreleasepool {
|
||||||
|
Ident *v = [[Ident alloc] init];
|
||||||
|
v.type = ID_VAR;
|
||||||
|
v.name = name;
|
||||||
|
v.min = min;
|
||||||
|
v.max = max;
|
||||||
|
v.storage = storage;
|
||||||
|
v.fun = fun;
|
||||||
|
v.persist = persist;
|
||||||
|
|
||||||
|
idents[@(name)] = v;
|
||||||
|
}
|
||||||
|
|
||||||
return cur;
|
return cur;
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
setvar(char *name, int i)
|
setvar(char *name, int i)
|
||||||
{
|
{
|
||||||
*idents->access(name)->storage = i;
|
@autoreleasepool {
|
||||||
};
|
*idents[@(name)].storage = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
getvar(char *name)
|
getvar(char *name)
|
||||||
{
|
{
|
||||||
return *idents->access(name)->storage;
|
@autoreleasepool {
|
||||||
};
|
return *idents[@(name)].storage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
identexists(char *name)
|
identexists(char *name)
|
||||||
{
|
{
|
||||||
return idents->access(name) != NULL;
|
@autoreleasepool {
|
||||||
};
|
return (idents[@(name)] != nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
getalias(char *name)
|
getalias(char *name)
|
||||||
{
|
{
|
||||||
ident *i = idents->access(name);
|
@autoreleasepool {
|
||||||
return i && i->type == ID_ALIAS ? i->action : NULL;
|
Ident *i = idents[@(name)];
|
||||||
};
|
return i != nil && i.type == ID_ALIAS ? i.action : NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
addcommand(char *name, void (*fun)(), int narg)
|
addcommand(char *name, void (*fun)(), int narg)
|
||||||
{
|
{
|
||||||
if (!idents)
|
if (idents == nil)
|
||||||
idents = new hashtable<ident>;
|
idents = [[OFMutableDictionary alloc] init];
|
||||||
ident c = {ID_COMMAND, name, 0, 0, 0, fun, narg, 0, false};
|
|
||||||
idents->access(name, &c);
|
@autoreleasepool {
|
||||||
|
Ident *c = [[Ident alloc] init];
|
||||||
|
c.type = ID_COMMAND;
|
||||||
|
c.name = name;
|
||||||
|
c.fun = fun;
|
||||||
|
c.narg = narg;
|
||||||
|
|
||||||
|
idents[@(name)] = c;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
parseexp(char *&p, int right) // parse any nested set of () or []
|
parseexp(char *&p, int right) // parse any nested set of () or []
|
||||||
|
@ -113,8 +154,8 @@ parseexp(char *&p, int right) // parse any nested set of () or []
|
||||||
p--;
|
p--;
|
||||||
conoutf("missing \"%c\"", right);
|
conoutf("missing \"%c\"", right);
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
char *s = newstring(word, p - word - 1);
|
char *s = newstring(word, p - word - 1);
|
||||||
if (left == '(') {
|
if (left == '(') {
|
||||||
string t;
|
string t;
|
||||||
|
@ -122,9 +163,9 @@ parseexp(char *&p, int right) // parse any nested set of () or []
|
||||||
execute(
|
execute(
|
||||||
s)); // evaluate () exps directly, and substitute result
|
s)); // evaluate () exps directly, and substitute result
|
||||||
s = exchangestr(s, t);
|
s = exchangestr(s, t);
|
||||||
};
|
}
|
||||||
return s;
|
return s;
|
||||||
};
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
parseword(char *&p) // parse single argument, including expressions
|
parseword(char *&p) // parse single argument, including expressions
|
||||||
|
@ -140,7 +181,7 @@ parseword(char *&p) // parse single argument, including expressions
|
||||||
if (*p == '\"')
|
if (*p == '\"')
|
||||||
p++;
|
p++;
|
||||||
return s;
|
return s;
|
||||||
};
|
}
|
||||||
if (*p == '(')
|
if (*p == '(')
|
||||||
return parseexp(p, ')');
|
return parseexp(p, ')');
|
||||||
if (*p == '[')
|
if (*p == '[')
|
||||||
|
@ -150,24 +191,29 @@ parseword(char *&p) // parse single argument, including expressions
|
||||||
if (p - word == 0)
|
if (p - word == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
return newstring(word, p - word);
|
return newstring(word, p - word);
|
||||||
};
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
lookup(char *n) // find value of ident referenced with $ in exp
|
lookup(char *n) // find value of ident referenced with $ in exp
|
||||||
{
|
{
|
||||||
ident *ID = idents->access(n + 1);
|
@autoreleasepool {
|
||||||
if (ID)
|
Ident *ID = idents[@(n + 1)];
|
||||||
switch (ID->type) {
|
|
||||||
case ID_VAR:
|
if (ID != nil) {
|
||||||
string t;
|
switch (ID.type) {
|
||||||
itoa(t, *(ID->storage));
|
case ID_VAR:
|
||||||
return exchangestr(n, t);
|
string t;
|
||||||
case ID_ALIAS:
|
itoa(t, *(ID.storage));
|
||||||
return exchangestr(n, ID->action);
|
return exchangestr(n, t);
|
||||||
};
|
case ID_ALIAS:
|
||||||
|
return exchangestr(n, ID.action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
conoutf("unknown alias lookup: %s", n + 1);
|
conoutf("unknown alias lookup: %s", n + 1);
|
||||||
return n;
|
return n;
|
||||||
};
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
execute(char *p, bool isdown) // all evaluation happens here, recursively
|
execute(char *p, bool isdown) // all evaluation happens here, recursively
|
||||||
|
@ -187,11 +233,11 @@ execute(char *p, bool isdown) // all evaluation happens here, recursively
|
||||||
if (!s) {
|
if (!s) {
|
||||||
numargs = i;
|
numargs = i;
|
||||||
s = "";
|
s = "";
|
||||||
};
|
}
|
||||||
if (*s == '$')
|
if (*s == '$')
|
||||||
s = lookup(s); // substitute variables
|
s = lookup(s); // substitute variables
|
||||||
w[i] = s;
|
w[i] = s;
|
||||||
};
|
}
|
||||||
|
|
||||||
p += strcspn(p, ";\n\0");
|
p += strcspn(p, ";\n\0");
|
||||||
cont = *p++ !=
|
cont = *p++ !=
|
||||||
|
@ -202,186 +248,234 @@ execute(char *p, bool isdown) // all evaluation happens here, recursively
|
||||||
if (!*c)
|
if (!*c)
|
||||||
continue; // empty statement
|
continue; // empty statement
|
||||||
|
|
||||||
ident *ID = idents->access(c);
|
@autoreleasepool {
|
||||||
if (!ID) {
|
Ident *ID = idents[@(c)];
|
||||||
val = ATOI(c);
|
|
||||||
if (!val && *c != '0')
|
if (ID == nil) {
|
||||||
conoutf("unknown command: %s", c);
|
val = ATOI(c);
|
||||||
} else
|
if (!val && *c != '0')
|
||||||
switch (ID->type) {
|
conoutf("unknown command: %s", c);
|
||||||
case ID_COMMAND: // game defined commands
|
} else {
|
||||||
switch (ID->narg) // use very ad-hoc function
|
switch (ID.type) {
|
||||||
// signature, and just call it
|
// game defined commands
|
||||||
{
|
case ID_COMMAND:
|
||||||
case ARG_1INT:
|
// use very ad-hoc function signature,
|
||||||
if (isdown)
|
// and just call it
|
||||||
((void(__cdecl *)(int))ID->fun)(
|
switch (ID.narg) {
|
||||||
ATOI(w[1]));
|
case ARG_1INT:
|
||||||
break;
|
if (isdown)
|
||||||
case ARG_2INT:
|
((void(__cdecl *)(
|
||||||
if (isdown)
|
int))ID.fun)(
|
||||||
((void(__cdecl *)(
|
ATOI(w[1]));
|
||||||
int, int))ID->fun)(
|
|
||||||
ATOI(w[1]), ATOI(w[2]));
|
|
||||||
break;
|
|
||||||
case ARG_3INT:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)(int, int,
|
|
||||||
int))ID->fun)(ATOI(w[1]),
|
|
||||||
ATOI(w[2]), ATOI(w[3]));
|
|
||||||
break;
|
|
||||||
case ARG_4INT:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)(int, int, int,
|
|
||||||
int))ID->fun)(ATOI(w[1]),
|
|
||||||
ATOI(w[2]), ATOI(w[3]),
|
|
||||||
ATOI(w[4]));
|
|
||||||
break;
|
|
||||||
case ARG_NONE:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)())ID->fun)();
|
|
||||||
break;
|
|
||||||
case ARG_1STR:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)(
|
|
||||||
char *))ID->fun)(w[1]);
|
|
||||||
break;
|
|
||||||
case ARG_2STR:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)(
|
|
||||||
char *, char *))ID->fun)(
|
|
||||||
w[1], w[2]);
|
|
||||||
break;
|
|
||||||
case ARG_3STR:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)(char *,
|
|
||||||
char *, char *))ID->fun)(
|
|
||||||
w[1], w[2], w[3]);
|
|
||||||
break;
|
|
||||||
case ARG_5STR:
|
|
||||||
if (isdown)
|
|
||||||
((void(__cdecl *)(char *,
|
|
||||||
char *, char *, char *,
|
|
||||||
char *))ID->fun)(w[1], w[2],
|
|
||||||
w[3], w[4], w[5]);
|
|
||||||
break;
|
|
||||||
case ARG_DOWN:
|
|
||||||
((void(__cdecl *)(bool))ID->fun)(
|
|
||||||
isdown);
|
|
||||||
break;
|
|
||||||
case ARG_DWN1:
|
|
||||||
((void(__cdecl *)(bool,
|
|
||||||
char *))ID->fun)(isdown, w[1]);
|
|
||||||
break;
|
|
||||||
case ARG_1EXP:
|
|
||||||
if (isdown)
|
|
||||||
val = ((int(__cdecl *)(
|
|
||||||
int))ID->fun)(
|
|
||||||
execute(w[1]));
|
|
||||||
break;
|
|
||||||
case ARG_2EXP:
|
|
||||||
if (isdown)
|
|
||||||
val = ((int(__cdecl *)(int,
|
|
||||||
int))ID->fun)(execute(w[1]),
|
|
||||||
execute(w[2]));
|
|
||||||
break;
|
|
||||||
case ARG_1EST:
|
|
||||||
if (isdown)
|
|
||||||
val = ((int(__cdecl *)(
|
|
||||||
char *))ID->fun)(w[1]);
|
|
||||||
break;
|
|
||||||
case ARG_2EST:
|
|
||||||
if (isdown)
|
|
||||||
val = ((int(__cdecl *)(
|
|
||||||
char *, char *))ID->fun)(
|
|
||||||
w[1], w[2]);
|
|
||||||
break;
|
|
||||||
case ARG_VARI:
|
|
||||||
if (isdown) {
|
|
||||||
string r; // limit, remove
|
|
||||||
r[0] = 0;
|
|
||||||
for (int i = 1; i < numargs;
|
|
||||||
i++) {
|
|
||||||
strcat_s(r,
|
|
||||||
w[i]); // make
|
|
||||||
// string-list
|
|
||||||
// out of all
|
|
||||||
// arguments
|
|
||||||
if (i == numargs - 1)
|
|
||||||
break;
|
|
||||||
strcat_s(r, " ");
|
|
||||||
};
|
|
||||||
((void(__cdecl *)(
|
|
||||||
char *))ID->fun)(r);
|
|
||||||
break;
|
break;
|
||||||
}
|
case ARG_2INT:
|
||||||
};
|
if (isdown)
|
||||||
break;
|
((void(__cdecl *)(
|
||||||
|
int, int))ID.fun)(
|
||||||
case ID_VAR: // game defined variabled
|
ATOI(w[1]),
|
||||||
if (isdown) {
|
ATOI(w[2]));
|
||||||
if (!w[1][0])
|
break;
|
||||||
conoutf("%s = %d", c,
|
case ARG_3INT:
|
||||||
*ID->storage); // var with
|
if (isdown)
|
||||||
// no value
|
((void(__cdecl *)(int,
|
||||||
// just
|
int, int))ID.fun)(
|
||||||
// prints its
|
ATOI(w[1]),
|
||||||
// current
|
ATOI(w[2]),
|
||||||
// value
|
ATOI(w[3]));
|
||||||
else {
|
break;
|
||||||
if (ID->min > ID->max) {
|
case ARG_4INT:
|
||||||
conoutf("variable is "
|
if (isdown)
|
||||||
"read-only");
|
((void(__cdecl *)(int,
|
||||||
} else {
|
int, int,
|
||||||
int i1 = ATOI(w[1]);
|
int))ID.fun)(
|
||||||
if (i1 < ID->min ||
|
ATOI(w[1]),
|
||||||
i1 > ID->max) {
|
ATOI(w[2]),
|
||||||
i1 =
|
ATOI(w[3]),
|
||||||
i1 < ID->min
|
ATOI(w[4]));
|
||||||
? ID->min
|
break;
|
||||||
: ID->max; // clamp to valid range
|
case ARG_NONE:
|
||||||
conoutf(
|
if (isdown)
|
||||||
"valid "
|
((void(__cdecl *)())
|
||||||
"range for "
|
ID.fun)();
|
||||||
"%s is "
|
break;
|
||||||
"%d..%d",
|
case ARG_1STR:
|
||||||
c, ID->min,
|
if (isdown)
|
||||||
ID->max);
|
((void(__cdecl *)(
|
||||||
|
char *))ID.fun)(
|
||||||
|
w[1]);
|
||||||
|
break;
|
||||||
|
case ARG_2STR:
|
||||||
|
if (isdown)
|
||||||
|
((void(__cdecl *)(
|
||||||
|
char *,
|
||||||
|
char *))ID.fun)(
|
||||||
|
w[1], w[2]);
|
||||||
|
break;
|
||||||
|
case ARG_3STR:
|
||||||
|
if (isdown)
|
||||||
|
((void(__cdecl *)(
|
||||||
|
char *, char *,
|
||||||
|
char *))ID.fun)(
|
||||||
|
w[1], w[2], w[3]);
|
||||||
|
break;
|
||||||
|
case ARG_5STR:
|
||||||
|
if (isdown)
|
||||||
|
((void(__cdecl *)(
|
||||||
|
char *, char *,
|
||||||
|
char *, char *,
|
||||||
|
char *))ID.fun)(
|
||||||
|
w[1], w[2], w[3],
|
||||||
|
w[4], w[5]);
|
||||||
|
break;
|
||||||
|
case ARG_DOWN:
|
||||||
|
((void(__cdecl *)(bool))ID.fun)(
|
||||||
|
isdown);
|
||||||
|
break;
|
||||||
|
case ARG_DWN1:
|
||||||
|
((void(__cdecl *)(
|
||||||
|
bool, char *))ID.fun)(
|
||||||
|
isdown, w[1]);
|
||||||
|
break;
|
||||||
|
case ARG_1EXP:
|
||||||
|
if (isdown)
|
||||||
|
val = ((int(__cdecl *)(
|
||||||
|
int))ID.fun)(
|
||||||
|
execute(w[1]));
|
||||||
|
break;
|
||||||
|
case ARG_2EXP:
|
||||||
|
if (isdown)
|
||||||
|
val = ((int(__cdecl *)(
|
||||||
|
int, int))ID.fun)(
|
||||||
|
execute(w[1]),
|
||||||
|
execute(w[2]));
|
||||||
|
break;
|
||||||
|
case ARG_1EST:
|
||||||
|
if (isdown)
|
||||||
|
val = ((int(__cdecl *)(
|
||||||
|
char *))ID.fun)(
|
||||||
|
w[1]);
|
||||||
|
break;
|
||||||
|
case ARG_2EST:
|
||||||
|
if (isdown)
|
||||||
|
val = ((int(__cdecl *)(
|
||||||
|
char *,
|
||||||
|
char *))ID.fun)(
|
||||||
|
w[1], w[2]);
|
||||||
|
break;
|
||||||
|
case ARG_VARI:
|
||||||
|
if (isdown) {
|
||||||
|
// limit, remove
|
||||||
|
string r;
|
||||||
|
r[0] = 0;
|
||||||
|
for (int i = 1;
|
||||||
|
i < numargs; i++) {
|
||||||
|
// make
|
||||||
|
// string-list
|
||||||
|
// out of all
|
||||||
|
// arguments
|
||||||
|
strcat_s(
|
||||||
|
r, w[i]);
|
||||||
|
if (i ==
|
||||||
|
numargs - 1)
|
||||||
|
break;
|
||||||
|
strcat_s(
|
||||||
|
r, " ");
|
||||||
}
|
}
|
||||||
*ID->storage = i1;
|
((void(__cdecl *)(
|
||||||
};
|
char *))ID.fun)(r);
|
||||||
if (ID->fun)
|
break;
|
||||||
((void(__cdecl *)())ID
|
}
|
||||||
->fun)(); // call
|
}
|
||||||
// trigger
|
break;
|
||||||
// function
|
|
||||||
// if
|
|
||||||
// available
|
|
||||||
};
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ID_ALIAS: // alias, also used as functions and
|
// game defined variables
|
||||||
// (global) variables
|
case ID_VAR:
|
||||||
for (int i = 1; i < numargs; i++) {
|
if (isdown) {
|
||||||
sprintf_sd(t)("arg%d",
|
if (!w[1][0])
|
||||||
i); // set any arguments as (global)
|
// var with no value
|
||||||
// arg values so functions can
|
// just prints its
|
||||||
// access them
|
// current value
|
||||||
alias(t, w[i]);
|
conoutf("%s = %d", c,
|
||||||
};
|
*ID.storage);
|
||||||
char *action = newstring(
|
else {
|
||||||
ID->action); // create new string here
|
if (ID.min > ID.max) {
|
||||||
// because alias could rebind
|
conoutf("variab"
|
||||||
// itself
|
"le is "
|
||||||
val = execute(action, isdown);
|
"read-"
|
||||||
gp()->deallocstr(action);
|
"only");
|
||||||
break;
|
} else {
|
||||||
};
|
int i1 =
|
||||||
|
ATOI(w[1]);
|
||||||
|
if (i1 <
|
||||||
|
ID.min ||
|
||||||
|
i1 >
|
||||||
|
ID.max) {
|
||||||
|
// clamp
|
||||||
|
// to
|
||||||
|
// valid
|
||||||
|
// range
|
||||||
|
i1 =
|
||||||
|
i1 < ID.min
|
||||||
|
? ID.min
|
||||||
|
: ID.max;
|
||||||
|
conoutf(
|
||||||
|
"va"
|
||||||
|
"li"
|
||||||
|
"d "
|
||||||
|
"ra"
|
||||||
|
"ng"
|
||||||
|
"e "
|
||||||
|
"fo"
|
||||||
|
"r "
|
||||||
|
"%s"
|
||||||
|
" i"
|
||||||
|
"s "
|
||||||
|
"%d"
|
||||||
|
".."
|
||||||
|
"%"
|
||||||
|
"d",
|
||||||
|
c,
|
||||||
|
ID.min,
|
||||||
|
ID.max);
|
||||||
|
}
|
||||||
|
*ID.storage =
|
||||||
|
i1;
|
||||||
|
}
|
||||||
|
if (ID.fun)
|
||||||
|
// call trigger
|
||||||
|
// function if
|
||||||
|
// available
|
||||||
|
((void(__cdecl
|
||||||
|
*)())ID
|
||||||
|
.fun)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// alias, also used as functions and (global)
|
||||||
|
// variables
|
||||||
|
case ID_ALIAS:
|
||||||
|
for (int i = 1; i < numargs; i++) {
|
||||||
|
// set any arguments as
|
||||||
|
// (global) arg values so
|
||||||
|
// functions can access them
|
||||||
|
sprintf_sd(t)("arg%d", i);
|
||||||
|
alias(t, w[i]);
|
||||||
|
}
|
||||||
|
// create new string here because alias
|
||||||
|
// could rebind itself
|
||||||
|
char *action = newstring(ID.action);
|
||||||
|
val = execute(action, isdown);
|
||||||
|
gp()->deallocstr(action);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
loopj(numargs) gp()->deallocstr(w[j]);
|
loopj(numargs) gp()->deallocstr(w[j]);
|
||||||
};
|
}
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
};
|
}
|
||||||
|
|
||||||
// tab-completion of all idents
|
// tab-completion of all idents
|
||||||
|
|
||||||
|
@ -391,7 +485,7 @@ void
|
||||||
resetcomplete()
|
resetcomplete()
|
||||||
{
|
{
|
||||||
completesize = 0;
|
completesize = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
complete(char *s)
|
complete(char *s)
|
||||||
|
@ -401,25 +495,26 @@ complete(char *s)
|
||||||
strcpy_s(t, s);
|
strcpy_s(t, s);
|
||||||
strcpy_s(s, "/");
|
strcpy_s(s, "/");
|
||||||
strcat_s(s, t);
|
strcat_s(s, t);
|
||||||
};
|
}
|
||||||
if (!s[1])
|
if (!s[1])
|
||||||
return;
|
return;
|
||||||
if (!completesize) {
|
if (!completesize) {
|
||||||
completesize = (int)strlen(s) - 1;
|
completesize = (int)strlen(s) - 1;
|
||||||
completeidx = 0;
|
completeidx = 0;
|
||||||
};
|
}
|
||||||
int idx = 0;
|
__block int idx = 0;
|
||||||
enumerate(
|
[idents enumerateKeysAndObjectsUsingBlock:^(
|
||||||
idents, ident *, id,
|
OFString *name, Ident *ident, bool *stop) {
|
||||||
if (strncmp(id->name, s + 1, completesize) == 0 &&
|
if (strncmp(ident.name, s + 1, completesize) == 0 &&
|
||||||
idx++ == completeidx) {
|
idx++ == completeidx) {
|
||||||
strcpy_s(s, "/");
|
strcpy_s(s, "/");
|
||||||
strcat_s(s, id->name);
|
strcat_s(s, ident.name);
|
||||||
};);
|
}
|
||||||
|
}];
|
||||||
completeidx++;
|
completeidx++;
|
||||||
if (completeidx >= idx)
|
if (completeidx >= idx)
|
||||||
completeidx = 0;
|
completeidx = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
execfile(char *cfgfile)
|
execfile(char *cfgfile)
|
||||||
|
@ -432,14 +527,14 @@ execfile(char *cfgfile)
|
||||||
execute(buf);
|
execute(buf);
|
||||||
free(buf);
|
free(buf);
|
||||||
return true;
|
return true;
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
exec(char *cfgfile)
|
exec(char *cfgfile)
|
||||||
{
|
{
|
||||||
if (!execfile(cfgfile))
|
if (!execfile(cfgfile))
|
||||||
conoutf("could not read \"%s\"", cfgfile);
|
conoutf("could not read \"%s\"", cfgfile);
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
writecfg()
|
writecfg()
|
||||||
|
@ -453,20 +548,23 @@ writecfg()
|
||||||
"autoexec.cfg to override anything\n\n");
|
"autoexec.cfg to override anything\n\n");
|
||||||
writeclientinfo(f);
|
writeclientinfo(f);
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
enumerate(
|
[idents enumerateKeysAndObjectsUsingBlock:^(
|
||||||
idents, ident *, ID, if (ID->type == ID_VAR && ID->persist) {
|
OFString *name, Ident *ident, bool *stop) {
|
||||||
fprintf(f, "%s %d\n", ID->name, *ID->storage);
|
if (ident.type == ID_VAR && ident.persist) {
|
||||||
};);
|
fprintf(f, "%s %d\n", ident.name, *ident.storage);
|
||||||
|
}
|
||||||
|
}];
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
writebinds(f);
|
writebinds(f);
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
enumerate(
|
[idents enumerateKeysAndObjectsUsingBlock:^(
|
||||||
idents, ident *, ID,
|
OFString *name, Ident *ident, bool *stop) {
|
||||||
if (ID->type == ID_ALIAS && !strstr(ID->name, "nextmap_")) {
|
if (ident.type == ID_ALIAS && !strstr(ident.name, "nextmap_")) {
|
||||||
fprintf(f, "alias \"%s\" [%s]\n", ID->name, ID->action);
|
fprintf(f, "alias \"%s\" [%s]\n", ident.name, ident.action);
|
||||||
};);
|
}
|
||||||
|
}];
|
||||||
fclose(f);
|
fclose(f);
|
||||||
};
|
}
|
||||||
|
|
||||||
COMMAND(writecfg, ARG_NONE);
|
COMMAND(writecfg, ARG_NONE);
|
||||||
|
|
||||||
|
@ -480,13 +578,14 @@ intset(char *name, int v)
|
||||||
string b;
|
string b;
|
||||||
itoa(b, v);
|
itoa(b, v);
|
||||||
alias(name, b);
|
alias(name, b);
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ifthen(char *cond, char *thenp, char *elsep)
|
ifthen(char *cond, char *thenp, char *elsep)
|
||||||
{
|
{
|
||||||
execute(cond[0] != '0' ? thenp : elsep);
|
execute(cond[0] != '0' ? thenp : elsep);
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
loopa(char *times, char *body)
|
loopa(char *times, char *body)
|
||||||
{
|
{
|
||||||
|
@ -495,26 +594,28 @@ loopa(char *times, char *body)
|
||||||
{
|
{
|
||||||
intset("i", i);
|
intset("i", i);
|
||||||
execute(body);
|
execute(body);
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
whilea(char *cond, char *body)
|
whilea(char *cond, char *body)
|
||||||
{
|
{
|
||||||
while (execute(cond))
|
while (execute(cond))
|
||||||
execute(body);
|
execute(body);
|
||||||
}; // can't get any simpler than this :)
|
} // can't get any simpler than this :)
|
||||||
|
|
||||||
void
|
void
|
||||||
onrelease(bool on, char *body)
|
onrelease(bool on, char *body)
|
||||||
{
|
{
|
||||||
if (!on)
|
if (!on)
|
||||||
execute(body);
|
execute(body);
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
concat(char *s)
|
concat(char *s)
|
||||||
{
|
{
|
||||||
alias("s", s);
|
alias("s", s);
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
concatword(char *s)
|
concatword(char *s)
|
||||||
|
@ -523,7 +624,7 @@ concatword(char *s)
|
||||||
if (*a != ' ')
|
if (*a != ' ')
|
||||||
a++;
|
a++;
|
||||||
concat(s);
|
concat(s);
|
||||||
};
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
listlen(char *a)
|
listlen(char *a)
|
||||||
|
@ -535,7 +636,7 @@ listlen(char *a)
|
||||||
if (*a++ == ' ')
|
if (*a++ == ' ')
|
||||||
n++;
|
n++;
|
||||||
return n + 1;
|
return n + 1;
|
||||||
};
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
at(char *s, char *pos)
|
at(char *s, char *pos)
|
||||||
|
@ -544,7 +645,7 @@ at(char *s, char *pos)
|
||||||
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
|
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
|
||||||
s[strcspn(s, " \0")] = 0;
|
s[strcspn(s, " \0")] = 0;
|
||||||
concat(s);
|
concat(s);
|
||||||
};
|
}
|
||||||
|
|
||||||
COMMANDN(loop, loopa, ARG_2STR);
|
COMMANDN(loop, loopa, ARG_2STR);
|
||||||
COMMANDN(while, whilea, ARG_2STR);
|
COMMANDN(while, whilea, ARG_2STR);
|
||||||
|
@ -560,68 +661,68 @@ int
|
||||||
add(int a, int b)
|
add(int a, int b)
|
||||||
{
|
{
|
||||||
return a + b;
|
return a + b;
|
||||||
};
|
}
|
||||||
COMMANDN(+, add, ARG_2EXP);
|
COMMANDN(+, add, ARG_2EXP);
|
||||||
int
|
int
|
||||||
mul(int a, int b)
|
mul(int a, int b)
|
||||||
{
|
{
|
||||||
return a * b;
|
return a * b;
|
||||||
};
|
}
|
||||||
COMMANDN(*, mul, ARG_2EXP);
|
COMMANDN(*, mul, ARG_2EXP);
|
||||||
int
|
int
|
||||||
sub(int a, int b)
|
sub(int a, int b)
|
||||||
{
|
{
|
||||||
return a - b;
|
return a - b;
|
||||||
};
|
}
|
||||||
COMMANDN(-, sub, ARG_2EXP);
|
COMMANDN(-, sub, ARG_2EXP);
|
||||||
int
|
int
|
||||||
divi(int a, int b)
|
divi(int a, int b)
|
||||||
{
|
{
|
||||||
return b ? a / b : 0;
|
return b ? a / b : 0;
|
||||||
};
|
}
|
||||||
COMMANDN(div, divi, ARG_2EXP);
|
COMMANDN(div, divi, ARG_2EXP);
|
||||||
int
|
int
|
||||||
mod(int a, int b)
|
mod(int a, int b)
|
||||||
{
|
{
|
||||||
return b ? a % b : 0;
|
return b ? a % b : 0;
|
||||||
};
|
}
|
||||||
COMMAND(mod, ARG_2EXP);
|
COMMAND(mod, ARG_2EXP);
|
||||||
int
|
int
|
||||||
equal(int a, int b)
|
equal(int a, int b)
|
||||||
{
|
{
|
||||||
return (int)(a == b);
|
return (int)(a == b);
|
||||||
};
|
}
|
||||||
COMMANDN(=, equal, ARG_2EXP);
|
COMMANDN(=, equal, ARG_2EXP);
|
||||||
int
|
int
|
||||||
lt(int a, int b)
|
lt(int a, int b)
|
||||||
{
|
{
|
||||||
return (int)(a < b);
|
return (int)(a < b);
|
||||||
};
|
}
|
||||||
COMMANDN(<, lt, ARG_2EXP);
|
COMMANDN(<, lt, ARG_2EXP);
|
||||||
int
|
int
|
||||||
gt(int a, int b)
|
gt(int a, int b)
|
||||||
{
|
{
|
||||||
return (int)(a > b);
|
return (int)(a > b);
|
||||||
};
|
}
|
||||||
COMMANDN(>, gt, ARG_2EXP);
|
COMMANDN(>, gt, ARG_2EXP);
|
||||||
|
|
||||||
int
|
int
|
||||||
strcmpa(char *a, char *b)
|
strcmpa(char *a, char *b)
|
||||||
{
|
{
|
||||||
return strcmp(a, b) == 0;
|
return strcmp(a, b) == 0;
|
||||||
};
|
}
|
||||||
COMMANDN(strcmp, strcmpa, ARG_2EST);
|
COMMANDN(strcmp, strcmpa, ARG_2EST);
|
||||||
|
|
||||||
int
|
int
|
||||||
rndn(int a)
|
rndn(int a)
|
||||||
{
|
{
|
||||||
return a > 0 ? rnd(a) : 0;
|
return a > 0 ? rnd(a) : 0;
|
||||||
};
|
}
|
||||||
COMMANDN(rnd, rndn, ARG_1EXP);
|
COMMANDN(rnd, rndn, ARG_1EXP);
|
||||||
|
|
||||||
int
|
int
|
||||||
explastmillis()
|
explastmillis()
|
||||||
{
|
{
|
||||||
return lastmillis;
|
return lastmillis;
|
||||||
};
|
}
|
||||||
COMMANDN(millis, explastmillis, ARG_1EXP);
|
COMMANDN(millis, explastmillis, ARG_1EXP);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue