Run clang-format on the entire codebase
FossilOrigin-Name: 0a0d4f91558171cf85e108964a5fed9e1c390a8343e9d2eda086c9c20fde7d1a
This commit is contained in:
parent
b8e3744913
commit
f84e7f7c72
37 changed files with 9648 additions and 7254 deletions
838
src/command.cxx
838
src/command.cxx
|
@ -1,344 +1,554 @@
|
|||
// command.cpp: implements the parsing and execution of a tiny script language which
|
||||
// is largely backwards compatible with the quake console language.
|
||||
// command.cpp: implements the parsing and execution of a tiny script language
|
||||
// which is largely backwards compatible with the quake console language.
|
||||
|
||||
#include "cube.h"
|
||||
|
||||
enum { ID_VAR, ID_COMMAND, ID_ALIAS };
|
||||
|
||||
struct ident
|
||||
{
|
||||
int type; // one of ID_* above
|
||||
char *name;
|
||||
int min, max; // ID_VAR
|
||||
int *storage; // ID_VAR
|
||||
void (*fun)(); // ID_VAR, ID_COMMAND
|
||||
int narg; // ID_VAR, ID_COMMAND
|
||||
char *action; // ID_ALIAS
|
||||
bool persist;
|
||||
struct ident {
|
||||
int type; // one of ID_* above
|
||||
char *name;
|
||||
int min, max; // ID_VAR
|
||||
int *storage; // ID_VAR
|
||||
void (*fun)(); // ID_VAR, ID_COMMAND
|
||||
int narg; // ID_VAR, ID_COMMAND
|
||||
char *action; // ID_ALIAS
|
||||
bool persist;
|
||||
};
|
||||
|
||||
void itoa(char *s, int i) { sprintf_s(s)("%d", i); };
|
||||
char *exchangestr(char *o, char *n) { gp()->deallocstr(o); return newstring(n); };
|
||||
|
||||
hashtable<ident> *idents = NULL; // contains ALL vars/commands/aliases
|
||||
|
||||
void alias(char *name, char *action)
|
||||
void
|
||||
itoa(char *s, int i)
|
||||
{
|
||||
ident *b = idents->access(name);
|
||||
if(!b)
|
||||
{
|
||||
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);
|
||||
};
|
||||
sprintf_s(s)("%d", i);
|
||||
};
|
||||
char *
|
||||
exchangestr(char *o, char *n)
|
||||
{
|
||||
gp()->deallocstr(o);
|
||||
return newstring(n);
|
||||
};
|
||||
|
||||
hashtable<ident> *idents = NULL; // contains ALL vars/commands/aliases
|
||||
|
||||
void
|
||||
alias(char *name, char *action)
|
||||
{
|
||||
ident *b = idents->access(name);
|
||||
if (!b) {
|
||||
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);
|
||||
|
||||
// variable's and commands are registered through globals, see cube.h
|
||||
|
||||
int variable(char *name, int min, int cur, int max, int *storage, void (*fun)(), bool persist)
|
||||
int
|
||||
variable(char *name, int min, int cur, int max, int *storage, void (*fun)(),
|
||||
bool persist)
|
||||
{
|
||||
if(!idents) idents = new hashtable<ident>;
|
||||
ident v = { ID_VAR, name, min, max, storage, fun, 0, 0, persist };
|
||||
idents->access(name, &v);
|
||||
return cur;
|
||||
if (!idents)
|
||||
idents = new hashtable<ident>;
|
||||
ident v = {ID_VAR, name, min, max, storage, fun, 0, 0, persist};
|
||||
idents->access(name, &v);
|
||||
return cur;
|
||||
};
|
||||
|
||||
void setvar(char *name, int i) { *idents->access(name)->storage = i; };
|
||||
int getvar(char *name) { return *idents->access(name)->storage; };
|
||||
bool identexists(char *name) { return idents->access(name)!=NULL; };
|
||||
|
||||
char *getalias(char *name)
|
||||
void
|
||||
setvar(char *name, int i)
|
||||
{
|
||||
ident *i = idents->access(name);
|
||||
return i && i->type==ID_ALIAS ? i->action : NULL;
|
||||
*idents->access(name)->storage = i;
|
||||
};
|
||||
int
|
||||
getvar(char *name)
|
||||
{
|
||||
return *idents->access(name)->storage;
|
||||
};
|
||||
bool
|
||||
identexists(char *name)
|
||||
{
|
||||
return idents->access(name) != NULL;
|
||||
};
|
||||
|
||||
bool addcommand(char *name, void (*fun)(), int narg)
|
||||
char *
|
||||
getalias(char *name)
|
||||
{
|
||||
if(!idents) idents = new hashtable<ident>;
|
||||
ident c = { ID_COMMAND, name, 0, 0, 0, fun, narg, 0, false };
|
||||
idents->access(name, &c);
|
||||
return false;
|
||||
ident *i = idents->access(name);
|
||||
return i && i->type == ID_ALIAS ? i->action : NULL;
|
||||
};
|
||||
|
||||
char *parseexp(char *&p, int right) // parse any nested set of () or []
|
||||
bool
|
||||
addcommand(char *name, void (*fun)(), int narg)
|
||||
{
|
||||
int left = *p++;
|
||||
char *word = p;
|
||||
for(int brak = 1; brak; )
|
||||
{
|
||||
int c = *p++;
|
||||
if(c=='\r') *(p-1) = ' '; // hack
|
||||
if(c==left) brak++;
|
||||
else if(c==right) brak--;
|
||||
else if(!c) { p--; conoutf("missing \"%c\"", right); return NULL; };
|
||||
};
|
||||
char *s = newstring(word, p-word-1);
|
||||
if(left=='(')
|
||||
{
|
||||
string t;
|
||||
itoa(t, execute(s)); // evaluate () exps directly, and substitute result
|
||||
s = exchangestr(s, t);
|
||||
};
|
||||
return s;
|
||||
if (!idents)
|
||||
idents = new hashtable<ident>;
|
||||
ident c = {ID_COMMAND, name, 0, 0, 0, fun, narg, 0, false};
|
||||
idents->access(name, &c);
|
||||
return false;
|
||||
};
|
||||
|
||||
char *parseword(char *&p) // parse single argument, including expressions
|
||||
char *
|
||||
parseexp(char *&p, int right) // parse any nested set of () or []
|
||||
{
|
||||
p += strspn(p, " \t\r");
|
||||
if(p[0]=='/' && p[1]=='/') p += strcspn(p, "\n\0");
|
||||
if(*p=='\"')
|
||||
{
|
||||
p++;
|
||||
char *word = p;
|
||||
p += strcspn(p, "\"\r\n\0");
|
||||
char *s = newstring(word, p-word);
|
||||
if(*p=='\"') p++;
|
||||
return s;
|
||||
};
|
||||
if(*p=='(') return parseexp(p, ')');
|
||||
if(*p=='[') return parseexp(p, ']');
|
||||
char *word = p;
|
||||
p += strcspn(p, "; \t\r\n\0");
|
||||
if(p-word==0) return NULL;
|
||||
return newstring(word, p-word);
|
||||
int left = *p++;
|
||||
char *word = p;
|
||||
for (int brak = 1; brak;) {
|
||||
int c = *p++;
|
||||
if (c == '\r')
|
||||
*(p - 1) = ' '; // hack
|
||||
if (c == left)
|
||||
brak++;
|
||||
else if (c == right)
|
||||
brak--;
|
||||
else if (!c) {
|
||||
p--;
|
||||
conoutf("missing \"%c\"", right);
|
||||
return NULL;
|
||||
};
|
||||
};
|
||||
char *s = newstring(word, p - word - 1);
|
||||
if (left == '(') {
|
||||
string t;
|
||||
itoa(t,
|
||||
execute(
|
||||
s)); // evaluate () exps directly, and substitute result
|
||||
s = exchangestr(s, t);
|
||||
};
|
||||
return s;
|
||||
};
|
||||
|
||||
char *lookup(char *n) // find value of ident referenced with $ in exp
|
||||
char *
|
||||
parseword(char *&p) // parse single argument, including expressions
|
||||
{
|
||||
ident *id = idents->access(n+1);
|
||||
if(id) switch(id->type)
|
||||
{
|
||||
case ID_VAR: string t; itoa(t, *(id->storage)); return exchangestr(n, t);
|
||||
case ID_ALIAS: return exchangestr(n, id->action);
|
||||
};
|
||||
conoutf("unknown alias lookup: %s", n+1);
|
||||
return n;
|
||||
p += strspn(p, " \t\r");
|
||||
if (p[0] == '/' && p[1] == '/')
|
||||
p += strcspn(p, "\n\0");
|
||||
if (*p == '\"') {
|
||||
p++;
|
||||
char *word = p;
|
||||
p += strcspn(p, "\"\r\n\0");
|
||||
char *s = newstring(word, p - word);
|
||||
if (*p == '\"')
|
||||
p++;
|
||||
return s;
|
||||
};
|
||||
if (*p == '(')
|
||||
return parseexp(p, ')');
|
||||
if (*p == '[')
|
||||
return parseexp(p, ']');
|
||||
char *word = p;
|
||||
p += strcspn(p, "; \t\r\n\0");
|
||||
if (p - word == 0)
|
||||
return NULL;
|
||||
return newstring(word, p - word);
|
||||
};
|
||||
|
||||
int execute(char *p, bool isdown) // all evaluation happens here, recursively
|
||||
char *
|
||||
lookup(char *n) // find value of ident referenced with $ in exp
|
||||
{
|
||||
const int MAXWORDS = 25; // limit, remove
|
||||
char *w[MAXWORDS];
|
||||
int val = 0;
|
||||
for(bool cont = true; cont;) // for each ; seperated statement
|
||||
{
|
||||
int numargs = MAXWORDS;
|
||||
loopi(MAXWORDS) // collect all argument values
|
||||
{
|
||||
w[i] = "";
|
||||
if(i>numargs) continue;
|
||||
char *s = parseword(p); // parse and evaluate exps
|
||||
if(!s) { numargs = i; s = ""; };
|
||||
if(*s=='$') s = lookup(s); // substitute variables
|
||||
w[i] = s;
|
||||
};
|
||||
|
||||
p += strcspn(p, ";\n\0");
|
||||
cont = *p++!=0; // more statements if this isn't the end of the string
|
||||
char *c = w[0];
|
||||
if(*c=='/') c++; // strip irc-style command prefix
|
||||
if(!*c) continue; // empty statement
|
||||
|
||||
ident *id = idents->access(c);
|
||||
if(!id)
|
||||
{
|
||||
val = ATOI(c);
|
||||
if(!val && *c!='0') conoutf("unknown command: %s", c);
|
||||
}
|
||||
else switch(id->type)
|
||||
{
|
||||
case ID_COMMAND: // game defined commands
|
||||
switch(id->narg) // use very ad-hoc function signature, and just call it
|
||||
{
|
||||
case ARG_1INT: if(isdown) ((void (__cdecl *)(int))id->fun)(ATOI(w[1])); break;
|
||||
case ARG_2INT: if(isdown) ((void (__cdecl *)(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 ID_VAR: // game defined variabled
|
||||
if(isdown)
|
||||
{
|
||||
if(!w[1][0]) conoutf("%s = %d", c, *id->storage); // var with no value just prints its current value
|
||||
else
|
||||
{
|
||||
if(id->min>id->max)
|
||||
{
|
||||
conoutf("variable is read-only");
|
||||
}
|
||||
else
|
||||
{
|
||||
int i1 = ATOI(w[1]);
|
||||
if(i1<id->min || i1>id->max)
|
||||
{
|
||||
i1 = i1<id->min ? id->min : id->max; // clamp to valid range
|
||||
conoutf("valid range for %s is %d..%d", c, id->min, id->max);
|
||||
}
|
||||
*id->storage = i1;
|
||||
};
|
||||
if(id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available
|
||||
};
|
||||
};
|
||||
break;
|
||||
|
||||
case ID_ALIAS: // alias, also used as functions and (global) variables
|
||||
for(int i = 1; i<numargs; i++)
|
||||
{
|
||||
sprintf_sd(t)("arg%d", i); // set any arguments as (global) arg values so functions can access them
|
||||
alias(t, w[i]);
|
||||
};
|
||||
char *action = newstring(id->action); // create new string here because alias could rebind itself
|
||||
val = execute(action, isdown);
|
||||
gp()->deallocstr(action);
|
||||
break;
|
||||
};
|
||||
loopj(numargs) gp()->deallocstr(w[j]);
|
||||
};
|
||||
return val;
|
||||
ident *id = idents->access(n + 1);
|
||||
if (id)
|
||||
switch (id->type) {
|
||||
case ID_VAR:
|
||||
string t;
|
||||
itoa(t, *(id->storage));
|
||||
return exchangestr(n, t);
|
||||
case ID_ALIAS:
|
||||
return exchangestr(n, id->action);
|
||||
};
|
||||
conoutf("unknown alias lookup: %s", n + 1);
|
||||
return n;
|
||||
};
|
||||
|
||||
int
|
||||
execute(char *p, bool isdown) // all evaluation happens here, recursively
|
||||
{
|
||||
const int MAXWORDS = 25; // limit, remove
|
||||
char *w[MAXWORDS];
|
||||
int val = 0;
|
||||
for (bool cont = true; cont;) // for each ; seperated statement
|
||||
{
|
||||
int numargs = MAXWORDS;
|
||||
loopi(MAXWORDS) // collect all argument values
|
||||
{
|
||||
w[i] = "";
|
||||
if (i > numargs)
|
||||
continue;
|
||||
char *s = parseword(p); // parse and evaluate exps
|
||||
if (!s) {
|
||||
numargs = i;
|
||||
s = "";
|
||||
};
|
||||
if (*s == '$')
|
||||
s = lookup(s); // substitute variables
|
||||
w[i] = s;
|
||||
};
|
||||
|
||||
p += strcspn(p, ";\n\0");
|
||||
cont = *p++ !=
|
||||
0; // more statements if this isn't the end of the string
|
||||
char *c = w[0];
|
||||
if (*c == '/')
|
||||
c++; // strip irc-style command prefix
|
||||
if (!*c)
|
||||
continue; // empty statement
|
||||
|
||||
ident *id = idents->access(c);
|
||||
if (!id) {
|
||||
val = ATOI(c);
|
||||
if (!val && *c != '0')
|
||||
conoutf("unknown command: %s", c);
|
||||
} else
|
||||
switch (id->type) {
|
||||
case ID_COMMAND: // game defined commands
|
||||
switch (id->narg) // use very ad-hoc function
|
||||
// signature, and just call it
|
||||
{
|
||||
case ARG_1INT:
|
||||
if (isdown)
|
||||
((void(__cdecl *)(int))id->fun)(
|
||||
ATOI(w[1]));
|
||||
break;
|
||||
case ARG_2INT:
|
||||
if (isdown)
|
||||
((void(__cdecl *)(
|
||||
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 ID_VAR: // game defined variabled
|
||||
if (isdown) {
|
||||
if (!w[1][0])
|
||||
conoutf("%s = %d", c,
|
||||
*id->storage); // var with
|
||||
// no value
|
||||
// just
|
||||
// prints its
|
||||
// current
|
||||
// value
|
||||
else {
|
||||
if (id->min > id->max) {
|
||||
conoutf("variable is "
|
||||
"read-only");
|
||||
} else {
|
||||
int i1 = ATOI(w[1]);
|
||||
if (i1 < id->min ||
|
||||
i1 > id->max) {
|
||||
i1 =
|
||||
i1 < id->min
|
||||
? id->min
|
||||
: id->max; // clamp to valid range
|
||||
conoutf(
|
||||
"valid "
|
||||
"range for "
|
||||
"%s is "
|
||||
"%d..%d",
|
||||
c, id->min,
|
||||
id->max);
|
||||
}
|
||||
*id->storage = i1;
|
||||
};
|
||||
if (id->fun)
|
||||
((void(__cdecl *)())id
|
||||
->fun)(); // call
|
||||
// trigger
|
||||
// function
|
||||
// if
|
||||
// available
|
||||
};
|
||||
};
|
||||
break;
|
||||
|
||||
case ID_ALIAS: // alias, also used as functions and
|
||||
// (global) variables
|
||||
for (int i = 1; i < numargs; i++) {
|
||||
sprintf_sd(t)("arg%d",
|
||||
i); // set any arguments as (global)
|
||||
// arg values so functions can
|
||||
// access them
|
||||
alias(t, w[i]);
|
||||
};
|
||||
char *action = newstring(
|
||||
id->action); // create new string here
|
||||
// because alias could rebind
|
||||
// itself
|
||||
val = execute(action, isdown);
|
||||
gp()->deallocstr(action);
|
||||
break;
|
||||
};
|
||||
loopj(numargs) gp()->deallocstr(w[j]);
|
||||
};
|
||||
return val;
|
||||
};
|
||||
|
||||
// tab-completion of all idents
|
||||
|
||||
int completesize = 0, completeidx = 0;
|
||||
|
||||
void resetcomplete() { completesize = 0; };
|
||||
|
||||
void complete(char *s)
|
||||
void
|
||||
resetcomplete()
|
||||
{
|
||||
if(*s!='/')
|
||||
{
|
||||
string t;
|
||||
strcpy_s(t, s);
|
||||
strcpy_s(s, "/");
|
||||
strcat_s(s, t);
|
||||
};
|
||||
if(!s[1]) return;
|
||||
if(!completesize) { completesize = (int)strlen(s)-1; completeidx = 0; };
|
||||
int idx = 0;
|
||||
enumerate(idents, ident *, id,
|
||||
if(strncmp(id->name, s+1, completesize)==0 && idx++==completeidx)
|
||||
{
|
||||
strcpy_s(s, "/");
|
||||
strcat_s(s, id->name);
|
||||
};
|
||||
);
|
||||
completeidx++;
|
||||
if(completeidx>=idx) completeidx = 0;
|
||||
completesize = 0;
|
||||
};
|
||||
|
||||
bool execfile(char *cfgfile)
|
||||
void
|
||||
complete(char *s)
|
||||
{
|
||||
string s;
|
||||
strcpy_s(s, cfgfile);
|
||||
char *buf = loadfile(path(s), NULL);
|
||||
if(!buf) return false;
|
||||
execute(buf);
|
||||
free(buf);
|
||||
return true;
|
||||
if (*s != '/') {
|
||||
string t;
|
||||
strcpy_s(t, s);
|
||||
strcpy_s(s, "/");
|
||||
strcat_s(s, t);
|
||||
};
|
||||
if (!s[1])
|
||||
return;
|
||||
if (!completesize) {
|
||||
completesize = (int)strlen(s) - 1;
|
||||
completeidx = 0;
|
||||
};
|
||||
int idx = 0;
|
||||
enumerate(
|
||||
idents, ident *, id,
|
||||
if (strncmp(id->name, s + 1, completesize) == 0 &&
|
||||
idx++ == completeidx) {
|
||||
strcpy_s(s, "/");
|
||||
strcat_s(s, id->name);
|
||||
};);
|
||||
completeidx++;
|
||||
if (completeidx >= idx)
|
||||
completeidx = 0;
|
||||
};
|
||||
|
||||
void exec(char *cfgfile)
|
||||
bool
|
||||
execfile(char *cfgfile)
|
||||
{
|
||||
if(!execfile(cfgfile)) conoutf("could not read \"%s\"", cfgfile);
|
||||
string s;
|
||||
strcpy_s(s, cfgfile);
|
||||
char *buf = loadfile(path(s), NULL);
|
||||
if (!buf)
|
||||
return false;
|
||||
execute(buf);
|
||||
free(buf);
|
||||
return true;
|
||||
};
|
||||
|
||||
void writecfg()
|
||||
void
|
||||
exec(char *cfgfile)
|
||||
{
|
||||
FILE *f = fopen("config.cfg", "w");
|
||||
if(!f) return;
|
||||
fprintf(f, "// automatically written on exit, do not modify\n// delete this file to have defaults.cfg overwrite these settings\n// modify settings in game, or put settings in autoexec.cfg to override anything\n\n");
|
||||
writeclientinfo(f);
|
||||
fprintf(f, "\n");
|
||||
enumerate(idents, ident *, id,
|
||||
if(id->type==ID_VAR && id->persist)
|
||||
{
|
||||
fprintf(f, "%s %d\n", id->name, *id->storage);
|
||||
};
|
||||
);
|
||||
fprintf(f, "\n");
|
||||
writebinds(f);
|
||||
fprintf(f, "\n");
|
||||
enumerate(idents, ident *, id,
|
||||
if(id->type==ID_ALIAS && !strstr(id->name, "nextmap_"))
|
||||
{
|
||||
fprintf(f, "alias \"%s\" [%s]\n", id->name, id->action);
|
||||
};
|
||||
);
|
||||
fclose(f);
|
||||
if (!execfile(cfgfile))
|
||||
conoutf("could not read \"%s\"", cfgfile);
|
||||
};
|
||||
|
||||
void
|
||||
writecfg()
|
||||
{
|
||||
FILE *f = fopen("config.cfg", "w");
|
||||
if (!f)
|
||||
return;
|
||||
fprintf(f, "// automatically written on exit, do not modify\n// delete "
|
||||
"this file to have defaults.cfg overwrite these "
|
||||
"settings\n// modify settings in game, or put settings in "
|
||||
"autoexec.cfg to override anything\n\n");
|
||||
writeclientinfo(f);
|
||||
fprintf(f, "\n");
|
||||
enumerate(
|
||||
idents, ident *, id, if (id->type == ID_VAR && id->persist) {
|
||||
fprintf(f, "%s %d\n", id->name, *id->storage);
|
||||
};);
|
||||
fprintf(f, "\n");
|
||||
writebinds(f);
|
||||
fprintf(f, "\n");
|
||||
enumerate(
|
||||
idents, ident *, id,
|
||||
if (id->type == ID_ALIAS && !strstr(id->name, "nextmap_")) {
|
||||
fprintf(f, "alias \"%s\" [%s]\n", id->name, id->action);
|
||||
};);
|
||||
fclose(f);
|
||||
};
|
||||
|
||||
COMMAND(writecfg, ARG_NONE);
|
||||
|
||||
// below the commands that implement a small imperative language. thanks to the semantics of
|
||||
// below the commands that implement a small imperative language. thanks to the
|
||||
// semantics of
|
||||
// () and [] expressions, any control construct can be defined trivially.
|
||||
|
||||
void intset(char *name, int v) { string b; itoa(b, v); alias(name, b); };
|
||||
|
||||
void ifthen(char *cond, char *thenp, char *elsep) { execute(cond[0]!='0' ? thenp : elsep); };
|
||||
void loopa(char *times, char *body) { int t = atoi(times); loopi(t) { intset("i", i); execute(body); }; };
|
||||
void whilea(char *cond, char *body) { while(execute(cond)) execute(body); }; // can't get any simpler than this :)
|
||||
void onrelease(bool on, char *body) { if(!on) execute(body); };
|
||||
|
||||
void concat(char *s) { alias("s", s); };
|
||||
|
||||
void concatword(char *s)
|
||||
void
|
||||
intset(char *name, int v)
|
||||
{
|
||||
for(char *a = s, *b = s; *a = *b; b++) if(*a!=' ') a++;
|
||||
concat(s);
|
||||
string b;
|
||||
itoa(b, v);
|
||||
alias(name, b);
|
||||
};
|
||||
|
||||
int listlen(char *a)
|
||||
void
|
||||
ifthen(char *cond, char *thenp, char *elsep)
|
||||
{
|
||||
if(!*a) return 0;
|
||||
int n = 0;
|
||||
while(*a) if(*a++==' ') n++;
|
||||
return n+1;
|
||||
execute(cond[0] != '0' ? thenp : elsep);
|
||||
};
|
||||
void
|
||||
loopa(char *times, char *body)
|
||||
{
|
||||
int t = atoi(times);
|
||||
loopi(t)
|
||||
{
|
||||
intset("i", i);
|
||||
execute(body);
|
||||
};
|
||||
};
|
||||
void
|
||||
whilea(char *cond, char *body)
|
||||
{
|
||||
while (execute(cond))
|
||||
execute(body);
|
||||
}; // can't get any simpler than this :)
|
||||
void
|
||||
onrelease(bool on, char *body)
|
||||
{
|
||||
if (!on)
|
||||
execute(body);
|
||||
};
|
||||
|
||||
void at(char *s, char *pos)
|
||||
void
|
||||
concat(char *s)
|
||||
{
|
||||
int n = atoi(pos);
|
||||
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
|
||||
s[strcspn(s, " \0")] = 0;
|
||||
concat(s);
|
||||
alias("s", s);
|
||||
};
|
||||
|
||||
void
|
||||
concatword(char *s)
|
||||
{
|
||||
for (char *a = s, *b = s; *a = *b; b++)
|
||||
if (*a != ' ')
|
||||
a++;
|
||||
concat(s);
|
||||
};
|
||||
|
||||
int
|
||||
listlen(char *a)
|
||||
{
|
||||
if (!*a)
|
||||
return 0;
|
||||
int n = 0;
|
||||
while (*a)
|
||||
if (*a++ == ' ')
|
||||
n++;
|
||||
return n + 1;
|
||||
};
|
||||
|
||||
void
|
||||
at(char *s, char *pos)
|
||||
{
|
||||
int n = atoi(pos);
|
||||
loopi(n) s += strspn(s += strcspn(s, " \0"), " ");
|
||||
s[strcspn(s, " \0")] = 0;
|
||||
concat(s);
|
||||
};
|
||||
|
||||
COMMANDN(loop, loopa, ARG_2STR);
|
||||
COMMANDN(while, whilea, ARG_2STR);
|
||||
COMMANDN(if, ifthen, ARG_3STR);
|
||||
COMMANDN(if, ifthen, ARG_3STR);
|
||||
COMMAND(onrelease, ARG_DWN1);
|
||||
COMMAND(exec, ARG_1STR);
|
||||
COMMAND(concat, ARG_VARI);
|
||||
|
@ -346,18 +556,72 @@ COMMAND(concatword, ARG_VARI);
|
|||
COMMAND(at, ARG_2STR);
|
||||
COMMAND(listlen, ARG_1EST);
|
||||
|
||||
int add(int a, int b) { return a+b; }; COMMANDN(+, add, ARG_2EXP);
|
||||
int mul(int a, int b) { return a*b; }; COMMANDN(*, mul, ARG_2EXP);
|
||||
int sub(int a, int b) { return a-b; }; COMMANDN(-, sub, ARG_2EXP);
|
||||
int divi(int a, int b) { return b ? a/b : 0; }; COMMANDN(div, divi, ARG_2EXP);
|
||||
int mod(int a, int b) { return b ? a%b : 0; }; COMMAND(mod, ARG_2EXP);
|
||||
int equal(int a, int b) { return (int)(a==b); }; COMMANDN(=, equal, ARG_2EXP);
|
||||
int lt(int a, int b) { return (int)(a<b); }; COMMANDN(<, lt, ARG_2EXP);
|
||||
int gt(int a, int b) { return (int)(a>b); }; COMMANDN(>, gt, ARG_2EXP);
|
||||
int
|
||||
add(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
};
|
||||
COMMANDN(+, add, ARG_2EXP);
|
||||
int
|
||||
mul(int a, int b)
|
||||
{
|
||||
return a * b;
|
||||
};
|
||||
COMMANDN(*, mul, ARG_2EXP);
|
||||
int
|
||||
sub(int a, int b)
|
||||
{
|
||||
return a - b;
|
||||
};
|
||||
COMMANDN(-, sub, ARG_2EXP);
|
||||
int
|
||||
divi(int a, int b)
|
||||
{
|
||||
return b ? a / b : 0;
|
||||
};
|
||||
COMMANDN(div, divi, ARG_2EXP);
|
||||
int
|
||||
mod(int a, int b)
|
||||
{
|
||||
return b ? a % b : 0;
|
||||
};
|
||||
COMMAND(mod, ARG_2EXP);
|
||||
int
|
||||
equal(int a, int b)
|
||||
{
|
||||
return (int)(a == b);
|
||||
};
|
||||
COMMANDN(=, equal, ARG_2EXP);
|
||||
int
|
||||
lt(int a, int b)
|
||||
{
|
||||
return (int)(a < b);
|
||||
};
|
||||
COMMANDN(<, lt, ARG_2EXP);
|
||||
int
|
||||
gt(int a, int b)
|
||||
{
|
||||
return (int)(a > b);
|
||||
};
|
||||
COMMANDN(>, gt, ARG_2EXP);
|
||||
|
||||
int strcmpa(char *a, char *b) { return strcmp(a,b)==0; }; COMMANDN(strcmp, strcmpa, ARG_2EST);
|
||||
int
|
||||
strcmpa(char *a, char *b)
|
||||
{
|
||||
return strcmp(a, b) == 0;
|
||||
};
|
||||
COMMANDN(strcmp, strcmpa, ARG_2EST);
|
||||
|
||||
int rndn(int a) { return a>0 ? rnd(a) : 0; }; COMMANDN(rnd, rndn, ARG_1EXP);
|
||||
|
||||
int explastmillis() { return lastmillis; }; COMMANDN(millis, explastmillis, ARG_1EXP);
|
||||
int
|
||||
rndn(int a)
|
||||
{
|
||||
return a > 0 ? rnd(a) : 0;
|
||||
};
|
||||
COMMANDN(rnd, rndn, ARG_1EXP);
|
||||
|
||||
int
|
||||
explastmillis()
|
||||
{
|
||||
return lastmillis;
|
||||
};
|
||||
COMMANDN(millis, explastmillis, ARG_1EXP);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue