forked from github/server
start to get rid of getstrtoken(), which uses an internal static buffer and causes horrible bugs when called multiple times.
This commit is contained in:
parent
0b58ca9176
commit
5cdc85f6bf
|
@ -1485,6 +1485,7 @@ static void create_item(unit * u, const item_type * itype, int want)
|
|||
|
||||
int make_cmd(unit * u, struct order *ord)
|
||||
{
|
||||
char token[128];
|
||||
region *r = u->region;
|
||||
const building_type *btype = 0;
|
||||
const ship_type *stype = 0;
|
||||
|
@ -1498,15 +1499,16 @@ int make_cmd(unit * u, struct order *ord)
|
|||
|
||||
kwd = init_order(ord);
|
||||
assert(kwd == K_MAKE);
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
|
||||
if (s) {
|
||||
m = atoi((const char *)s);
|
||||
sprintf(ibuf, "%d", m);
|
||||
if (!strcmp(ibuf, (const char *)s)) {
|
||||
/* a quantity was given */
|
||||
s = getstrtoken();
|
||||
} else {
|
||||
s = getstrtok(token, sizeof(token));
|
||||
}
|
||||
else {
|
||||
m = INT_MAX;
|
||||
}
|
||||
if (s) {
|
||||
|
@ -1520,7 +1522,7 @@ int make_cmd(unit * u, struct order *ord)
|
|||
cmistake(u, ord, 275, MSG_PRODUCE);
|
||||
}
|
||||
else {
|
||||
const char * s = getstrtoken();
|
||||
const char * s = getstrtok(token, sizeof(token));
|
||||
direction_t d = s ? get_direction(s, u->faction->locale) : NODIRECTION;
|
||||
if (d != NODIRECTION) {
|
||||
build_road(r, u, m, d);
|
||||
|
|
|
@ -207,7 +207,7 @@ static order_data *create_data(keyword_t kwd, const char *sptr, int lindex)
|
|||
|
||||
/* learning, only one order_data per skill required */
|
||||
if (kwd == K_STUDY) {
|
||||
skill_t sk = get_skill(parse_token(&sptr), lang);
|
||||
skill_t sk = get_skill(parse_token_depr(&sptr), lang);
|
||||
switch (sk) {
|
||||
case NOSKILL: /* fehler */
|
||||
break;
|
||||
|
@ -364,11 +364,11 @@ order *parse_order(const char *s, const struct locale * lang)
|
|||
++s;
|
||||
}
|
||||
sptr = s;
|
||||
p = *sptr ? parse_token(&sptr) : 0;
|
||||
p = *sptr ? parse_token_depr(&sptr) : 0;
|
||||
kwd = p ? get_keyword(p, lang) : NOKEYWORD;
|
||||
if (kwd == K_MAKE) {
|
||||
const char *s, *sp = sptr;
|
||||
s = parse_token(&sp);
|
||||
s = parse_token_depr(&sp);
|
||||
if (s && isparam(s, lang, P_TEMP)) {
|
||||
kwd = K_MAKETEMP;
|
||||
sptr = sp;
|
||||
|
@ -570,6 +570,6 @@ keyword_t init_order(const struct order *ord)
|
|||
|
||||
assert(ord && ord->data);
|
||||
if (ord->data->_str) cmd = _strdup(ord->data->_str);
|
||||
init_tokens_str(cmd, cmd);
|
||||
init_tokens_str(cmd);
|
||||
return ord->data->_keyword;
|
||||
}
|
||||
|
|
|
@ -128,19 +128,19 @@ static void test_init_order(CuTest *tc) {
|
|||
|
||||
static void test_getstrtoken(CuTest *tc) {
|
||||
char *cmd = _strdup("hurr \"durr\" \"\" \'\'");
|
||||
init_tokens_str(cmd, cmd);
|
||||
init_tokens_str(cmd);
|
||||
CuAssertStrEquals(tc, "hurr", getstrtoken());
|
||||
CuAssertStrEquals(tc, "durr", getstrtoken());
|
||||
CuAssertStrEquals(tc, "", getstrtoken());
|
||||
CuAssertStrEquals(tc, "", getstrtoken());
|
||||
CuAssertStrEquals(tc, 0, getstrtoken());
|
||||
init_tokens_str(0, 0);
|
||||
init_tokens_str(0);
|
||||
CuAssertStrEquals(tc, 0, getstrtoken());
|
||||
}
|
||||
|
||||
static void test_skip_token(CuTest *tc) {
|
||||
char *cmd = _strdup("hurr \"durr\"");
|
||||
init_tokens_str(cmd, cmd);
|
||||
init_tokens_str(cmd);
|
||||
skip_token();
|
||||
CuAssertStrEquals(tc, "durr", getstrtoken());
|
||||
CuAssertStrEquals(tc, 0, getstrtoken());
|
||||
|
|
|
@ -169,7 +169,7 @@ static unit *unitorders(FILE * F, int enc, struct faction *f)
|
|||
if (s[0]) {
|
||||
if (s[0] != '@') {
|
||||
const char *stok = s;
|
||||
stok = parse_token(&stok);
|
||||
stok = parse_token_depr(&stok);
|
||||
|
||||
if (stok) {
|
||||
bool quit = false;
|
||||
|
@ -267,11 +267,12 @@ int readorders(const char *filename)
|
|||
* Partei */
|
||||
|
||||
while (b) {
|
||||
char token[128];
|
||||
const struct locale *lang = f ? f->locale : default_locale;
|
||||
param_t p;
|
||||
const char *s;
|
||||
init_tokens_str(b, NULL);
|
||||
s = getstrtoken();
|
||||
init_tokens_str(b);
|
||||
s = getstrtok(token, sizeof(token));
|
||||
p = s ? findparam(s, lang) : NOPARAM;
|
||||
switch (p) {
|
||||
#undef LOCALE_CHANGE
|
||||
|
@ -308,7 +309,7 @@ int readorders(const char *filename)
|
|||
if (!b) {
|
||||
break;
|
||||
}
|
||||
init_tokens_str(b, NULL);
|
||||
init_tokens_str(b);
|
||||
b = getstrtoken();
|
||||
p = (!b || b[0] == '@') ? NOPARAM : findparam(b, lang);
|
||||
} while ((p != P_UNIT || !f) && p != P_FACTION && p != P_NEXT
|
||||
|
|
13
src/laws.c
13
src/laws.c
|
@ -1159,13 +1159,14 @@ void do_enter(struct region *r, bool is_final_attempt)
|
|||
while (*ordp) {
|
||||
order *ord = *ordp;
|
||||
if (getkeyword(ord) == K_ENTER) {
|
||||
char token[128];
|
||||
param_t p;
|
||||
int id;
|
||||
unit *ulast = NULL;
|
||||
const char * s;
|
||||
|
||||
init_order(ord);
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
p = findparam_ex(s, u->faction->locale);
|
||||
id = getid();
|
||||
|
||||
|
@ -2613,11 +2614,12 @@ int guard_off_cmd(unit * u, struct order *ord)
|
|||
|
||||
int reshow_cmd(unit * u, struct order *ord)
|
||||
{
|
||||
char lbuf[64];
|
||||
const char *s;
|
||||
param_t p = NOPARAM;
|
||||
|
||||
init_order(ord);
|
||||
s = getstrtoken();
|
||||
s = getstrtok(lbuf, sizeof(lbuf));
|
||||
|
||||
if (s && isparam(s, u->faction->locale, P_ANY)) {
|
||||
p = getparam(u->faction->locale);
|
||||
|
@ -2676,12 +2678,13 @@ int status_cmd(unit * u, struct order *ord)
|
|||
|
||||
int combatspell_cmd(unit * u, struct order *ord)
|
||||
{
|
||||
char token[128];
|
||||
const char *s;
|
||||
int level = 0;
|
||||
spell *sp = 0;
|
||||
|
||||
init_order(ord);
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
|
||||
/* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */
|
||||
if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) {
|
||||
|
@ -2694,7 +2697,7 @@ int combatspell_cmd(unit * u, struct order *ord)
|
|||
/* Merken, setzen kommt erst später */
|
||||
level = getint();
|
||||
level = _max(0, level);
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
}
|
||||
|
||||
sp = unit_getspell(u, s, u->faction->locale);
|
||||
|
@ -2703,7 +2706,7 @@ int combatspell_cmd(unit * u, struct order *ord)
|
|||
return 0;
|
||||
}
|
||||
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
|
||||
if (findparam(s, u->faction->locale) == P_NOT) {
|
||||
/* KAMPFZAUBER "<Spruchname>" NICHT löscht diesen speziellen
|
||||
|
|
12
src/magic.c
12
src/magic.c
|
@ -2495,6 +2495,7 @@ static bool is_moving_ship(const region * r, ship * sh)
|
|||
|
||||
static castorder *cast_cmd(unit * u, order * ord)
|
||||
{
|
||||
char token[128];
|
||||
region *r = u->region;
|
||||
region *target_r = r;
|
||||
int level, range;
|
||||
|
@ -2518,7 +2519,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
level = eff_skill(u, SK_MAGIC, r);
|
||||
|
||||
init_order(ord);
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
param = findparam(s, u->faction->locale);
|
||||
/* für Syntax ' STUFE x REGION y z ' */
|
||||
if (param == P_LEVEL) {
|
||||
|
@ -2529,7 +2530,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
cmistake(u, ord, 10, MSG_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
param = findparam(s, u->faction->locale);
|
||||
}
|
||||
if (param == P_REGION) {
|
||||
|
@ -2546,7 +2547,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
"unit region command", u, u->region, ord));
|
||||
return 0;
|
||||
}
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
param = findparam(s, u->faction->locale);
|
||||
}
|
||||
/* für Syntax ' REGION x y STUFE z '
|
||||
|
@ -2559,7 +2560,7 @@ static castorder *cast_cmd(unit * u, order * ord)
|
|||
cmistake(u, ord, 10, MSG_MAGIC);
|
||||
return 0;
|
||||
}
|
||||
s = getstrtoken();
|
||||
s = getstrtok(token, sizeof(token));
|
||||
}
|
||||
if (!s || !s[0] || strlen(s) == 0) {
|
||||
/* Fehler "Es wurde kein Zauber angegeben" */
|
||||
|
@ -2935,7 +2936,7 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan
|
|||
if (sb) {
|
||||
select_spellbook(&tokens, sb, lang);
|
||||
}
|
||||
|
||||
#if 0 // TODO: some familiars can cast spells from the mage's spellbook?
|
||||
u = get_familiar_mage(u);
|
||||
if (u) {
|
||||
sb = unit_get_spellbook(u);
|
||||
|
@ -2943,6 +2944,7 @@ spell *unit_getspell(struct unit *u, const char *name, const struct locale * lan
|
|||
select_spellbook(&tokens, sb, lang);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tokens) {
|
||||
variant token;
|
||||
|
|
|
@ -2615,7 +2615,7 @@ static int hunt(unit * u, order * ord)
|
|||
/* In command steht jetzt das NACH-Kommando. */
|
||||
|
||||
/* NACH ignorieren und Parsing initialisieren. */
|
||||
init_tokens_str(command, NULL);
|
||||
init_tokens_str(command);
|
||||
getstrtoken();
|
||||
/* NACH ausführen */
|
||||
move(u, false);
|
||||
|
|
|
@ -48,6 +48,7 @@ int RunAllTests(void)
|
|||
RUN_TESTS(suite, base36);
|
||||
RUN_TESTS(suite, bsdstring);
|
||||
RUN_TESTS(suite, functions);
|
||||
RUN_TESTS(suite, parser);
|
||||
RUN_TESTS(suite, umlaut);
|
||||
RUN_TESTS(suite, unicode);
|
||||
RUN_TESTS(suite, strings);
|
||||
|
|
|
@ -2,6 +2,7 @@ project(util C)
|
|||
|
||||
SET(_TEST_FILES
|
||||
base36.test.c
|
||||
parser.test.c
|
||||
attrib.test.c
|
||||
strings.test.c
|
||||
bsdstring.test.c
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
|
||||
typedef struct parser_state {
|
||||
const char *current_token;
|
||||
char *current_cmd;
|
||||
struct parser_state *next;
|
||||
} parser_state;
|
||||
|
||||
|
@ -50,22 +49,17 @@ static int eatwhitespace_c(const char **str_p)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void init_tokens_str(const char *initstr, char *cmd)
|
||||
void init_tokens_str(const char *initstr)
|
||||
{
|
||||
if (states == NULL) {
|
||||
states = malloc(sizeof(parser_state));
|
||||
}
|
||||
else if (states->current_cmd && states->current_cmd!=cmd) {
|
||||
free(states->current_cmd);
|
||||
}
|
||||
states->current_cmd = cmd;
|
||||
states->current_token = initstr;
|
||||
}
|
||||
|
||||
void parser_pushstate(void)
|
||||
{
|
||||
parser_state *new_state = malloc(sizeof(parser_state));
|
||||
new_state->current_cmd = NULL;
|
||||
new_state->current_token = NULL;
|
||||
new_state->next = states;
|
||||
states = new_state;
|
||||
|
@ -74,8 +68,6 @@ void parser_pushstate(void)
|
|||
void parser_popstate(void)
|
||||
{
|
||||
parser_state *new_state = states->next;
|
||||
if (states->current_cmd != NULL)
|
||||
free(states->current_cmd);
|
||||
free(states);
|
||||
states = new_state;
|
||||
}
|
||||
|
@ -128,83 +120,104 @@ void skip_token(void)
|
|||
}
|
||||
}
|
||||
|
||||
const char *parse_token(const char **str)
|
||||
char *parse_token(const char **str, char *lbuf, size_t len)
|
||||
{
|
||||
char *cursor = lbuf;
|
||||
char quotechar = 0;
|
||||
bool escape = false;
|
||||
const char *ctoken = *str;
|
||||
|
||||
if (!ctoken) {
|
||||
return 0;
|
||||
}
|
||||
eatwhitespace_c(&ctoken);
|
||||
if (!*ctoken) {
|
||||
return 0;
|
||||
}
|
||||
while (*ctoken && cursor-len < lbuf-1) {
|
||||
ucs4_t ucs;
|
||||
size_t len;
|
||||
bool copy = false;
|
||||
|
||||
unsigned char utf8_character = *(unsigned char *)ctoken;
|
||||
if (~utf8_character & 0x80) {
|
||||
ucs = utf8_character;
|
||||
len = 1;
|
||||
}
|
||||
else {
|
||||
int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len);
|
||||
if (ret != 0) {
|
||||
log_warning("illegal character sequence in UTF8 string: %s\n", ctoken);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (escape) {
|
||||
copy = true;
|
||||
escape = false;
|
||||
}
|
||||
else if (iswxspace((wint_t)ucs)) {
|
||||
if (quotechar == 0)
|
||||
break;
|
||||
copy = true;
|
||||
}
|
||||
else if (utf8_character == '"' || utf8_character == '\'') {
|
||||
if (utf8_character == quotechar) {
|
||||
++ctoken;
|
||||
break;
|
||||
}
|
||||
else if (quotechar == 0) {
|
||||
quotechar = utf8_character;
|
||||
++ctoken;
|
||||
}
|
||||
else {
|
||||
*cursor++ = *ctoken++;
|
||||
}
|
||||
}
|
||||
else if (utf8_character == SPACE_REPLACEMENT) {
|
||||
*cursor++ = ' ';
|
||||
++ctoken;
|
||||
}
|
||||
else if (utf8_character == ESCAPE_CHAR) {
|
||||
escape = true;
|
||||
++ctoken;
|
||||
}
|
||||
else {
|
||||
copy = true;
|
||||
}
|
||||
if (copy) {
|
||||
memcpy(cursor, ctoken, len);
|
||||
cursor += len;
|
||||
ctoken += len;
|
||||
}
|
||||
}
|
||||
|
||||
assert(cursor - len < lbuf - 1); // TODO: handle too-small buffers
|
||||
*cursor = '\0';
|
||||
*str = ctoken;
|
||||
return lbuf;
|
||||
}
|
||||
|
||||
const char *parse_token_depr(const char **str)
|
||||
{
|
||||
static char lbuf[MAXTOKENSIZE]; /* STATIC_RESULT: used for return, not across calls */
|
||||
char *cursor = lbuf;
|
||||
char quotechar = 0;
|
||||
bool escape = false;
|
||||
const char *ctoken = *str;
|
||||
|
||||
if (!ctoken) {
|
||||
return 0;
|
||||
}
|
||||
eatwhitespace_c(&ctoken);
|
||||
if (!*ctoken) {
|
||||
return 0;
|
||||
}
|
||||
while (*ctoken && cursor - lbuf < MAXTOKENSIZE - 1) {
|
||||
ucs4_t ucs;
|
||||
size_t len;
|
||||
bool copy = false;
|
||||
|
||||
unsigned char utf8_character = *(unsigned char *)ctoken;
|
||||
if (~utf8_character & 0x80) {
|
||||
ucs = utf8_character;
|
||||
len = 1;
|
||||
} else {
|
||||
int ret = unicode_utf8_to_ucs4(&ucs, ctoken, &len);
|
||||
if (ret != 0) {
|
||||
log_warning("illegal character sequence in UTF8 string: %s\n", ctoken);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (escape) {
|
||||
copy = true;
|
||||
escape = false;
|
||||
} else if (iswxspace((wint_t) ucs)) {
|
||||
if (quotechar == 0)
|
||||
break;
|
||||
copy = true;
|
||||
} else if (utf8_character == '"' || utf8_character == '\'') {
|
||||
if (utf8_character == quotechar) {
|
||||
++ctoken;
|
||||
break;
|
||||
} else if (quotechar == 0) {
|
||||
quotechar = utf8_character;
|
||||
++ctoken;
|
||||
} else {
|
||||
*cursor++ = *ctoken++;
|
||||
}
|
||||
} else if (utf8_character == SPACE_REPLACEMENT) {
|
||||
*cursor++ = ' ';
|
||||
++ctoken;
|
||||
} else if (utf8_character == ESCAPE_CHAR) {
|
||||
escape = true;
|
||||
++ctoken;
|
||||
} else {
|
||||
copy = true;
|
||||
}
|
||||
if (copy) {
|
||||
memcpy(cursor, ctoken, len);
|
||||
cursor += len;
|
||||
ctoken += len;
|
||||
}
|
||||
}
|
||||
|
||||
*cursor = '\0';
|
||||
*str = ctoken;
|
||||
return lbuf;
|
||||
return parse_token(str, lbuf, MAXTOKENSIZE);
|
||||
}
|
||||
|
||||
const char *getstrtoken(void)
|
||||
{
|
||||
return parse_token((const char **)&states->current_token);
|
||||
char lbuf[MAXTOKENSIZE];
|
||||
return parse_token((const char **)&states->current_token, lbuf, MAXTOKENSIZE);
|
||||
}
|
||||
|
||||
const char *getstrtok(char *lbuf, size_t bufsize)
|
||||
{
|
||||
return parse_token((const char **)&states->current_token, lbuf, bufsize);
|
||||
}
|
||||
|
||||
int getid(void)
|
||||
{
|
||||
const char *str = getstrtoken();
|
||||
char token[16];
|
||||
const char *str = getstrtok(token, sizeof(token));
|
||||
int i = str ? atoi36(str) : 0;
|
||||
if (i < 0) {
|
||||
return -1;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* +-------------------+ Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||
* | | Enno Rehling <enno@eressea.de>
|
||||
* | Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
|
||||
* | (c) 1998 - 2007 |
|
||||
* | (c) 1998 - 2007 |
|
||||
* | | This program may not be used, modified or distributed
|
||||
* +-------------------+ without prior permission by the authors of Eressea.
|
||||
*
|
||||
|
@ -14,14 +14,16 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void init_tokens_str(const char *initstr, char *cmd); /* initialize token parsing, take ownership of cmd */
|
||||
void skip_token(void);
|
||||
const char *parse_token(const char **str);
|
||||
void parser_pushstate(void);
|
||||
void parser_popstate(void);
|
||||
bool parser_end(void);
|
||||
const char *getstrtoken(void);
|
||||
int getid(void);
|
||||
void init_tokens_str(const char *initstr); /* initialize token parsing */
|
||||
void skip_token(void);
|
||||
const char *parse_token_depr(const char **str);
|
||||
char *parse_token(const char **str, char *buffer, size_t bufsize);
|
||||
void parser_pushstate(void);
|
||||
void parser_popstate(void);
|
||||
bool parser_end(void);
|
||||
const char *getstrtoken(void);
|
||||
const char *getstrtok(char *lbuf, size_t bufsize);
|
||||
int getid(void);
|
||||
#define getshipid() getid()
|
||||
#define getfactionid() getid()
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#include <platform.h>
|
||||
#include "parser.h"
|
||||
|
||||
#include <CuTest.h>
|
||||
|
||||
static void test_parser(CuTest *tc) {
|
||||
init_tokens_str("HELP ONE TWO THREE");
|
||||
}
|
||||
|
||||
CuSuite *get_parser_suite(void)
|
||||
{
|
||||
CuSuite *suite = CuSuiteNew();
|
||||
SUITE_ADD_TEST(suite, test_parser);
|
||||
return suite;
|
||||
}
|
Loading…
Reference in New Issue