command cleanup

changed commands:

  strstr haystack needle

    now returns position of needle in haystack (counting from 1)
    or zero, if not found

  substr string start len

    now counts negative length from total length
    "substr text 1 -2" now returns the text without first and last char

  strreplace text search replace

    no longer restricted to 260 char stringlengths

removed commands:

  swapelements, strpos (can be scripted, if required)

DOCREF strstr substr
DOCREF swapelements strpos
This commit is contained in:
ac-stef
2017-06-07 23:20:00 +02:00
parent ffee440fa0
commit 83d0199867
8 changed files with 207 additions and 307 deletions
+1 -1
View File
@@ -60,7 +60,7 @@ const fullscreentoggle [ fullscreen (! $fullscreen) ]
const editsvar [ inputcommand $$arg1 (concatword "push q (addpunct $cmdbuf) ; " $arg1 " (at $q 0) ; pop q") (concatword "edit " $arg1 :) ]
const editmapmsg [ editsvar mapmsg ]
const editalias [ if (checkalias $arg1) 0 [ alias $arg1 "" ] ; inputcommand $$arg1 (concatword "push q (addpunct $cmdbuf) ; " $arg1 " = (at $q 0) ; pop q") (concatword "edit " $arg1 :) ]
const escapenoquotes [ substr (escape $arg1) 1 (- (strlen (escape $arg1)) 2) ]
const escapenoquotes [ substr (escape $arg1) 1 -2 ]
const run [ push n (concatword "exec config/" $arg1 ".cfg") ; loop i (- $numargs 1) [ n = (concat $n $(concatword arg (+ $i 2))) ] ; n ; pop n]
const closecurmenu [ closemenu (curmenu) ]
const resetcurmenu [ delmenu (curmenu) ; newmenu (curmenu) ]
+13
View File
@@ -883,3 +883,16 @@ COMMAND(securemap, "s");
COMMAND(getdemo, "is");
COMMAND(listdemos, "");
COMMANDF(watchingdemo, "", () { intret(watchingdemo); });
COMMANDF(systime, "", () { result(numtime()); });
COMMANDF(timestamp, "", () { result(timestring(true, "%Y %m %d %H %M %S")); });
COMMANDF(datestring, "", () { result(timestring(true, "%c")); });
COMMANDF(timestring, "", ()
{
const char *res = timestring(true, "%H:%M:%S");
result(res[0] == '0' ? res + 1 : res);
});
COMMANDF(millis, "", () { intret(totalmillis); });
+72
View File
@@ -367,6 +367,78 @@ void teaminfo(const char *team, const char *attr)
COMMAND(teaminfo, "ss");
const char *currentserver(int i) // [client version]
{
static string curSRVinfo;
// using the curpeer directly we can get the info of our currently connected server
string r;
r[0] = '\0';
extern ENetPeer *curpeer;
if(curpeer)
{
switch(i)
{
case 1: // IP
{
uchar *ip = (uchar *)&curpeer->address.host;
formatstring(r)("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
break;
}
case 2: // HOST
{
char hn[1024];
formatstring(r)("%s", (enet_address_get_host(&curpeer->address, hn, sizeof(hn))==0) ? hn : "unknown");
break;
}
case 3: // PORT
{
formatstring(r)("%d", curpeer->address.port);
break;
}
case 4: // STATE
{
const char *statenames[] =
{
"disconnected",
"connecting",
"acknowledging connect",
"connection pending",
"connection succeeded",
"connected",
"disconnect later",
"disconnecting",
"acknowledging disconnect",
"zombie"
};
if(curpeer->state>=0 && curpeer->state<int(sizeof(statenames)/sizeof(statenames[0])))
copystring(r, statenames[curpeer->state]);
break; // 5 == Connected (compare ../enet/include/enet/enet.h +165)
}
// CAUTION: the following are only filled if the serverbrowser was used or the scoreboard shown
// SERVERNAME
case 5: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->name); break; }
// DESCRIPTION (3)
case 6: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->sdesc); break; }
case 7: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->description); break; }
// CAUTION: the following is only the last full-description _seen_ in the serverbrowser!
case 8: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->full); break; }
// just IP & PORT as default response - always available, no lookup-delay either
default:
{
uchar *ip = (uchar *)&curpeer->address.host;
formatstring(r)("%d.%d.%d.%d %d", ip[0], ip[1], ip[2], ip[3], curpeer->address.port);
break;
}
}
}
copystring(curSRVinfo, r);
return curSRVinfo;
}
COMMANDF(curserver, "i", (int *i) { result(currentserver(*i)); });
COMMANDF(getmode, "i", (int *acr) { result(modestr(gamemode, *acr != 0)); });
void deathstate(playerent *pl)
{
pl->state = CS_DEAD;
+116 -299
View File
@@ -225,98 +225,6 @@ void setsvar(const char *name, const char *str, bool dofunc)
if(dofunc && id->fun) ((void (__cdecl *)())id->fun)(); // call trigger function if available
}
void modifyvar(const char *name, int arg, char op)
{
ident *id = idents->access(name);
if(!id) return;
if(identaccessdenied(id))
{
conoutf("not allowed in this execution context: %s", id->name);
scripterr();
return;
}
if((id->type == ID_VAR && id->minval > id->maxval) || (id->type == ID_FVAR && id->minvalf > id->maxvalf)) { conoutf("variable %s is read-only", id->name); return; }
int val = 0;
switch(id->type)
{
case ID_VAR: val = *id->storage.i; break;
case ID_FVAR: val = int(*id->storage.f); break;
case ID_SVAR: { { if(id->getfun) ((void (__cdecl *)())id->getfun)(); } val = ATOI(*id->storage.s); break; }
case ID_ALIAS: val = ATOI(id->action); break;
}
switch(op)
{
case '+': val += arg; break;
case '-': val -= arg; break;
case '*': val *= arg; break;
case '/': val = arg ? val/arg : 0; break;
}
switch(id->type)
{
case ID_VAR: *id->storage.i = clamp(val, id->minval, id->maxval); break;
case ID_FVAR: *id->storage.f = clamp((float)val, id->minvalf, id->maxvalf); break;
case ID_SVAR: { string str; itoa(str, val); *id->storage.s = exchangestr(*id->storage.s, str); break; }
case ID_ALIAS: { string str; itoa(str, val); alias(name, str); return; }
default: return;
}
if(id->fun) ((void (__cdecl *)())id->fun)();
}
void modifyfvar(const char *name, float arg, char op)
{
ident *id = idents->access(name);
if(!id) return;
if(identaccessdenied(id))
{
conoutf("not allowed in this execution context: %s", id->name);
scripterr();
return;
}
if((id->type == ID_VAR && id->minval > id->maxval) || (id->type == ID_FVAR && id->minvalf > id->maxvalf)) { conoutf("variable %s is read-only", id->name); return; }
float val = 0;
switch(id->type)
{
case ID_VAR: val = *id->storage.i; break;
case ID_FVAR: val = *id->storage.f; break;
case ID_SVAR: { { if(id->getfun) ((void (__cdecl *)())id->getfun)(); } val = atof(*id->storage.s); break; }
case ID_ALIAS: val = atof(id->action); break;
}
switch(op)
{
case '+': val += arg; break;
case '-': val -= arg; break;
case '*': val *= arg; break;
case '/': val = (arg == 0.0f) ? 0 : val/arg; break;
}
switch(id->type)
{
case ID_VAR: *id->storage.i = clamp((int)val, id->minval, id->maxval); break;
case ID_FVAR: *id->storage.f = clamp(val, id->minvalf, id->maxvalf); break;
case ID_SVAR: *id->storage.s = exchangestr(*id->storage.s, floatstr(val)); break;
case ID_ALIAS: alias(name, floatstr(val)); return;
default: return;
}
if(id->fun) ((void (__cdecl *)())id->fun)();
}
void addeq(char *name, int *arg) { modifyvar(name, *arg, '+'); }
void subeq(char *name, int *arg) { modifyvar(name, *arg, '-'); }
void muleq(char *name, int *arg) { modifyvar(name, *arg, '*'); }
void diveq(char *name, int *arg) { modifyvar(name, *arg, '/'); }
void addeqf(char *name, float *arg) { modifyfvar(name, *arg, '+'); }
void subeqf(char *name, float *arg) { modifyfvar(name, *arg, '-'); }
void muleqf(char *name, float *arg) { modifyfvar(name, *arg, '*'); }
void diveqf(char *name, float *arg) { modifyfvar(name, *arg, '/'); }
COMMANDN(+=, addeq, "si");
COMMANDN(-=, subeq, "si");
COMMANDN(*=, muleq, "si");
COMMANDN(div=, diveq, "si");
COMMANDN(+=f, addeqf, "sf");
COMMANDN(-=f, subeqf, "sf");
COMMANDN(*=f, muleqf, "sf");
COMMANDN(div=f, diveqf, "sf");
bool identexists(const char *name) { return idents->access(name)!=NULL; }
const char *getalias(const char *name)
@@ -1320,10 +1228,42 @@ int find(char *s, const char *key)
COMMANDF(findlist, "ss", (char *s, char *key) { intret(find(s, key)); });
#ifndef STANDALONE
// Easily inject a string into various CubeScript punctuations
COMMANDF(l0, "ii", (int *p, int *v) { defformatstring(f)("%%0%dd", clamp(*p, 0, 200)); defformatstring(r)(f, *v); result(r); });
COMMANDF(h0, "ii", (int *p, int *v) { defformatstring(f)("%%0%dx", clamp(*p, 0, 200)); defformatstring(r)(f, *v); result(r); });
COMMANDF(strlen, "s", (char *s) { intret(strlen(s)); });
COMMANDF(strstr, "ss", (char *h, char *n) { char *r = strstr(h, n); intret(r ? r - h + 1 : 0); });
void substr_(char *text, int *_start, int *_len)
{
int start = *_start, len = *_len, textlen = (int)strlen(text);
if(start < 0) start += textlen; // negative positions count from the end
if(len < 0) len += textlen; // negative len subtracts from total
if(start > textlen || start < 0 || len < 0) return;
if(!len) len = textlen - start; // zero len gets all
if(len >= 0 && len < int(strlen(text + start))) (text + start)[len] = '\0'; // cut text at len, if too long
result(text + start);
}
COMMANDN(substr, substr_, "sii");
void strreplace(char *text, char *search, char *replace)
{
vector<char> buf;
char *o = text;
while(*search && (o = strstr(text, search)))
{
buf.put(text, o - text);
buf.put(replace, strlen(replace));
text = o + strlen(search);
}
buf.put(text, strlen(text));
resultcharvector(buf, 0);
}
COMMAND(strreplace, "sss");
const char *punctnames[] = { "QUOTES", "BRACKETS", "PARENTHESIS", "_$_", "QUOTE", "PERCENT", "" };
void addpunct(char *s, char *type)
void addpunct(char *s, char *type) // Easily inject a string into various CubeScript punctuations
{
int t = getlistindex(type, punctnames, true, 0);
const char *puncts[] = { "\"%s\"", "[%s]", "(%s)", "$%s", "\"", "%" }, *punct = puncts[t];
@@ -1344,65 +1284,12 @@ COMMANDF(toupper, "s", (char *s) { toany(s, toupper); result(s); });
void testchar(char *s, int *type)
{
bool istrue = false;
switch(*type) {
case 1:
if(isalpha(s[0]) != 0) { istrue = true; }
break;
case 2:
if(isalnum(s[0]) != 0) { istrue = true; }
break;
case 3:
if(islower(s[0]) != 0) { istrue = true; }
break;
case 4:
if(isupper(s[0]) != 0) { istrue = true; }
break;
case 5:
if(isprint(s[0]) != 0) { istrue = true; }
break;
case 6:
if(ispunct(s[0]) != 0) { istrue = true; }
break;
case 7:
if(isspace(s[0]) != 0) { istrue = true; }
break;
case 8: // Without this it is impossible to determine if a character === " in cubescript
if(!strcmp(s, "\"")) { istrue = true; }
break;
default:
if(isdigit(s[0]) != 0) { istrue = true; }
break;
}
intret(istrue ? 1 : 0);
int (*funcs[8])(int) = { isdigit, isalpha, isalnum, islower, isupper, isprint, ispunct, isspace };
if(*type < 1 || *type > 7) *type = 0; // default to isdigit
intret((funcs[*type])(*s) ? 1 : 0);
}
COMMAND(testchar, "si");
char *strreplace(char *dest, const char *source, const char *search, const char *replace)
{
vector<char> buf;
int searchlen = strlen(search);
if(!searchlen) { copystring(dest, source); return dest; }
for(;;)
{
const char *found = strstr(source, search);
if(found)
{
while(source < found) buf.add(*source++);
for(const char *n = replace; *n; n++) buf.add(*n);
source = found + searchlen;
}
else
{
while(*source) buf.add(*source++);
buf.add('\0');
return copystring(dest, buf.getbuf());
}
}
}
COMMANDF(strreplace, "sss", (const char *source, const char *search, const char *replace) { string d; result(strreplace(d, source, search, replace)); });
void sortlist(char *list)
{
vector<char *> elems;
@@ -1413,33 +1300,89 @@ void sortlist(char *list)
}
COMMAND(sortlist, "c");
void swapelements(char *list, char *v)
void modifyvar(const char *name, int arg, char op)
{
vector<char *> elems;
explodelist(list, elems);
vector<char *> swap;
explodelist(v, swap);
vector<int> swapi;
loopv(swap) swapi.add(atoi(swap[i]));
if(swapi.length() && !(swapi.length() & 1)) // swap needs to have an even number of elements
ident *id = idents->access(name);
if(!id) return;
if(identaccessdenied(id))
{
for(int i = 0; i < swapi.length(); i += 2)
{
if (elems.inrange(swapi[i]) && elems.inrange(swapi[i + 1]))
{
char *tmp = elems[swapi[i]];
elems[swapi[i]] = elems[swapi[i + 1]];
elems[swapi[i + 1]] = tmp;
}
}
conoutf("not allowed in this execution context: %s", id->name);
scripterr();
return;
}
commandret = conc((const char **)elems.getbuf(), elems.length(), true);
elems.deletearrays();
swap.deletearrays();
if((id->type == ID_VAR && id->minval > id->maxval) || (id->type == ID_FVAR && id->minvalf > id->maxvalf)) { conoutf("variable %s is read-only", id->name); return; }
int val = 0;
switch(id->type)
{
case ID_VAR: val = *id->storage.i; break;
case ID_FVAR: val = int(*id->storage.f); break;
case ID_SVAR: { { if(id->getfun) ((void (__cdecl *)())id->getfun)(); } val = ATOI(*id->storage.s); break; }
case ID_ALIAS: val = ATOI(id->action); break;
default: return;
}
switch(op)
{
case '+': val += arg; break;
case '-': val -= arg; break;
case '*': val *= arg; break;
case '/': val = arg ? val / arg : 0; break;
}
switch(id->type)
{
case ID_VAR: *id->storage.i = clamp(val, id->minval, id->maxval); break;
case ID_FVAR: *id->storage.f = clamp((float)val, id->minvalf, id->maxvalf); break;
case ID_SVAR: { string str; itoa(str, val); *id->storage.s = exchangestr(*id->storage.s, str); break; }
case ID_ALIAS: { string str; itoa(str, val); alias(name, str); return; }
}
if(id->fun) ((void (__cdecl *)())id->fun)();
}
COMMAND(swapelements, "ss");
void addeq(char *name, int *arg) { modifyvar(name, *arg, '+'); } COMMANDN(+=, addeq, "si");
void subeq(char *name, int *arg) { modifyvar(name, *arg, '-'); } COMMANDN(-=, subeq, "si");
void muleq(char *name, int *arg) { modifyvar(name, *arg, '*'); } COMMANDN(*=, muleq, "si");
void diveq(char *name, int *arg) { modifyvar(name, *arg, '/'); } COMMANDN(div=, diveq, "si");
void modifyfvar(const char *name, float arg, char op)
{
ident *id = idents->access(name);
if(!id) return;
if(identaccessdenied(id))
{
conoutf("not allowed in this execution context: %s", id->name);
scripterr();
return;
}
if((id->type == ID_VAR && id->minval > id->maxval) || (id->type == ID_FVAR && id->minvalf > id->maxvalf)) { conoutf("variable %s is read-only", id->name); return; }
float val = 0;
switch(id->type)
{
case ID_VAR: val = *id->storage.i; break;
case ID_FVAR: val = *id->storage.f; break;
case ID_SVAR: { { if(id->getfun) ((void (__cdecl *)())id->getfun)(); } val = atof(*id->storage.s); break; }
case ID_ALIAS: val = atof(id->action); break;
default: return;
}
switch(op)
{
case '+': val += arg; break;
case '-': val -= arg; break;
case '*': val *= arg; break;
case '/': val = (arg == 0.0f) ? 0 : val / arg; break;
}
switch(id->type)
{
case ID_VAR: *id->storage.i = clamp((int)val, id->minval, id->maxval); break;
case ID_FVAR: *id->storage.f = clamp(val, id->minvalf, id->maxvalf); break;
case ID_SVAR: *id->storage.s = exchangestr(*id->storage.s, floatstr(val)); break;
case ID_ALIAS: alias(name, floatstr(val)); return;
}
if(id->fun) ((void (__cdecl *)())id->fun)();
}
void addeqf(char *name, float *arg) { modifyfvar(name, *arg, '+'); } COMMANDN(+=f, addeqf, "sf");
void subeqf(char *name, float *arg) { modifyfvar(name, *arg, '-'); } COMMANDN(-=f, subeqf, "sf");
void muleqf(char *name, float *arg) { modifyfvar(name, *arg, '*'); } COMMANDN(*=f, muleqf, "sf");
void diveqf(char *name, float *arg) { modifyfvar(name, *arg, '/'); } COMMANDN(div=f, diveqf, "sf");
void add_(char **args, int numargs)
{
@@ -1788,63 +1731,6 @@ void dumpexecutionstack(stream *f)
}
#ifndef STANDALONE
COMMANDF(watchingdemo, "", () { intret(watchingdemo); });
COMMANDF(systime, "", () { result(numtime()); });
COMMANDF(timestamp, "", () { result(timestring(true, "%Y %m %d %H %M %S")); });
COMMANDF(datestring, "", () { result(timestring(true, "%c")); });
COMMANDF(timestring, "", ()
{
const char *res = timestring(true, "%H:%M:%S");
result(res[0] == '0' ? res + 1 : res);
});
COMMANDF(millis, "", () { intret(totalmillis); });
COMMANDF(strlen, "s", (char *s) { intret(strlen(s)); });
void substr_(char *fs, int *pa, int *len)
{
int ia = *pa;
int ilen = *len;
int fslen = (int)strlen(fs);
if(ia<0) ia += fslen;
if(ia>fslen || ia < 0 || ilen < 0) return;
if(!ilen) ilen = fslen-ia;
if(ilen >= 0 && ilen < int(strlen(fs+ia))) (fs+ia)[ilen] = '\0';
result(fs+ia);
}
COMMANDN(substr, substr_, "sii");
void strpos_(char *haystack, char *needle, int *occurence)
{
int position = -1;
char *ptr = haystack;
if(haystack && needle)
for(int iocc = *occurence; iocc >= 0; iocc--)
{
ptr = strstr(ptr, needle);
if (ptr)
{
position = ptr-haystack;
ptr += strlen(needle);
}
else
{
position = -1;
break;
}
}
intret(position);
}
COMMANDN(strpos, strpos_, "ssi");
COMMANDF(l0, "ii", (int *p, int *v) { defformatstring(f)("%%0%dd", clamp(*p, 0, 200)); defformatstring(r)(f, *v); result(r); });
COMMANDF(h0, "ii", (int *p, int *v) { defformatstring(f)("%%0%dx", clamp(*p, 0, 200)); defformatstring(r)(f, *v); result(r); });
COMMANDF(getmode, "i", (int *acr) { result(modestr(gamemode, *acr != 0)); });
void listoptions(char *s)
{
@@ -1856,75 +1742,6 @@ void listoptions(char *s)
}
COMMAND(listoptions, "s");
const char *currentserver(int i) // [client version]
{
static string curSRVinfo;
// using the curpeer directly we can get the info of our currently connected server
string r;
r[0] = '\0';
extern ENetPeer *curpeer;
if(curpeer)
{
switch(i)
{
case 1: // IP
{
uchar *ip = (uchar *)&curpeer->address.host;
formatstring(r)("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
break;
}
case 2: // HOST
{
char hn[1024];
formatstring(r)("%s", (enet_address_get_host(&curpeer->address, hn, sizeof(hn))==0) ? hn : "unknown");
break;
}
case 3: // PORT
{
formatstring(r)("%d", curpeer->address.port);
break;
}
case 4: // STATE
{
const char *statenames[] =
{
"disconnected",
"connecting",
"acknowledging connect",
"connection pending",
"connection succeeded",
"connected",
"disconnect later",
"disconnecting",
"acknowledging disconnect",
"zombie"
};
if(curpeer->state>=0 && curpeer->state<int(sizeof(statenames)/sizeof(statenames[0])))
copystring(r, statenames[curpeer->state]);
break; // 5 == Connected (compare ../enet/include/enet/enet.h +165)
}
// CAUTION: the following are only filled if the serverbrowser was used or the scoreboard shown
// SERVERNAME
case 5: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->name); break; }
// DESCRIPTION (3)
case 6: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->sdesc); break; }
case 7: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->description); break; }
// CAUTION: the following is only the last full-description _seen_ in the serverbrowser!
case 8: { serverinfo *si = getconnectedserverinfo(); if(si) copystring(r, si->full); break; }
// just IP & PORT as default response - always available, no lookup-delay either
default:
{
uchar *ip = (uchar *)&curpeer->address.host;
formatstring(r)("%d.%d.%d.%d %d", ip[0], ip[1], ip[2], ip[3], curpeer->address.port);
break;
}
}
}
copystring(curSRVinfo, r);
return curSRVinfo;
}
COMMANDF(curserver, "i", (int *i) { result(currentserver(*i)); });
#endif
void debugargs(char **args, int numargs)
-2
View File
@@ -128,8 +128,6 @@ void conoutf(const char *s, ...)
delete[] conline; conline=newstring(sf);
}
COMMANDF(strstr, "ss", (char *a, char *b) { intret(strstr(a, b) ? 1 : 0); });
int rendercommand(int x, int y, int w)
{
const char *useprompt = cmdprompt ? cmdprompt : "#";
+4 -4
View File
@@ -65,7 +65,7 @@ struct docident
struct docsection
{
char *name;
vector<docident *> idents;
vector<docident *> sidents;
void *menu;
docsection() : name(NULL) {};
@@ -95,7 +95,7 @@ void adddocident(char *name, char *desc)
if(!name || !desc || !lastsection || !*name) { lastident = NULL; return; }
name = newstring(name);
docident &c = docidents[name];
lastsection->idents.add(&c);
lastsection->sidents.add(&c);
c.name = name;
c.desc = newstring(desc);
lastident = &c;
@@ -672,9 +672,9 @@ void renderdocsection(void *menu, bool init)
loopv(sections)
{
if(sections[i].menu != menu) continue;
loopvj(sections[i].idents)
loopvj(sections[i].sidents)
{
docident &id = *sections[i].idents[j];
docident &id = *sections[i].sidents[j];
msection &s = msections.add();
s.name = id.name;
formatstring(s.cmd)("saycommand [/%s ]", id.name);
+1
View File
@@ -222,3 +222,4 @@ enum
#define FTXT__MEDIAFILEPATH (FTXT_FILENAME | FTXT_ALLOWSLASH)
#define FTXT__ZIPDESC (FTXT_NOWHITE | FTXT_ALLOWBLANKS | FTXT_TABTOBLANK | FTXT_NOCOLOR | FTXT_SAFECS)
#define FTXT__CERTFILENAME (FTXT_MAPNAME | FTXT_TOLOWER)
#define FTXT__CONSOLEPASTE (FTXT_TABTOBLANK)
-1
View File
@@ -1010,7 +1010,6 @@ extern void writecfg();
extern void deletecfg();
extern void identnames(vector<const char *> &names, bool builtinonly);
extern void explodelist(const char *s, vector<char *> &elems);
extern char *indexlist(const char *s, int pos);
extern const char *escapestring(const char *s, bool force = true, bool noquotes = false);
extern int execcontext;
extern void pushscontext(int newcontext);