Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
automatic escaping for strings
* parsed words starting with " will handle richtext
* all strings in saved.cfg that need escaping are escaped
* new command "escape" to escape a string manually

DOCREF escape
  • Loading branch information
ac-stef committed Feb 23, 2015
1 parent 1956f0a commit d585550
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 31 deletions.
104 changes: 74 additions & 30 deletions source/src/command.cpp
Expand Up @@ -419,11 +419,18 @@ char *parseword(const char *&p, int arg, int &infix) // pa
if(p[0]=='/' && p[1]=='/') p += strcspn(p, "\n\0");
if(*p=='\"')
{
p++;
const char *word = p;
p += strcspn(p, "\"\r\n\0");
char *s = newstring(word, p-word);
const char *word = p + 1;
do
{
p++;
p += strcspn(p, "\"\n\r");
}
while(*p == '\"' && p[-1] == '\\'); // skip escaped quotes
char *s = newstring(word, p - word);
if(*p=='\"') p++;
#ifndef STANDALONE
filterrichtext(s, s, strlen(s));
#endif
return s;
}
if(*p=='(') return parseexp(p, ')');
Expand Down Expand Up @@ -1053,6 +1060,7 @@ void loopa(char *var, int *times, char *body)
popident(*id);
loop_level--;
}

void whilea(char *cond, char *body)
{
loop_level++;
Expand Down Expand Up @@ -1106,7 +1114,7 @@ void format(char **args, int numargs)
}

#define whitespaceskip s += strspn(s, "\n\t \r")
#define elementskip *s=='"' ? (++s, s += strcspn(s, "\"\n\0"), s += *s=='"') : s += strcspn(s, "\n\t \0")
#define elementskip { if(*s=='"') { do { ++s; s += strcspn(s, "\"\n"); } while(*s == '\"' && s[-1] == '\\'); s += *s=='"'; } else s += strcspn(s, "\n\t "); }

void explodelist(const char *s, vector<char *> &elems)
{
Expand All @@ -1115,7 +1123,11 @@ void explodelist(const char *s, vector<char *> &elems)
{
const char *elem = s;
elementskip;
elems.add(*elem=='"' ? newstring(elem+1, s-elem-(s[-1]=='"' ? 2 : 1)) : newstring(elem, s-elem));
char *newelem = *elem == '"' ? newstring(elem + 1, s - elem - (s[-1]=='"' ? 2 : 1)) : newstring(elem, s-elem);
#ifndef STANDALONE
if(*elem == '\"') filterrichtext(newelem, newelem, strlen(newelem));
#endif
elems.add(newelem);
whitespaceskip;
}
}
Expand Down Expand Up @@ -1165,52 +1177,61 @@ char *indexlist(const char *s, int pos)
if(!*s) break;
}
const char *e = s;
char *res;
elementskip;
if(*e=='"')
{
e++;
if(s[-1]=='"') --s;
res = newstring(e, s - e);
#ifndef STANDALONE
filterrichtext(res, res, s - e);
#endif
}
return newstring(e, s-e);
else res = newstring(e, s-e);
return res;
}
COMMANDF(at, "si", (char *s, int *pos) { commandret = indexlist(s, *pos); });

int listlen(char *s)
{
int n = 0;
whitespaceskip;
for(; *s; n++) elementskip, whitespaceskip;
for(; *s; n++) { elementskip; whitespaceskip; }
return n;
}

void at(char *s, int *pos)
{
commandret = indexlist(s, *pos);
}

int find(const char *s, const char *key)
int find(char *s, const char *key)
{
whitespaceskip;
int len = strlen(key);
for(int i = 0; *s; i++)
{
const char *a = s, *e = s;
char *e = s;
elementskip;
if(*e=='"')
char *a = s;
if(*e == '"')
{
e++;
if(s[-1]=='"') --s;
if(s[-1] == '"') --s;
if(s - e >= len)
{
*s = '\0';
#ifndef STANDALONE
filterrichtext(e, e, s - e);
#endif
if(int(strlen(e)) == len && !strncmp(e, key, len)) return i;
*s = ' ';
}
}
if(s-e==len && !strncmp(e, key, s-e)) return i;
else s = a;
elementskip, whitespaceskip;
else if(s - e == len && !strncmp(e, key, s - e)) return i;
s = a;
whitespaceskip;
}
return -1;
}
COMMANDF(findlist, "ss", (char *s, char *key) { intret(find(s, key)); });

void findlist(char *s, char *key)
{
intret(find(s, key));
}
void colora(char *s)
{
if(s[0] && s[1]=='\0')
Expand Down Expand Up @@ -1354,9 +1375,7 @@ COMMAND(concatword, "w");
COMMAND(format, "v");
COMMAND(result, "s");
COMMANDF(execute, "s", (char *s) { intret(execute(s)); });
COMMAND(at, "si");
COMMANDF(listlen, "s", (char *l) { intret(listlen(l)); });
COMMAND(findlist, "ss");
COMMANDN(tolower, toLower, "s");
COMMANDN(toupper, toUpper, "s");
COMMAND(testchar, "si");
Expand Down Expand Up @@ -1406,14 +1425,39 @@ COMMANDF(strcmp, "ss", (char *a, char *b) { intret((strcmp(a, b) == 0) ? 1 : 0);
COMMANDF(rnd, "i", (int *a) { intret(*a>0 ? rnd(*a) : 0); });

#ifndef STANDALONE

const char *escapestring(const char *s, bool force)
{
static vector<char> strbuf[3];
static int stridx = 0;
if(!s) return force ? "\"\"" : "";
if(!force && !*(s + strcspn(s, "\"/\\;()[] \f\t\r\n"))) return s;
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();
}
COMMANDF(escape, "s", (const char *s) { result(escapestring(s));});

void writecfg()
{
filerotate("config/saved", "cfg", CONFIGROTATEMAX); // keep five old config sets
stream *f = openfile(path("config/saved.cfg", true), "w");
if(!f) return;
f->printf("// 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");
f->printf("// basic settings\n\n");
f->printf("name \"%s\"\n", player1->name);
f->printf("name %s\n", escapestring(player1->name, false));
loopi(CROSSHAIR_NUM) if(crosshairs[i] && crosshairs[i] != notexture)
{
f->printf("loadcrosshair %s %s\n", crosshairnames[i], behindpath(crosshairs[i]->name));
Expand Down Expand Up @@ -1448,7 +1492,7 @@ void writecfg()
if(*id.storage.f != id.defaultvalf) f->printf("%s %s\n", id.name, floatstr(*id.storage.f));
break;
}
case ID_SVAR: f->printf("%s [%s]\n", id.name, *id.storage.s); break;
case ID_SVAR: f->printf("%s %s\n", id.name, escapestring(*id.storage.s, false)); break;
}
);
f->printf("\n// weapon settings\n\n");
Expand All @@ -1462,14 +1506,14 @@ void writecfg()
enumerate(*idents, ident, id,
if(id.type==ID_ALIAS && id.persist && id.action[0] && strncmp(id.name, "demodesc_", 9))
{
f->printf("%s = [%s]\n", id.name, id.action);
f->printf("alias %s %s\n", escapestring(id.name, false), escapestring(id.action, false));
}
);
f->printf("\n// demo descriptions\n\n");
enumerate(*idents, ident, id,
if(id.type==ID_ALIAS && id.persist && id.action[0] && !strncmp(id.name, "demodesc_", 9) && id.action)
{
f->printf("%s = [%s]\n", id.name, id.action);
f->printf("alias %s %s\n", escapestring(id.name, false), escapestring(id.action, false));
}
);
f->printf("\n");
Expand Down
2 changes: 1 addition & 1 deletion source/src/console.cpp
Expand Up @@ -606,7 +606,7 @@ void writebinds(stream *f)
loopv(keyms)
{
keym *km = &keyms[i];
loopj(3) if(*km->actions[j]) f->printf("%s \"%s\" [%s]\n", keycmd(j), km->name, km->actions[j]);
loopj(3) if(*km->actions[j]) f->printf("%s \"%s\" %s\n", keycmd(j), km->name, escapestring(km->actions[j]));
}
}

1 change: 1 addition & 0 deletions source/src/protos.h
Expand Up @@ -847,6 +847,7 @@ extern char *strreplace(char *dest, const char *source, const char *search, cons
extern void pushscontext(int newcontext);
extern int popscontext();
extern int curscontext();
extern const char *escapestring(const char *s, bool force = true);
extern int execcontext;
extern const char *currentserver(int i);
extern void setcontext(const char *context, const char *info);
Expand Down

0 comments on commit d585550

Please sign in to comment.