From 5cdc85f6bffd3131b95dcac04856bc231baa4e75 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 22 Dec 2014 14:21:24 +0100 Subject: [PATCH 1/5] start to get rid of getstrtoken(), which uses an internal static buffer and causes horrible bugs when called multiple times. --- src/economy.c | 10 ++- src/kernel/order.c | 8 +- src/kernel/order.test.c | 6 +- src/kernel/save.c | 9 ++- src/laws.c | 13 ++-- src/magic.c | 12 +-- src/move.c | 2 +- src/test_eressea.c | 1 + src/util/CMakeLists.txt | 1 + src/util/parser.c | 165 ++++++++++++++++++++++------------------ src/util/parser.h | 20 ++--- src/util/parser.test.c | 15 ++++ 12 files changed, 151 insertions(+), 111 deletions(-) create mode 100644 src/util/parser.test.c diff --git a/src/economy.c b/src/economy.c index 2553a973d..7c8321d88 100644 --- a/src/economy.c +++ b/src/economy.c @@ -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); diff --git a/src/kernel/order.c b/src/kernel/order.c index 93e3d6c96..93692b9d1 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -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; } diff --git a/src/kernel/order.test.c b/src/kernel/order.test.c index f0f9a814d..a45752c95 100644 --- a/src/kernel/order.test.c +++ b/src/kernel/order.test.c @@ -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()); diff --git a/src/kernel/save.c b/src/kernel/save.c index 3671b07fe..f47c3a9be 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -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 diff --git a/src/laws.c b/src/laws.c index 968f36137..341d2b656 100755 --- a/src/laws.c +++ b/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 "" NICHT löscht diesen speziellen diff --git a/src/magic.c b/src/magic.c index 8fc5072f6..d1bd6c661 100644 --- a/src/magic.c +++ b/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; diff --git a/src/move.c b/src/move.c index 69486d2e9..cadb6dca6 100644 --- a/src/move.c +++ b/src/move.c @@ -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); diff --git a/src/test_eressea.c b/src/test_eressea.c index ac18fc0b2..caa54b067 100644 --- a/src/test_eressea.c +++ b/src/test_eressea.c @@ -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); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index a9fde29a8..a08046ae2 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -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 diff --git a/src/util/parser.c b/src/util/parser.c index 2520fd170..12ac19a6e 100644 --- a/src/util/parser.c +++ b/src/util/parser.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; diff --git a/src/util/parser.h b/src/util/parser.h index c268ad22a..2ab7f1b75 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -2,7 +2,7 @@ * +-------------------+ Christian Schlittchen * | | Enno Rehling * | Eressea PBEM host | Katja Zedel - * | (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() diff --git a/src/util/parser.test.c b/src/util/parser.test.c new file mode 100644 index 000000000..f5543a7cb --- /dev/null +++ b/src/util/parser.test.c @@ -0,0 +1,15 @@ +#include +#include "parser.h" + +#include + +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; +} From 870d8001ef8b983eeade71b01961d0dd013a02f6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 22 Dec 2014 14:30:04 +0100 Subject: [PATCH 2/5] more getstrtoken() removal. remove obsolete argument to checkpasswd(). --- src/kernel/faction.c | 4 ++-- src/kernel/faction.h | 2 +- src/kernel/save.c | 5 +++-- src/laws.c | 44 ++++++++++++++++++++++++-------------------- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/kernel/faction.c b/src/kernel/faction.c index f300a11c8..731d817bb 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -278,9 +278,9 @@ unit *addplayer(region * r, faction * f) return u; } -bool checkpasswd(const faction * f, const char *passwd, bool shortp) +bool checkpasswd(const faction * f, const char *passwd) { - if (unicode_utf8_strcasecmp(f->passw, passwd) == 0) + if (passwd && unicode_utf8_strcasecmp(f->passw, passwd) == 0) return true; return false; } diff --git a/src/kernel/faction.h b/src/kernel/faction.h index c8764392d..20c6f9785 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -120,7 +120,7 @@ const char *factionname(const struct faction *f); struct unit *addplayer(struct region *r, faction * f); struct faction *addfaction(const char *email, const char *password, const struct race *frace, const struct locale *loc, int subscription); -bool checkpasswd(const faction * f, const char *passwd, bool shortp); +bool checkpasswd(const faction * f, const char *passwd); void destroyfaction(faction * f); extern void set_alliance(struct faction *a, struct faction *b, int status); diff --git a/src/kernel/save.c b/src/kernel/save.c index f47c3a9be..01cc9fc70 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -224,9 +224,10 @@ static faction *factionorders(void) f = findfaction(fid); if (f != NULL && !fval(f, FFL_NPC)) { - const char *pass = getstrtoken(); + char token[128]; + const char *pass = getstrtok(token, sizeof(token)); - if (!checkpasswd(f, (const char *)pass, true)) { + if (!checkpasswd(f, (const char *)pass)) { log_debug("Invalid password for faction %s\n", itoa36(fid)); ADDMSG(&f->msgs, msg_message("wrongpasswd", "faction password", f->no, pass)); diff --git a/src/laws.c b/src/laws.c index 341d2b656..95894ad9b 100755 --- a/src/laws.c +++ b/src/laws.c @@ -946,14 +946,15 @@ static bool EnhancedQuit(void) int quit_cmd(unit * u, struct order *ord) { + char token[128]; faction *f = u->faction; const char *passwd; keyword_t kwd; kwd = init_order(ord); assert(kwd == K_QUIT); - passwd = getstrtoken(); - if (checkpasswd(f, (const char *)passwd, false)) { + passwd = getstrtok(token, sizeof(token)); + if (checkpasswd(f, (const char *)passwd)) { if (EnhancedQuit()) { int f2_id = getid(); if (f2_id > 0) { @@ -1340,6 +1341,7 @@ void quit(void) int ally_cmd(unit * u, struct order *ord) { + char token[128]; ally *sf, **sfp; faction *f; int keyword, not_kw; @@ -1355,7 +1357,7 @@ int ally_cmd(unit * u, struct order *ord) if (f == u->faction) return 0; - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); if (!s[0]) keyword = P_ANY; @@ -2924,13 +2926,14 @@ void restack_units(void) struct order *ord; for (ord = u->orders; ord; ord = ord->next) { if (getkeyword(ord) == K_SORT) { + char token[128]; const char *s; param_t p; int id; unit *v; init_order(ord); - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); p = findparam(s, u->faction->locale); id = getid(); v = findunit(id); @@ -3000,16 +3003,17 @@ void restack_units(void) int renumber_cmd(unit * u, order * ord) { + char token[128]; const char *s; int i; faction *f = u->faction; init_order(ord); - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); switch (findparam_ex(s, u->faction->locale)) { case P_FACTION: - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); if (s && *s) { int id = atoi36((const char *)s); attrib *a = a_find(f->attribs, &at_number); @@ -3020,7 +3024,7 @@ int renumber_cmd(unit * u, order * ord) break; case P_UNIT: - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); if (s == NULL || *s == 0) { i = newunitid(); } @@ -3063,7 +3067,7 @@ int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 116, MSG_EVENT); break; } - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); if (s == NULL || *s == 0) { i = newcontainerid(); } @@ -3092,7 +3096,7 @@ int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 148, MSG_EVENT); break; } - s = getstrtoken(); + s = getstrtok(token, sizeof(token)); if (*s == 0) { i = newcontainerid(); } @@ -3358,8 +3362,8 @@ void new_units(void) while (*ordp) { order *makeord = *ordp; if (getkeyword(makeord) == K_MAKETEMP) { - const char *token; - char *name = NULL; + char token[128], *name = NULL; + const char *s; int alias; ship *sh; order **newordersp; @@ -3393,9 +3397,9 @@ void new_units(void) init_order(makeord); alias = getid(); - token = getstrtoken(); - if (token && token[0]) { - name = _strdup(token); + s = getstrtok(token, sizeof(token)); + if (s && s[0]) { + name = _strdup(s); } u2 = create_unit(r, u->faction, 0, u->faction->race, alias, name, u); if (name != NULL) @@ -3703,10 +3707,9 @@ void defaultorders(void) order *new_order = 0; const char *s; init_order(ord); - s = getstrtoken(); + s = getstrtok(lbuf, sizeof(lbuf)); if (s) { - strcpy(lbuf, s); - new_order = parse_order(lbuf, u->faction->locale); + new_order = parse_order(s, u->faction->locale); } *ordp = ord->next; ord->next = NULL; @@ -3813,19 +3816,20 @@ static void update_spells(void) int use_cmd(unit * u, struct order *ord) { + char token[128]; const char *t; int n, err = ENOITEM; const item_type *itype; init_order(ord); - t = getstrtoken(); + t = getstrtok(token, sizeof(token)); n = atoi((const char *)t); if (n == 0) { if (isparam(t, u->faction->locale, P_ANY)) { /* BENUTZE ALLES Yanxspirit */ n = INT_MAX; - t = getstrtoken(); + t = getstrtok(token, sizeof(token)); } else { /* BENUTZE Yanxspirit */ @@ -3834,7 +3838,7 @@ int use_cmd(unit * u, struct order *ord) } else { /* BENUTZE 42 Yanxspirit */ - t = getstrtoken(); + t = getstrtok(token, sizeof(token)); } itype = t ? finditemtype(t, u->faction->locale) : NULL; From c8b9044f78e85eab3bc40acedc50a3116a8cce4b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 22 Dec 2014 16:28:17 +0100 Subject: [PATCH 3/5] rename to gettoken, use more widely, add a basic test. --- src/economy.c | 32 +- src/give.c | 11 +- src/items.c | 3 +- src/kernel/build.c | 1442 ++++++++++++++++++++-------------------- src/kernel/command.c | 3 +- src/kernel/config.c | 12 +- src/kernel/save.c | 4 +- src/kernel/unit.c | 13 +- src/laws.c | 102 ++- src/magic.c | 10 +- src/move.c | 22 +- src/util/parser.c | 7 +- src/util/parser.h | 2 +- src/util/parser.test.c | 12 +- 14 files changed, 859 insertions(+), 816 deletions(-) diff --git a/src/economy.c b/src/economy.c index 7c8321d88..0fb810848 100644 --- a/src/economy.c +++ b/src/economy.c @@ -476,7 +476,8 @@ static void recruit(unit * u, struct order *ord, request ** recruitorders) n = getuint(); if (u->number == 0) { - str = getstrtoken(); + char token[128]; + str = gettoken(token, sizeof(token)); if (str && str[0]) { /* Monsters can RECRUIT 15 DRACOID * also: secondary race */ @@ -626,6 +627,7 @@ void give_control(unit * u, unit * u2) int give_control_cmd(unit * u, order * ord) { + char token[128]; region *r = u->region; unit *u2; const char *s; @@ -633,7 +635,7 @@ int give_control_cmd(unit * u, order * ord) init_order(ord); getunit(r, u->faction, &u2); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if (s && isparam(s, u->faction->locale, P_CONTROL)) { message *msg = 0; @@ -676,6 +678,7 @@ int give_control_cmd(unit * u, order * ord) static int forget_cmd(unit * u, order * ord) { + char token[128]; skill_t sk; const char *s; @@ -685,7 +688,7 @@ static int forget_cmd(unit * u, order * ord) } init_order(ord); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if ((sk = get_skill(s, u->faction->locale)) != NOSKILL) { ADDMSG(&u->faction->msgs, msg_message("forget", "unit skill", u, sk)); @@ -1499,14 +1502,14 @@ int make_cmd(unit * u, struct order *ord) kwd = init_order(ord); assert(kwd == K_MAKE); - s = getstrtok(token, sizeof(token)); + s = gettoken(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 = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); } else { m = INT_MAX; @@ -1522,7 +1525,7 @@ int make_cmd(unit * u, struct order *ord) cmistake(u, ord, 275, MSG_PRODUCE); } else { - const char * s = getstrtok(token, sizeof(token)); + const char * s = gettoken(token, sizeof(token)); direction_t d = s ? get_direction(s, u->faction->locale) : NODIRECTION; if (d != NODIRECTION) { build_road(r, u, m, d); @@ -1755,6 +1758,7 @@ attrib_type at_trades = { static void buy(unit * u, request ** buyorders, struct order *ord) { + char token[128]; region *r = u->region; int n, k; request *o; @@ -1838,7 +1842,7 @@ static void buy(unit * u, request ** buyorders, struct order *ord) /* die Menge der verkauften Güter merken */ a->data.i += n; - s = getstrtoken(); + s = gettoken(token, sizeof(token)); itype = s ? finditemtype(s, u->faction->locale) : 0; if (itype != NULL) { ltype = resource2luxury(itype->rtype); @@ -2061,6 +2065,7 @@ static void expandselling(region * r, request * sellorders, int limit) static bool sell(unit * u, request ** sellorders, struct order *ord) { + char token[128]; bool unlimited = true; const item_type *itype; const luxury_type *ltype; @@ -2078,7 +2083,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) kwd = init_order(ord); assert(kwd == K_SELL); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if (findparam(s, u->faction->locale) == P_ANY) { unlimited = false; @@ -2136,7 +2141,7 @@ static bool sell(unit * u, request ** sellorders, struct order *ord) cmistake(u, ord, 54, MSG_COMMERCE); return false; } - s = getstrtoken(); + s = gettoken(token, sizeof(token)); itype = s ? finditemtype(s, u->faction->locale) : 0; ltype = itype ? resource2luxury(itype->rtype) : 0; if (ltype == NULL) { @@ -2464,6 +2469,7 @@ static void breedhorses(region * r, unit * u) static void breed_cmd(unit * u, struct order *ord) { + char token[128]; int m; const char *s; param_t p; @@ -2477,12 +2483,12 @@ static void breed_cmd(unit * u, struct order *ord) /* züchte [] */ (void)init_order(ord); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); m = s ? atoi((const char *)s) : 0; if (m != 0) { /* first came a want-paramter */ - s = getstrtoken(); + s = gettoken(token, sizeof(token)); } else { m = INT_MAX; @@ -2545,10 +2551,6 @@ static void research_cmd(unit * u, struct order *ord) kwd = init_order(ord); assert(kwd == K_RESEARCH); - /* - const char *s = getstrtoken(); - - if (findparam(s, u->faction->locale) == P_HERBS) { */ if (eff_skill(u, SK_HERBALISM, r) < 7) { cmistake(u, ord, 227, MSG_EVENT); diff --git a/src/give.c b/src/give.c index 71928f630..913226bb4 100644 --- a/src/give.c +++ b/src/give.c @@ -531,6 +531,7 @@ bool can_give_to(unit *u, unit *u2) { void give_cmd(unit * u, order * ord) { + char token[128]; region *r = u->region; unit *u2; const char *s; @@ -544,7 +545,7 @@ void give_cmd(unit * u, order * ord) kwd = init_order(ord); assert(kwd == K_GIVE); err = getunit(r, u->faction, &u2); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); n = s ? atoip(s) : 0; p = (n > 0) ? NOPARAM : findparam(s, u->faction->locale); @@ -652,7 +653,7 @@ void give_cmd(unit * u, order * ord) feedback_give_not_allowed(u, ord); return; } - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if (!s || *s == 0) { /* GIVE ALL items that you have */ /* do these checks once, not for each item we have: */ @@ -732,11 +733,11 @@ void give_cmd(unit * u, order * ord) msg_feedback(u, ord, "peasants_give_invalid", "")); return; } - s = getstrtoken(); /* skip one ahead to get the amount. */ - n = atoip(s); /* n: Anzahl */ + s = gettoken(token, sizeof(token)); /* skip one ahead to get the amount. */ + n = s ? atoip(s) : 0; /* n: Anzahl */ n *= u2->number; } - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if (s == NULL) { cmistake(u, ord, 113, MSG_COMMERCE); diff --git a/src/items.c b/src/items.c index 49d7a2652..012dc9f7c 100644 --- a/src/items.c +++ b/src/items.c @@ -35,9 +35,10 @@ use_studypotion(struct unit *u, const struct item_type *itype, int amount, struct order *ord) { if (init_order(u->thisorder) == K_STUDY) { + char token[128]; skill_t sk = NOSKILL; skill *sv = 0; - const char * s = getstrtoken(); + const char * s = gettoken(token, sizeof(token)); if (s) { sk = get_skill(s, u->faction->locale); diff --git a/src/kernel/build.c b/src/kernel/build.c index 6c0b8c76e..a3abdf43e 100644 --- a/src/kernel/build.c +++ b/src/kernel/build.c @@ -1,7 +1,7 @@ /* Copyright (c) 1998-2010, Enno Rehling - Katja Zedel +Katja Zedel Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -69,20 +69,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. struct building *getbuilding(const struct region *r) { - building *b = findbuilding(getid()); - if (b == NULL || r != b->region) - return NULL; - return b; + building *b = findbuilding(getid()); + if (b == NULL || r != b->region) + return NULL; + return b; } ship *getship(const struct region * r) { - ship *sh, *sx = findship(getshipid()); - for (sh = r->ships; sh; sh = sh->next) { - if (sh == sx) - return sh; - } - return NULL; + ship *sh, *sx = findship(getshipid()); + for (sh = r->ships; sh; sh = sh->next) { + if (sh == sx) + return sh; + } + return NULL; } /* ------------------------------------------------------------- */ @@ -91,19 +91,22 @@ ship *getship(const struct region * r) static void destroy_road(unit * u, int nmax, struct order *ord) { - const char *s = getstrtoken(); + char token[128]; + const char *s = gettoken(token, sizeof(token)); direction_t d = s ? get_direction(s, u->faction->locale) : NODIRECTION; if (d == NODIRECTION) { /* Die Richtung wurde nicht erkannt */ cmistake(u, ord, 71, MSG_PRODUCE); - } else { + } + else { unit *u2; region *r = u->region; short road, n = (short)nmax; - + if (nmax > SHRT_MAX) { n = SHRT_MAX; - } else if (nmax < 0) { + } + else if (nmax < 0) { n = 0; } @@ -126,244 +129,253 @@ static void destroy_road(unit * u, int nmax, struct order *ord) /* TODO: error message */ } if (willdo > SHRT_MAX) - road = 0; + road = 0; else - road = road - (short)willdo; + road = road - (short)willdo; rsetroad(r, d, road); ADDMSG(&u->faction->msgs, msg_message("destroy_road", - "unit from to", u, r, r2)); + "unit from to", u, r, r2)); } } } int destroy_cmd(unit * u, struct order *ord) { - ship *sh; - unit *u2; - region *r = u->region; - const construction *con = NULL; - int size = 0; - const char *s; - int n = INT_MAX; + char token[128]; + ship *sh; + unit *u2; + region *r = u->region; + const construction *con = NULL; + int size = 0; + const char *s; + int n = INT_MAX; - if (u->number < 1) - return 0; + if (u->number < 1) + return 0; - init_order(ord); - s = getstrtoken(); + init_order(ord); + s = gettoken(token, sizeof(token)); - if (findparam(s, u->faction->locale) == P_ROAD) { - destroy_road(u, INT_MAX, ord); - return 0; - } - - if (s && *s) { - n = atoi((const char *)s); - if (n <= 0) { - cmistake(u, ord, 288, MSG_PRODUCE); - return 0; + if (findparam(s, u->faction->locale) == P_ROAD) { + destroy_road(u, INT_MAX, ord); + return 0; } - } - if (getparam(u->faction->locale) == P_ROAD) { - destroy_road(u, n, ord); - return 0; - } - - if (u->building) { - building *b = u->building; - - if (u!=building_owner(b)) { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } - if (fval(b->type, BTF_INDESTRUCTIBLE)) { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } - if (n >= b->size) { - /* destroy completly */ - /* all units leave the building */ - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->building == b) { - leave_building(u2); + if (s && *s) { + n = atoi((const char *)s); + if (n <= 0) { + cmistake(u, ord, 288, MSG_PRODUCE); + return 0; } - } - ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u)); - con = b->type->construction; - remove_building(&r->buildings, b); - } else { - /* partial destroy */ - b->size -= n; - ADDMSG(&u->faction->msgs, msg_message("destroy_partial", - "building unit", b, u)); - } - } else if (u->ship) { - sh = u->ship; - - if (u!=ship_owner(sh)) { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } - if (fval(r->terrain, SEA_REGION)) { - cmistake(u, ord, 14, MSG_EVENT); - return 0; } - if (n >= (sh->size * 100) / sh->type->construction->maxsize) { - /* destroy completly */ - /* all units leave the ship */ - for (u2 = r->units; u2; u2 = u2->next) { - if (u2->ship == sh) { - leave_ship(u2); + if (getparam(u->faction->locale) == P_ROAD) { + destroy_road(u, n, ord); + return 0; + } + + if (u->building) { + building *b = u->building; + + if (u != building_owner(b)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + if (fval(b->type, BTF_INDESTRUCTIBLE)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + if (n >= b->size) { + /* destroy completly */ + /* all units leave the building */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->building == b) { + leave_building(u2); + } + } + ADDMSG(&u->faction->msgs, msg_message("destroy", "building unit", b, u)); + con = b->type->construction; + remove_building(&r->buildings, b); + } + else { + /* partial destroy */ + b->size -= n; + ADDMSG(&u->faction->msgs, msg_message("destroy_partial", + "building unit", b, u)); } - } - ADDMSG(&u->faction->msgs, msg_message("shipdestroy", - "unit region ship", u, r, sh)); - con = sh->type->construction; - remove_ship(&sh->region->ships, sh); - } else { - /* partial destroy */ - sh->size -= (sh->type->construction->maxsize * n) / 100; - ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", - "unit region ship", u, r, sh)); } - } else { - cmistake(u, ord, 138, MSG_PRODUCE); - return 0; - } + else if (u->ship) { + sh = u->ship; - if (con) { - /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ - int c; - for (c = 0; con->materials[c].number; ++c) { - const requirement *rq = con->materials + c; - int recycle = (rq->number * size / con->reqsize)/2; - if (recycle) { - change_resource(u, rq->rtype, recycle); - } + if (u != ship_owner(sh)) { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + if (fval(r->terrain, SEA_REGION)) { + cmistake(u, ord, 14, MSG_EVENT); + return 0; + } + + if (n >= (sh->size * 100) / sh->type->construction->maxsize) { + /* destroy completly */ + /* all units leave the ship */ + for (u2 = r->units; u2; u2 = u2->next) { + if (u2->ship == sh) { + leave_ship(u2); + } + } + ADDMSG(&u->faction->msgs, msg_message("shipdestroy", + "unit region ship", u, r, sh)); + con = sh->type->construction; + remove_ship(&sh->region->ships, sh); + } + else { + /* partial destroy */ + sh->size -= (sh->type->construction->maxsize * n) / 100; + ADDMSG(&u->faction->msgs, msg_message("shipdestroy_partial", + "unit region ship", u, r, sh)); + } } - } - return 0; + else { + cmistake(u, ord, 138, MSG_PRODUCE); + return 0; + } + + if (con) { + /* TODO: Nicht an ZERSTÖRE mit Punktangabe angepaßt! */ + int c; + for (c = 0; con->materials[c].number; ++c) { + const requirement *rq = con->materials + c; + int recycle = (rq->number * size / con->reqsize) / 2; + if (recycle) { + change_resource(u, rq->rtype, recycle); + } + } + } + return 0; } /* ------------------------------------------------------------- */ void build_road(region * r, unit * u, int size, direction_t d) { - int n, left; - region *rn = rconnect(r, d); + int n, left; + region *rn = rconnect(r, d); - assert(u->number); - if (!eff_skill(u, SK_ROAD_BUILDING, r)) { - cmistake(u, u->thisorder, 103, MSG_PRODUCE); - return; - } - if (besieged(u)) { - cmistake(u, u->thisorder, 60, MSG_PRODUCE); - return; - } - - if (rn == NULL || rn->terrain->max_road < 0) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); - return; - } - - if (r->terrain->max_road < 0) { - cmistake(u, u->thisorder, 94, MSG_PRODUCE); - return; - } - - if (r->terrain == newterrain(T_SWAMP)) { - /* wenn kein Damm existiert */ - const struct building_type *bt_dam = bt_find("dam"); - if (!bt_dam || !buildingtype_exists(r, bt_dam, true)) { - cmistake(u, u->thisorder, 132, MSG_PRODUCE); - return; + assert(u->number); + if (!eff_skill(u, SK_ROAD_BUILDING, r)) { + cmistake(u, u->thisorder, 103, MSG_PRODUCE); + return; } - } else if (r->terrain == newterrain(T_DESERT)) { - const struct building_type *bt_caravan = bt_find("caravan"); - /* wenn keine Karawanserei existiert */ - if (!bt_caravan || !buildingtype_exists(r, bt_caravan, true)) { - cmistake(u, u->thisorder, 133, MSG_PRODUCE); - return; + if (besieged(u)) { + cmistake(u, u->thisorder, 60, MSG_PRODUCE); + return; } - } else if (r->terrain == newterrain(T_GLACIER)) { - const struct building_type *bt_tunnel = bt_find("tunnel"); - /* wenn kein Tunnel existiert */ - if (!bt_tunnel || !buildingtype_exists(r, bt_tunnel, true)) { - cmistake(u, u->thisorder, 131, MSG_PRODUCE); - return; - } - } - /* left kann man noch bauen */ - left = r->terrain->max_road - rroad(r, d); - - /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ - if (left <= 0) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, - "error_roads_finished", "")); - return; - } - - if (size > 0) - left = _min(size, left); - /* baumaximum anhand der rohstoffe */ - if (u_race(u) == get_race(RC_STONEGOLEM)) { - n = u->number * GOLEM_STONE; - } else { - n = get_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, left); - if (n == 0) { - cmistake(u, u->thisorder, 151, MSG_PRODUCE); - return; + if (rn == NULL || rn->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; } - } - left = _min(n, left); - /* n = maximum by skill. try to maximize it */ - n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); - if (n < left) { - const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); - item *itm = ring ? *i_find(&u->items, ring->itype) : 0; - if (itm != NULL && itm->number > 0) { - int rings = _min(u->number, itm->number); - n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; + if (r->terrain->max_road < 0) { + cmistake(u, u->thisorder, 94, MSG_PRODUCE); + return; } - } - if (n < left) { - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - if (dm != 0) { - int sk = eff_skill(u, SK_ROAD_BUILDING, r); - int todo = (left - n + sk - 1) / sk; - todo = _min(todo, u->number); - dm = _min(dm, todo); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - n += dm * sk; - } /* Auswirkung Schaffenstrunk */ - } - /* make minimum of possible and available: */ - n = _min(left, n); - - /* n is now modified by several special effects, so we have to - * minimize it again to make sure the road will not grow beyond - * maximum. */ - rsetroad(r, d, rroad(r, d) + (short)n); - - if (u_race(u) == get_race(RC_STONEGOLEM)) { - int golemsused = n / GOLEM_STONE; - if (n % GOLEM_STONE != 0) { - ++golemsused; + if (r->terrain == newterrain(T_SWAMP)) { + /* wenn kein Damm existiert */ + const struct building_type *bt_dam = bt_find("dam"); + if (!bt_dam || !buildingtype_exists(r, bt_dam, true)) { + cmistake(u, u->thisorder, 132, MSG_PRODUCE); + return; + } } - scale_number(u, u->number - golemsused); - } else { - use_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, n); - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, SK_ROAD_BUILDING, _min(n, u->number)); - } - ADDMSG(&u->faction->msgs, msg_message("buildroad", - "region unit size", r, u, n)); + else if (r->terrain == newterrain(T_DESERT)) { + const struct building_type *bt_caravan = bt_find("caravan"); + /* wenn keine Karawanserei existiert */ + if (!bt_caravan || !buildingtype_exists(r, bt_caravan, true)) { + cmistake(u, u->thisorder, 133, MSG_PRODUCE); + return; + } + } + else if (r->terrain == newterrain(T_GLACIER)) { + const struct building_type *bt_tunnel = bt_find("tunnel"); + /* wenn kein Tunnel existiert */ + if (!bt_tunnel || !buildingtype_exists(r, bt_tunnel, true)) { + cmistake(u, u->thisorder, 131, MSG_PRODUCE); + return; + } + } + + /* left kann man noch bauen */ + left = r->terrain->max_road - rroad(r, d); + + /* hoffentlich ist r->road <= r->terrain->max_road, n also >= 0 */ + if (left <= 0) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_roads_finished", "")); + return; + } + + if (size > 0) + left = _min(size, left); + /* baumaximum anhand der rohstoffe */ + if (u_race(u) == get_race(RC_STONEGOLEM)) { + n = u->number * GOLEM_STONE; + } + else { + n = get_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, left); + if (n == 0) { + cmistake(u, u->thisorder, 151, MSG_PRODUCE); + return; + } + } + left = _min(n, left); + + /* n = maximum by skill. try to maximize it */ + n = u->number * eff_skill(u, SK_ROAD_BUILDING, r); + if (n < left) { + const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); + item *itm = ring ? *i_find(&u->items, ring->itype) : 0; + if (itm != NULL && itm->number > 0) { + int rings = _min(u->number, itm->number); + n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; + } + } + if (n < left) { + int dm = get_effect(u, oldpotiontype[P_DOMORE]); + if (dm != 0) { + int sk = eff_skill(u, SK_ROAD_BUILDING, r); + int todo = (left - n + sk - 1) / sk; + todo = _min(todo, u->number); + dm = _min(dm, todo); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + n += dm * sk; + } /* Auswirkung Schaffenstrunk */ + } + + /* make minimum of possible and available: */ + n = _min(left, n); + + /* n is now modified by several special effects, so we have to + * minimize it again to make sure the road will not grow beyond + * maximum. */ + rsetroad(r, d, rroad(r, d) + (short)n); + + if (u_race(u) == get_race(RC_STONEGOLEM)) { + int golemsused = n / GOLEM_STONE; + if (n % GOLEM_STONE != 0) { + ++golemsused; + } + scale_number(u, u->number - golemsused); + } + else { + use_pooled(u, get_resourcetype(R_STONE), GET_DEFAULT, n); + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, SK_ROAD_BUILDING, _min(n, u->number)); + } + ADDMSG(&u->faction->msgs, msg_message("buildroad", + "region unit size", r, u, n)); } /* ------------------------------------------------------------- */ @@ -373,38 +385,38 @@ void build_road(region * r, unit * u, int size, direction_t d) * ** ** ** ** ** ** */ static int required(int size, int msize, int maxneed) - /* um size von msize Punkten zu bauen, - * braucht man required von maxneed resourcen */ +/* um size von msize Punkten zu bauen, + * braucht man required von maxneed resourcen */ { - int used; + int used; - used = size * maxneed / msize; - if (size * maxneed % msize) - ++used; - return used; + used = size * maxneed / msize; + if (size * maxneed % msize) + ++used; + return used; } static int matmod(const attrib * a, const unit * u, const resource_type * material, - int value) +int value) { - for (a = a_find((attrib *) a, &at_matmod); a && a->type == &at_matmod; - a = a->next) { - mm_fun fun = (mm_fun) a->data.f; - value = fun(u, material, value); - if (value < 0) - return value; /* pass errors to caller */ - } - return value; + for (a = a_find((attrib *)a, &at_matmod); a && a->type == &at_matmod; + a = a->next) { + mm_fun fun = (mm_fun)a->data.f; + value = fun(u, material, value); + if (value < 0) + return value; /* pass errors to caller */ + } + return value; } int roqf_factor(void) { - int value = -1; - if (value < 0) { - value = get_param_int(global.parameters, "rules.economy.roqf", 10); - } - return value; + int value = -1; + if (value < 0) { + value = get_param_int(global.parameters, "rules.economy.roqf", 10); + } + return value; } /** Use up resources for building an object. @@ -414,230 +426,234 @@ int roqf_factor(void) */ int build(unit * u, const construction * ctype, int completed, int want) { - const construction *type = ctype; - int skills = INT_MAX; /* number of skill points remainig */ - int basesk = 0; - int made = 0; + const construction *type = ctype; + int skills = INT_MAX; /* number of skill points remainig */ + int basesk = 0; + int made = 0; - if (want <= 0) - return 0; - if (type == NULL) - return ENOMATERIALS; - if (type->improvement == NULL && completed == type->maxsize) - return ECOMPLETE; - if (type->btype != NULL) { - building *b; - if (!u->building || u->building->type != type->btype) { - return EBUILDINGREQ; - } - b = inside_building(u); - if (b == NULL) - return EBUILDINGREQ; - } - - if (type->skill != NOSKILL) { - int effsk; - int dm = get_effect(u, oldpotiontype[P_DOMORE]); - - assert(u->number); - basesk = effskill(u, type->skill); - if (basesk == 0) - return ENEEDSKILL; - - effsk = basesk; - if (inside_building(u)) { - effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - } - effsk = skillmod(type->attribs, u, u->region, type->skill, - effsk, SMF_PRODUCTION); - if (effsk < 0) - return effsk; /* pass errors to caller */ - if (effsk == 0) - return ENEEDSKILL; - - skills = effsk * u->number; - - /* technically, nimblefinge and domore should be in a global set of - * "game"-attributes, (as at_skillmod) but for a while, we're leaving - * them in here. */ - - if (dm != 0) { - /* Auswirkung Schaffenstrunk */ - dm = _min(dm, u->number); - change_effect(u, oldpotiontype[P_DOMORE], -dm); - skills += dm * effsk; - } - } - for (; want > 0 && skills > 0;) { - int c, n; - - /* skip over everything that's already been done: - * type->improvement==NULL means no more improvements, but no size limits - * type->improvement==type means build another object of the same time - * while material lasts type->improvement==x means build x when type - * is finished */ - while (type->improvement != NULL && - type->improvement != type && - type->maxsize > 0 && type->maxsize <= completed) { - completed -= type->maxsize; - type = type->improvement; - } - if (type == NULL) { - if (made == 0) - return ECOMPLETE; - break; /* completed */ - } - - /* Hier ist entweder maxsize == -1, oder completed < maxsize. - * Andernfalls ist das Datenfile oder sonstwas kaputt... - * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe - * die gleiche wie die vorherige ist. z.b. gegenstände. - */ - if (type->maxsize > 1) { - completed = completed % type->maxsize; - } else { - completed = 0; - assert(type->reqsize >= 1); - } - - if (basesk < type->minskill) { - if (made == 0) - return ELOWSKILL; /* not good enough to go on */ - } - - /* n = maximum buildable size */ - if (type->minskill > 1) { - n = skills / type->minskill; - } else { - n = skills; - } - /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) - * Talente */ - if (skill_limit(u->faction, type->skill) == INT_MAX) { - const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); - item *itm = ring ? *i_find(&u->items, ring->itype) : 0; - int i = itm ? itm->number : 0; - if (i > 0) { - int rings = _min(u->number, i); - n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; - } - } - - if (want < n) n = want; - - if (type->maxsize > 0) { - n = _min(type->maxsize - completed, n); - if (type->improvement == NULL) { - want = n; - } - } - - if (type->materials) - for (c = 0; n > 0 && type->materials[c].number; c++) { - const struct resource_type *rtype = type->materials[c].rtype; - int need, prebuilt; - int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - - if (inside_building(u)) { - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - } - - if (canuse < 0) - return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - if (type->reqsize > 1) { - prebuilt = - required(completed, type->reqsize, type->materials[c].number); - for (; n;) { - need = - required(completed + n, type->reqsize, type->materials[c].number); - if (need - prebuilt <= canuse) - break; - --n; /* TODO: optimieren? */ - } - } else { - int maxn = canuse / type->materials[c].number; - if (maxn < n) - n = maxn; - } - } - if (n <= 0) { - if (made == 0) + if (want <= 0) + return 0; + if (type == NULL) return ENOMATERIALS; - else - break; + if (type->improvement == NULL && completed == type->maxsize) + return ECOMPLETE; + if (type->btype != NULL) { + building *b; + if (!u->building || u->building->type != type->btype) { + return EBUILDINGREQ; + } + b = inside_building(u); + if (b == NULL) + return EBUILDINGREQ; } - if (type->materials) - for (c = 0; type->materials[c].number; c++) { - const struct resource_type *rtype = type->materials[c].rtype; - int prebuilt = - required(completed, type->reqsize, type->materials[c].number); - int need = - required(completed + n, type->reqsize, type->materials[c].number); - int multi = 1; - int canuse = 100; /* normalization */ - if (inside_building(u)) - canuse = matmod(u->building->type->attribs, u, rtype, canuse); - if (canuse < 0) - return canuse; /* pass errors to caller */ - canuse = matmod(type->attribs, u, rtype, canuse); - assert(canuse % 100 == 0 - || !"only constant multipliers are implemented in build()"); - multi = canuse / 100; - if (canuse < 0) - return canuse; /* pass errors to caller */ + if (type->skill != NOSKILL) { + int effsk; + int dm = get_effect(u, oldpotiontype[P_DOMORE]); - use_pooled(u, rtype, GET_DEFAULT, - (need - prebuilt + multi - 1) / multi); - } - made += n; - skills -= n * type->minskill; - want -= n; - completed = completed + n; - } - /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ - produceexp(u, ctype->skill, _min(made, u->number)); + assert(u->number); + basesk = effskill(u, type->skill); + if (basesk == 0) + return ENEEDSKILL; - return made; + effsk = basesk; + if (inside_building(u)) { + effsk = skillmod(u->building->type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + } + effsk = skillmod(type->attribs, u, u->region, type->skill, + effsk, SMF_PRODUCTION); + if (effsk < 0) + return effsk; /* pass errors to caller */ + if (effsk == 0) + return ENEEDSKILL; + + skills = effsk * u->number; + + /* technically, nimblefinge and domore should be in a global set of + * "game"-attributes, (as at_skillmod) but for a while, we're leaving + * them in here. */ + + if (dm != 0) { + /* Auswirkung Schaffenstrunk */ + dm = _min(dm, u->number); + change_effect(u, oldpotiontype[P_DOMORE], -dm); + skills += dm * effsk; + } + } + for (; want > 0 && skills > 0;) { + int c, n; + + /* skip over everything that's already been done: + * type->improvement==NULL means no more improvements, but no size limits + * type->improvement==type means build another object of the same time + * while material lasts type->improvement==x means build x when type + * is finished */ + while (type->improvement != NULL && + type->improvement != type && + type->maxsize > 0 && type->maxsize <= completed) { + completed -= type->maxsize; + type = type->improvement; + } + if (type == NULL) { + if (made == 0) + return ECOMPLETE; + break; /* completed */ + } + + /* Hier ist entweder maxsize == -1, oder completed < maxsize. + * Andernfalls ist das Datenfile oder sonstwas kaputt... + * (enno): Nein, das ist für Dinge, bei denen die nächste Ausbaustufe + * die gleiche wie die vorherige ist. z.b. gegenstände. + */ + if (type->maxsize > 1) { + completed = completed % type->maxsize; + } + else { + completed = 0; + assert(type->reqsize >= 1); + } + + if (basesk < type->minskill) { + if (made == 0) + return ELOWSKILL; /* not good enough to go on */ + } + + /* n = maximum buildable size */ + if (type->minskill > 1) { + n = skills / type->minskill; + } + else { + n = skills; + } + /* Flinkfingerring wirkt nicht auf Mengenbegrenzte (magische) + * Talente */ + if (skill_limit(u->faction, type->skill) == INT_MAX) { + const resource_type *ring = get_resourcetype(R_RING_OF_NIMBLEFINGER); + item *itm = ring ? *i_find(&u->items, ring->itype) : 0; + int i = itm ? itm->number : 0; + if (i > 0) { + int rings = _min(u->number, i); + n = n * ((roqf_factor() - 1) * rings + u->number) / u->number; + } + } + + if (want < n) n = want; + + if (type->maxsize > 0) { + n = _min(type->maxsize - completed, n); + if (type->improvement == NULL) { + want = n; + } + } + + if (type->materials) + for (c = 0; n > 0 && type->materials[c].number; c++) { + const struct resource_type *rtype = type->materials[c].rtype; + int need, prebuilt; + int canuse = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + + if (inside_building(u)) { + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + } + + if (canuse < 0) + return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + if (type->reqsize > 1) { + prebuilt = + required(completed, type->reqsize, type->materials[c].number); + for (; n;) { + need = + required(completed + n, type->reqsize, type->materials[c].number); + if (need - prebuilt <= canuse) + break; + --n; /* TODO: optimieren? */ + } + } + else { + int maxn = canuse / type->materials[c].number; + if (maxn < n) + n = maxn; + } + } + if (n <= 0) { + if (made == 0) + return ENOMATERIALS; + else + break; + } + if (type->materials) + for (c = 0; type->materials[c].number; c++) { + const struct resource_type *rtype = type->materials[c].rtype; + int prebuilt = + required(completed, type->reqsize, type->materials[c].number); + int need = + required(completed + n, type->reqsize, type->materials[c].number); + int multi = 1; + int canuse = 100; /* normalization */ + if (inside_building(u)) + canuse = matmod(u->building->type->attribs, u, rtype, canuse); + if (canuse < 0) + return canuse; /* pass errors to caller */ + canuse = matmod(type->attribs, u, rtype, canuse); + + assert(canuse % 100 == 0 + || !"only constant multipliers are implemented in build()"); + multi = canuse / 100; + if (canuse < 0) + return canuse; /* pass errors to caller */ + + use_pooled(u, rtype, GET_DEFAULT, + (need - prebuilt + multi - 1) / multi); + } + made += n; + skills -= n * type->minskill; + want -= n; + completed = completed + n; + } + /* Nur soviel PRODUCEEXP wie auch tatsaechlich gemacht wurde */ + produceexp(u, ctype->skill, _min(made, u->number)); + + return made; } message *msg_materials_required(unit * u, order * ord, - const construction * ctype, int multi) + const construction * ctype, int multi) { - int c; - /* something missing from the list of materials */ - resource *reslist = NULL; + int c; + /* something missing from the list of materials */ + resource *reslist = NULL; - if (multi <= 0 || multi == INT_MAX) - multi = 1; - for (c = 0; ctype && ctype->materials[c].number; ++c) { - resource *res = malloc(sizeof(resource)); - res->number = multi * ctype->materials[c].number / ctype->reqsize; - res->type = ctype->materials[c].rtype; - res->next = reslist; - reslist = res; - } - return msg_feedback(u, ord, "build_required", "required", reslist); + if (multi <= 0 || multi == INT_MAX) + multi = 1; + for (c = 0; ctype && ctype->materials[c].number; ++c) { + resource *res = malloc(sizeof(resource)); + res->number = multi * ctype->materials[c].number / ctype->reqsize; + res->type = ctype->materials[c].rtype; + res->next = reslist; + reslist = res; + } + return msg_feedback(u, ord, "build_required", "required", reslist); } int maxbuild(const unit * u, const construction * cons) - /* calculate maximum size that can be built from available material */ - /* !! ignores maximum objectsize and improvements... */ +/* calculate maximum size that can be built from available material */ +/* !! ignores maximum objectsize and improvements... */ { - int c; - int maximum = INT_MAX; - for (c = 0; cons->materials[c].number; c++) { - const resource_type *rtype = cons->materials[c].rtype; - int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); - int need = required(1, cons->reqsize, cons->materials[c].number); - if (have < need) { - return 0; - } else - maximum = _min(maximum, have / need); - } - return maximum; + int c; + int maximum = INT_MAX; + for (c = 0; cons->materials[c].number; c++) { + const resource_type *rtype = cons->materials[c].rtype; + int have = get_pooled(u, rtype, GET_DEFAULT, INT_MAX); + int need = required(1, cons->reqsize, cons->materials[c].number); + if (have < need) { + return 0; + } + else + maximum = _min(maximum, have / need); + } + return maximum; } /** old build routines */ @@ -645,302 +661,312 @@ int maxbuild(const unit * u, const construction * cons) int build_building(unit * u, const building_type * btype, int id, int want, order * ord) { - region *r = u->region; - int n = want, built = 0; - building *b = NULL; - /* einmalige Korrektur */ - const char *btname; - order *new_order = NULL; - const struct locale *lang = u->faction->locale; - static int rule_other = -1; + region *r = u->region; + int n = want, built = 0; + building *b = NULL; + /* einmalige Korrektur */ + const char *btname; + order *new_order = NULL; + const struct locale *lang = u->faction->locale; + static int rule_other = -1; - assert(u->number); - assert(btype->construction); - if (eff_skill(u, SK_BUILDING, r) == 0) { - cmistake(u, ord, 101, MSG_PRODUCE); - return 0; - } + assert(u->number); + assert(btype->construction); + if (eff_skill(u, SK_BUILDING, r) == 0) { + cmistake(u, ord, 101, MSG_PRODUCE); + return 0; + } - /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der - * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg - * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten - * baut man an der eigenen burg weiter. */ + /* Falls eine Nummer angegeben worden ist, und ein Gebaeude mit der + * betreffenden Nummer existiert, ist b nun gueltig. Wenn keine Burg + * gefunden wurde, dann wird nicht einfach eine neue erbaut. Ansonsten + * baut man an der eigenen burg weiter. */ - /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ - if (id > 0) { /* eine Nummer angegeben, keine neue Burg bauen */ - b = findbuilding(id); - if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ - /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ - if (u->building && u->building->type == btype) { + /* Wenn die angegebene Nummer falsch ist, KEINE Burg bauen! */ + if (id > 0) { /* eine Nummer angegeben, keine neue Burg bauen */ + b = findbuilding(id); + if (!b || b->region != u->region) { /* eine Burg mit dieser Nummer gibt es hier nicht */ + /* vieleicht Tippfehler und die eigene Burg ist gemeint? */ + if (u->building && u->building->type == btype) { + b = u->building; + } + else { + /* keine neue Burg anfangen wenn eine Nummer angegeben war */ + cmistake(u, ord, 6, MSG_PRODUCE); + return 0; + } + } + } + else if (u->building && u->building->type == btype) { b = u->building; - } else { - /* keine neue Burg anfangen wenn eine Nummer angegeben war */ - cmistake(u, ord, 6, MSG_PRODUCE); + } + + if (b) + btype = b->type; + + if (fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { + /* only one of these per region */ + cmistake(u, ord, 93, MSG_PRODUCE); return 0; - } } - } else if (u->building && u->building->type == btype) { - b = u->building; - } - - if (b) - btype = b->type; - - if (fval(btype, BTF_UNIQUE) && buildingtype_exists(r, btype, false)) { - /* only one of these per region */ - cmistake(u, ord, 93, MSG_PRODUCE); - return 0; - } - if (besieged(u)) { - /* units under siege can not build */ - cmistake(u, ord, 60, MSG_PRODUCE); - return 0; - } - if (btype->flags & BTF_NOBUILD) { - /* special building, cannot be built */ - cmistake(u, ord, 221, MSG_PRODUCE); - return 0; - } - if ((r->terrain->flags & LAND_REGION) == 0) { - /* special terrain, cannot build */ - cmistake(u, ord, 221, MSG_PRODUCE); - return 0; - } - if (btype->flags & BTF_ONEPERTURN) { - if (b && fval(b, BLD_EXPANDED)) { - cmistake(u, ord, 318, MSG_PRODUCE); - return 0; - } - n = 1; - } - if (b) { - if (rule_other < 0) { - rule_other = - get_param_int(global.parameters, "rules.build.other_buildings", 1); - } - if (!rule_other) { - unit *owner = building_owner(b); - if (!owner || owner->faction != u->faction) { - cmistake(u, ord, 1222, MSG_PRODUCE); + if (besieged(u)) { + /* units under siege can not build */ + cmistake(u, ord, 60, MSG_PRODUCE); return 0; - } } - } + if (btype->flags & BTF_NOBUILD) { + /* special building, cannot be built */ + cmistake(u, ord, 221, MSG_PRODUCE); + return 0; + } + if ((r->terrain->flags & LAND_REGION) == 0) { + /* special terrain, cannot build */ + cmistake(u, ord, 221, MSG_PRODUCE); + return 0; + } + if (btype->flags & BTF_ONEPERTURN) { + if (b && fval(b, BLD_EXPANDED)) { + cmistake(u, ord, 318, MSG_PRODUCE); + return 0; + } + n = 1; + } + if (b) { + if (rule_other < 0) { + rule_other = + get_param_int(global.parameters, "rules.build.other_buildings", 1); + } + if (!rule_other) { + unit *owner = building_owner(b); + if (!owner || owner->faction != u->faction) { + cmistake(u, ord, 1222, MSG_PRODUCE); + return 0; + } + } + } - if (b) - built = b->size; - if (n <= 0 || n == INT_MAX) { + if (b) + built = b->size; + if (n <= 0 || n == INT_MAX) { + if (b == NULL) { + if (btype->maxsize > 0) { + n = btype->maxsize - built; + } + else { + n = INT_MAX; + } + } + else { + if (b->type->maxsize > 0) { + n = b->type->maxsize - built; + } + else { + n = INT_MAX; + } + } + } + built = build(u, btype->construction, built, n); + + switch (built) { + case ECOMPLETE: + /* the building is already complete */ + cmistake(u, ord, 4, MSG_PRODUCE); + break; + case ENOMATERIALS: + ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, + btype->construction, want)); + break; + case ELOWSKILL: + case ENEEDSKILL: + /* no skill, or not enough skill points to build */ + cmistake(u, ord, 50, MSG_PRODUCE); + break; + } + if (built <= 0) { + return built; + } + /* at this point, the building size is increased. */ if (b == NULL) { - if (btype->maxsize > 0) { - n = btype->maxsize - built; - } else { - n = INT_MAX; - } - } else { - if (b->type->maxsize > 0) { - n = b->type->maxsize - built; - } else { - n = INT_MAX; - } - } - } - built = build(u, btype->construction, built, n); + /* build a new building */ + b = new_building(btype, r, lang); + b->type = btype; + fset(b, BLD_MAINTAINED | BLD_WORKING); - switch (built) { - case ECOMPLETE: - /* the building is already complete */ - cmistake(u, ord, 4, MSG_PRODUCE); - break; - case ENOMATERIALS: - ADDMSG(&u->faction->msgs, msg_materials_required(u, ord, - btype->construction, want)); - break; - case ELOWSKILL: - case ENEEDSKILL: - /* no skill, or not enough skill points to build */ - cmistake(u, ord, 50, MSG_PRODUCE); - break; - } - if (built<=0) { + /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ + if (u->number && leave(u, false)) { + u_set_building(u, b); + } + } + + btname = LOC(lang, btype->_name); + + if (want - built <= 0) { + /* gebäude fertig */ + new_order = default_order(lang); + } + else if (want != INT_MAX) { + /* reduzierte restgröße */ + const char *hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = + create_order(K_MAKE, lang, "%d \"%s\" %i", n - built, btname, b->no); + } + else { + new_order = + create_order(K_MAKE, lang, "%d %s %i", n - built, btname, b->no); + } + } + else if (btname) { + /* Neues Haus, Befehl mit Gebäudename */ + const char *hasspace = strchr(btname, ' '); + if (hasspace) { + new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); + } + else { + new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); + } + } + + if (new_order) { + replace_order(&u->orders, ord, new_order); + free_order(new_order); + } + + b->size += built; + fset(b, BLD_EXPANDED); + + update_lighthouse(b); + + ADDMSG(&u->faction->msgs, msg_message("buildbuilding", + "building unit size", b, u, built)); return built; - } - /* at this point, the building size is increased. */ - if (b == NULL) { - /* build a new building */ - b = new_building(btype, r, lang); - b->type = btype; - fset(b, BLD_MAINTAINED|BLD_WORKING); - - /* Die Einheit befindet sich automatisch im Inneren der neuen Burg. */ - if (u->number && leave(u, false)) { - u_set_building(u, b); - } - } - - btname = LOC(lang, btype->_name); - - if (want - built <= 0) { - /* gebäude fertig */ - new_order = default_order(lang); - } else if (want != INT_MAX) { - /* reduzierte restgröße */ - const char *hasspace = strchr(btname, ' '); - if (hasspace) { - new_order = - create_order(K_MAKE, lang, "%d \"%s\" %i", n - built, btname, b->no); - } else { - new_order = - create_order(K_MAKE, lang, "%d %s %i", n - built, btname, b->no); - } - } else if (btname) { - /* Neues Haus, Befehl mit Gebäudename */ - const char *hasspace = strchr(btname, ' '); - if (hasspace) { - new_order = create_order(K_MAKE, lang, "\"%s\" %i", btname, b->no); - } else { - new_order = create_order(K_MAKE, lang, "%s %i", btname, b->no); - } - } - - if (new_order) { - replace_order(&u->orders, ord, new_order); - free_order(new_order); - } - - b->size += built; - fset(b, BLD_EXPANDED); - - update_lighthouse(b); - - ADDMSG(&u->faction->msgs, msg_message("buildbuilding", - "building unit size", b, u, built)); - return built; } static void build_ship(unit * u, ship * sh, int want) { - const construction *construction = sh->type->construction; - int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; - int n; - int can = build(u, construction, size, want); + const construction *construction = sh->type->construction; + int size = (sh->size * DAMAGE_SCALE - sh->damage) / DAMAGE_SCALE; + int n; + int can = build(u, construction, size, want); - if ((n = construction->maxsize - sh->size) > 0 && can > 0) { - if (can >= n) { - sh->size += n; - can -= n; - } else { - sh->size += can; - n = can; - can = 0; + if ((n = construction->maxsize - sh->size) > 0 && can > 0) { + if (can >= n) { + sh->size += n; + can -= n; + } + else { + sh->size += can; + n = can; + can = 0; + } } - } - if (sh->damage && can) { - int repair = _min(sh->damage, can * DAMAGE_SCALE); - n += repair / DAMAGE_SCALE; - if (repair % DAMAGE_SCALE) - ++n; - sh->damage = sh->damage - repair; - } + if (sh->damage && can) { + int repair = _min(sh->damage, can * DAMAGE_SCALE); + n += repair / DAMAGE_SCALE; + if (repair % DAMAGE_SCALE) + ++n; + sh->damage = sh->damage - repair; + } - if (n) - ADDMSG(&u->faction->msgs, - msg_message("buildship", "ship unit size", sh, u, n)); + if (n) + ADDMSG(&u->faction->msgs, + msg_message("buildship", "ship unit size", sh, u, n)); } void create_ship(region * r, unit * u, const struct ship_type *newtype, int want, - order * ord) +order * ord) { - ship *sh; - int msize; - const construction *cons = newtype->construction; - order *new_order; + ship *sh; + int msize; + const construction *cons = newtype->construction; + order *new_order; - if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, ord, 100, MSG_PRODUCE); - return; - } - if (besieged(u)) { - cmistake(u, ord, 60, MSG_PRODUCE); - return; - } - - /* check if skill and material for 1 size is available */ - if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, - "error_build_skill_low", "value", cons->minskill)); - return; - } - - msize = maxbuild(u, cons); - if (msize == 0) { - cmistake(u, ord, 88, MSG_PRODUCE); - return; - } - if (want > 0) - want = _min(want, msize); - else - want = msize; - - sh = new_ship(newtype, r, u->faction->locale); - - if (leave(u, false)) { - if (fval(u_race(u), RCF_CANSAIL)) { - u_set_ship(u, sh); + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, ord, 100, MSG_PRODUCE); + return; + } + if (besieged(u)) { + cmistake(u, ord, 60, MSG_PRODUCE); + return; } - } - new_order = - create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, - parameters[P_SHIP]), sh->no); - replace_order(&u->orders, ord, new_order); - free_order(new_order); - build_ship(u, sh, want); + /* check if skill and material for 1 size is available */ + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_build_skill_low", "value", cons->minskill)); + return; + } + + msize = maxbuild(u, cons); + if (msize == 0) { + cmistake(u, ord, 88, MSG_PRODUCE); + return; + } + if (want > 0) + want = _min(want, msize); + else + want = msize; + + sh = new_ship(newtype, r, u->faction->locale); + + if (leave(u, false)) { + if (fval(u_race(u), RCF_CANSAIL)) { + u_set_ship(u, sh); + } + } + new_order = + create_order(K_MAKE, u->faction->locale, "%s %i", LOC(u->faction->locale, + parameters[P_SHIP]), sh->no); + replace_order(&u->orders, ord, new_order); + free_order(new_order); + + build_ship(u, sh, want); } void continue_ship(region * r, unit * u, int want) { - const construction *cons; - ship *sh; - int msize; + const construction *cons; + ship *sh; + int msize; - if (!eff_skill(u, SK_SHIPBUILDING, r)) { - cmistake(u, u->thisorder, 100, MSG_PRODUCE); - return; - } + if (!eff_skill(u, SK_SHIPBUILDING, r)) { + cmistake(u, u->thisorder, 100, MSG_PRODUCE); + return; + } - /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ - sh = getship(r); + /* Die Schiffsnummer bzw der Schiffstyp wird eingelesen */ + sh = getship(r); - if (!sh) - sh = u->ship; + if (!sh) + sh = u->ship; - if (!sh) { - cmistake(u, u->thisorder, 20, MSG_PRODUCE); - return; - } - cons = sh->type->construction; - assert(cons->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ - if (sh->size == cons->maxsize && !sh->damage) { - cmistake(u, u->thisorder, 16, MSG_PRODUCE); - return; - } - if (eff_skill(u, cons->skill, r) < cons->minskill) { - ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, - "error_build_skill_low", "value", cons->minskill)); - return; - } - msize = maxbuild(u, cons); - if (msize == 0) { - cmistake(u, u->thisorder, 88, MSG_PRODUCE); - return; - } - if (want > 0) - want = _min(want, msize); - else - want = msize; + if (!sh) { + cmistake(u, u->thisorder, 20, MSG_PRODUCE); + return; + } + cons = sh->type->construction; + assert(cons->improvement == NULL); /* sonst ist construction::size nicht ship_type::maxsize */ + if (sh->size == cons->maxsize && !sh->damage) { + cmistake(u, u->thisorder, 16, MSG_PRODUCE); + return; + } + if (eff_skill(u, cons->skill, r) < cons->minskill) { + ADDMSG(&u->faction->msgs, msg_feedback(u, u->thisorder, + "error_build_skill_low", "value", cons->minskill)); + return; + } + msize = maxbuild(u, cons); + if (msize == 0) { + cmistake(u, u->thisorder, 88, MSG_PRODUCE); + return; + } + if (want > 0) + want = _min(want, msize); + else + want = msize; - build_ship(u, sh, want); + build_ship(u, sh, want); } diff --git a/src/kernel/command.c b/src/kernel/command.c index c6d262dd0..86681c7c1 100644 --- a/src/kernel/command.c +++ b/src/kernel/command.c @@ -73,10 +73,11 @@ const char *str, parser fun) static int do_command_i(const void *keys, struct unit *u, struct order *ord) { + char token[128]; const char *c; variant var; - c = getstrtoken(); + c = gettoken(token, sizeof(token)); if (findtoken(keys, c, &var) == E_TOK_SUCCESS) { command *cmd = (command *)var.v; if (cmd->nodes && *c) { diff --git a/src/kernel/config.c b/src/kernel/config.c index 0e0e53e28..6d7f778a4 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -796,13 +796,15 @@ parse(keyword_t kword, int(*dofun) (unit *, struct order *), bool thisorder) unsigned int getuint(void) { - const char *s = getstrtoken(); + char token[16]; + const char *s = gettoken(token, sizeof(token)); return s ? atoip(s) : 0; } int getint(void) { - const char * s = getstrtoken(); + char token[16]; + const char * s = gettoken(token, sizeof(token)); return s ? atoi(s) : 0; } @@ -875,7 +877,8 @@ bool isparam(const char *s, const struct locale * lang, param_t param) param_t getparam(const struct locale * lang) { - const char *s = getstrtoken(); + char token[64]; + const char *s = gettoken(token, sizeof(token)); return s ? findparam(s, lang) : NOPARAM; } @@ -909,7 +912,8 @@ static int read_newunitid(const faction * f, const region * r) int read_unitid(const faction * f, const region * r) { - const char *s = getstrtoken(); + char token[8]; + const char *s = gettoken(token, sizeof(token)); /* Da s nun nur einen string enthaelt, suchen wir ihn direkt in der * paramliste. machen wir das nicht, dann wird getnewunit in s nach der diff --git a/src/kernel/save.c b/src/kernel/save.c index 01cc9fc70..00cb89d3e 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -225,7 +225,7 @@ static faction *factionorders(void) if (f != NULL && !fval(f, FFL_NPC)) { char token[128]; - const char *pass = getstrtok(token, sizeof(token)); + const char *pass = gettoken(token, sizeof(token)); if (!checkpasswd(f, (const char *)pass)) { log_debug("Invalid password for faction %s\n", itoa36(fid)); @@ -273,7 +273,7 @@ int readorders(const char *filename) param_t p; const char *s; init_tokens_str(b); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); p = s ? findparam(s, lang) : NOPARAM; switch (p) { #undef LOCALE_CHANGE diff --git a/src/kernel/unit.c b/src/kernel/unit.c index e55d21b5c..22dc8bc55 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -491,16 +491,19 @@ void usetprivate(unit * u, const char *str) { attrib *a = a_find(u->attribs, &at_private); - if (str == NULL) { - if (a) + if (str == NULL || *str == 0) { + if (a) { a_remove(&u->attribs, a); + } return; } - if (!a) + if (!a) { a = a_add(&u->attribs, a_new(&at_private)); - if (a->data.v) + } + if (a->data.v) { free(a->data.v); - a->data.v = _strdup((const char *)str); + } + a->data.v = _strdup(str); } /*********************/ diff --git a/src/laws.c b/src/laws.c index 95894ad9b..a7fd9a3f4 100755 --- a/src/laws.c +++ b/src/laws.c @@ -953,7 +953,7 @@ int quit_cmd(unit * u, struct order *ord) kwd = init_order(ord); assert(kwd == K_QUIT); - passwd = getstrtok(token, sizeof(token)); + passwd = gettoken(token, sizeof(token)); if (checkpasswd(f, (const char *)passwd)) { if (EnhancedQuit()) { int f2_id = getid(); @@ -1167,7 +1167,7 @@ void do_enter(struct region *r, bool is_final_attempt) const char * s; init_order(ord); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); p = findparam_ex(s, u->faction->locale); id = getid(); @@ -1357,7 +1357,7 @@ int ally_cmd(unit * u, struct order *ord) if (f == u->faction) return 0; - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (!s[0]) keyword = P_ANY; @@ -1495,6 +1495,7 @@ static void init_prefixnames(void) int prefix_cmd(unit * u, struct order *ord) { + char token[128]; attrib **ap; const char *s; local_names *in = pnames; @@ -1512,7 +1513,7 @@ int prefix_cmd(unit * u, struct order *ord) } init_order(ord); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if (!s || !*s) { attrib *a = NULL; @@ -1559,13 +1560,14 @@ static cmp_building_cb get_cmp_region_owner(void) int display_cmd(unit * u, struct order *ord) { + char token[128]; char **s = NULL; const char *str; region *r = u->region; init_order(ord); - str = getstrtoken(); + str = gettoken(token, sizeof(token)); switch (findparam_ex(str, u->faction->locale)) { case P_BUILDING: case P_GEBAEUDE: @@ -1601,15 +1603,7 @@ int display_cmd(unit * u, struct order *ord) break; case P_PRIVAT: - { - const char *d = getstrtoken(); - if (d == NULL || *d == 0) { - usetprivate(u, NULL); - } - else { - usetprivate(u, d); - } - } + usetprivate(u, getstrtoken()); break; case P_REGION: @@ -1732,6 +1726,7 @@ rename_building(unit * u, order * ord, building * b, const char *name) int name_cmd(struct unit *u, struct order *ord) { + char token[128]; building *b = u->building; region *r = u->region; char **s = NULL; @@ -1740,11 +1735,11 @@ int name_cmd(struct unit *u, struct order *ord) const char *str; init_order(ord); - str = getstrtoken(); + str = gettoken(token, sizeof(token)); p = findparam_ex(str, u->faction->locale); if (p == P_FOREIGN) { - str = getstrtoken(); + str = gettoken(token, sizeof(token)); foreign = true; p = findparam_ex(str, u->faction->locale); } @@ -1994,13 +1989,14 @@ static void mailfaction(unit * u, int n, struct order *ord, const char *s) int mail_cmd(unit * u, struct order *ord) { + char token[128]; region *r = u->region; unit *u2; const char *s; int n, cont; init_order(ord); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); /* Falls kein Parameter, ist das eine Einheitsnummer; * das Füllwort "AN" muß wegfallen, da gültige Nummer! */ @@ -2185,7 +2181,7 @@ int email_cmd(unit * u, struct order *ord) } else { faction *f = u->faction; - if (set_email(&f->email, (const char *)s) != 0) { + if (set_email(&f->email, s) != 0) { log_error("Invalid email address for faction %s: %s\n", itoa36(f->no), s); ADDMSG(&f->msgs, msg_message("changemail_invalid", "value", s)); } @@ -2204,7 +2200,7 @@ int password_cmd(unit * u, struct order *ord) bool pwok = true; init_order(ord); - s = getstrtoken(); + s = gettoken(pwbuf, sizeof(pwbuf)); if (!s || !*s) { for (i = 0; i < 6; i++) @@ -2213,14 +2209,10 @@ int password_cmd(unit * u, struct order *ord) } else { char *c; - - strlcpy(pwbuf, (const char *)s, 31); - pwbuf[31] = 0; - c = pwbuf; - while (*c && pwok) { - if (!isalnum(*(unsigned char *)c)) + for (c = pwbuf; *c && pwok; ++c) { + if (!isalnum(*(unsigned char *)c)) { pwok = false; - c++; + } } } free(u->faction->passw); @@ -2238,11 +2230,12 @@ int password_cmd(unit * u, struct order *ord) int send_cmd(unit * u, struct order *ord) { + char token[128]; const char *s; int option; init_order(ord); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); option = findoption(s, u->faction->locale); @@ -2579,14 +2572,11 @@ int promotion_cmd(unit * u, struct order *ord) int group_cmd(unit * u, struct order *ord) { - const char *s; keyword_t kwd; kwd = init_order(ord); assert(kwd == K_GROUP); - s = getstrtoken(); - - join_group(u, s); + join_group(u, getstrtoken()); return 0; } @@ -2621,7 +2611,7 @@ int reshow_cmd(unit * u, struct order *ord) param_t p = NOPARAM; init_order(ord); - s = getstrtok(lbuf, sizeof(lbuf)); + s = gettoken(lbuf, sizeof(lbuf)); if (s && isparam(s, u->faction->locale, P_ANY)) { p = getparam(u->faction->locale); @@ -2634,12 +2624,12 @@ int reshow_cmd(unit * u, struct order *ord) int status_cmd(unit * u, struct order *ord) { - const char *param; + char token[128]; + const char *s; init_order(ord); - - param = getstrtoken(); - switch (findparam(param, u->faction->locale)) { + s = gettoken(token, sizeof(token)); + switch (findparam(s, u->faction->locale)) { case P_NOT: setstatus(u, ST_AVOID); break; @@ -2667,7 +2657,7 @@ int status_cmd(unit * u, struct order *ord) } break; default: - if (param && param[0]) { + if (s && s[0]) { add_message(&u->faction->msgs, msg_feedback(u, ord, "unknown_status", "")); } @@ -2686,7 +2676,7 @@ int combatspell_cmd(unit * u, struct order *ord) spell *sp = 0; init_order(ord); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); /* KAMPFZAUBER [NICHT] löscht alle gesetzten Kampfzauber */ if (!s || *s == 0 || findparam(s, u->faction->locale) == P_NOT) { @@ -2699,7 +2689,7 @@ int combatspell_cmd(unit * u, struct order *ord) /* Merken, setzen kommt erst später */ level = getint(); level = _max(0, level); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); } sp = unit_getspell(u, s, u->faction->locale); @@ -2708,7 +2698,7 @@ int combatspell_cmd(unit * u, struct order *ord) return 0; } - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (findparam(s, u->faction->locale) == P_NOT) { /* KAMPFZAUBER "" NICHT löscht diesen speziellen @@ -2933,7 +2923,7 @@ void restack_units(void) unit *v; init_order(ord); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); p = findparam(s, u->faction->locale); id = getid(); v = findunit(id); @@ -3009,11 +2999,11 @@ int renumber_cmd(unit * u, order * ord) faction *f = u->faction; init_order(ord); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); switch (findparam_ex(s, u->faction->locale)) { case P_FACTION: - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (s && *s) { int id = atoi36((const char *)s); attrib *a = a_find(f->attribs, &at_number); @@ -3024,7 +3014,7 @@ int renumber_cmd(unit * u, order * ord) break; case P_UNIT: - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (s == NULL || *s == 0) { i = newunitid(); } @@ -3067,7 +3057,7 @@ int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 116, MSG_EVENT); break; } - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (s == NULL || *s == 0) { i = newcontainerid(); } @@ -3096,7 +3086,7 @@ int renumber_cmd(unit * u, order * ord) cmistake(u, ord, 148, MSG_EVENT); break; } - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (*s == 0) { i = newcontainerid(); } @@ -3397,7 +3387,7 @@ void new_units(void) init_order(makeord); alias = getid(); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); if (s && s[0]) { name = _strdup(s); } @@ -3707,7 +3697,7 @@ void defaultorders(void) order *new_order = 0; const char *s; init_order(ord); - s = getstrtok(lbuf, sizeof(lbuf)); + s = gettoken(lbuf, sizeof(lbuf)); if (s) { new_order = parse_order(s, u->faction->locale); } @@ -3823,13 +3813,13 @@ int use_cmd(unit * u, struct order *ord) init_order(ord); - t = getstrtok(token, sizeof(token)); + t = gettoken(token, sizeof(token)); n = atoi((const char *)t); if (n == 0) { if (isparam(t, u->faction->locale, P_ANY)) { /* BENUTZE ALLES Yanxspirit */ n = INT_MAX; - t = getstrtok(token, sizeof(token)); + t = gettoken(token, sizeof(token)); } else { /* BENUTZE Yanxspirit */ @@ -3838,7 +3828,7 @@ int use_cmd(unit * u, struct order *ord) } else { /* BENUTZE 42 Yanxspirit */ - t = getstrtok(token, sizeof(token)); + t = gettoken(token, sizeof(token)); } itype = t ? finditemtype(t, u->faction->locale) : NULL; @@ -3920,20 +3910,21 @@ int pay_cmd(unit * u, struct order *ord) static int reserve_i(unit * u, struct order *ord, int flags) { + char token[128]; if (u->number > 0 && (urace(u)->ec_flags & GETITEM)) { int use, count, para; const item_type *itype; const char *s; init_order(ord); - s = getstrtoken(); + s = gettoken(token, sizeof(token)); count = s ? atoip(s) : 0; para = findparam(s, u->faction->locale); if (count == 0 && para == P_EACH) { count = getint() * u->number; } - s = getstrtoken(); + s = gettoken(token, sizeof(token)); itype = s ? finditemtype(s, u->faction->locale) : 0; if (itype == NULL) return 0; @@ -3963,19 +3954,20 @@ int reserve_self(unit * u, struct order *ord) { int claim_cmd(unit * u, struct order *ord) { + char token[128]; const char *t; int n; const item_type *itype; init_order(ord); - t = getstrtoken(); + t = gettoken(token, sizeof(token)); n = atoi((const char *)t); if (n == 0) { n = 1; } else { - t = getstrtoken(); + t = gettoken(token, sizeof(token)); } itype = finditemtype(t, u->faction->locale); diff --git a/src/magic.c b/src/magic.c index d1bd6c661..4afd3cf61 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2519,7 +2519,7 @@ static castorder *cast_cmd(unit * u, order * ord) level = eff_skill(u, SK_MAGIC, r); init_order(ord); - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); param = findparam(s, u->faction->locale); /* für Syntax ' STUFE x REGION y z ' */ if (param == P_LEVEL) { @@ -2530,7 +2530,7 @@ static castorder *cast_cmd(unit * u, order * ord) cmistake(u, ord, 10, MSG_MAGIC); return 0; } - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); param = findparam(s, u->faction->locale); } if (param == P_REGION) { @@ -2547,7 +2547,7 @@ static castorder *cast_cmd(unit * u, order * ord) "unit region command", u, u->region, ord)); return 0; } - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); param = findparam(s, u->faction->locale); } /* für Syntax ' REGION x y STUFE z ' @@ -2560,7 +2560,7 @@ static castorder *cast_cmd(unit * u, order * ord) cmistake(u, ord, 10, MSG_MAGIC); return 0; } - s = getstrtok(token, sizeof(token)); + s = gettoken(token, sizeof(token)); } if (!s || !s[0] || strlen(s) == 0) { /* Fehler "Es wurde kein Zauber angegeben" */ @@ -2693,7 +2693,7 @@ static castorder *cast_cmd(unit * u, order * ord) char **params = (char**)malloc(2 * sizeof(char *)); int p = 0, size = 2; for (;;) { - s = getstrtoken(); + s = gettoken(token, sizeof(token)); if (!s || *s == 0) break; if (p + 1 >= size) { diff --git a/src/move.c b/src/move.c index cadb6dca6..4b295896e 100644 --- a/src/move.c +++ b/src/move.c @@ -1156,7 +1156,7 @@ static void cycle_route(order * ord, unit * u, int gereist) int bytes, cm = 0; char tail[1024], *bufp = tail; char neworder[2048]; - const char *token; + char token[128]; direction_t d = NODIRECTION; bool paused = false; bool pause; @@ -1171,11 +1171,12 @@ static void cycle_route(order * ord, unit * u, int gereist) neworder[0] = 0; for (cm = 0;; ++cm) { + const char *s; const struct locale *lang = u->faction->locale; pause = false; - token = getstrtoken(); - if (token && *token) { - d = get_direction(token, lang); + s = gettoken(token, sizeof(token)); + if (s && *s) { + d = get_direction(s, lang); if (d == D_PAUSE) { pause = true; } @@ -1448,11 +1449,12 @@ static void make_route(unit * u, order * ord, region_list ** routep) region_list **iroute = routep; region *current = u->region; region *next = NULL; - const char *token = getstrtoken(); - int error = movewhere(u, token, current, &next); + char token[128]; + const char *s = gettoken(token, sizeof(token)); + int error = movewhere(u, s, current, &next); if (error != E_MOVE_OK) { - message *msg = movement_error(u, token, ord, error); + message *msg = movement_error(u, s, ord, error); if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); @@ -1471,10 +1473,10 @@ static void make_route(unit * u, order * ord, region_list ** routep) iroute = &(*iroute)->next; current = next; - token = getstrtoken(); - error = movewhere(u, token, current, &next); + s = gettoken(token, sizeof(token)); + error = movewhere(u, s, current, &next); if (error) { - message *msg = movement_error(u, token, ord, error); + message *msg = movement_error(u, s, ord, error); if (msg != NULL) { add_message(&u->faction->msgs, msg); msg_release(msg); diff --git a/src/util/parser.c b/src/util/parser.c index 12ac19a6e..da2f3f521 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -132,6 +132,9 @@ char *parse_token(const char **str, char *lbuf, size_t len) } eatwhitespace_c(&ctoken); if (!*ctoken) { + if (len > 0) { + *cursor = 0; + } return 0; } while (*ctoken && cursor-len < lbuf-1) { @@ -209,7 +212,7 @@ const char *getstrtoken(void) return parse_token((const char **)&states->current_token, lbuf, MAXTOKENSIZE); } -const char *getstrtok(char *lbuf, size_t bufsize) +const char *gettoken(char *lbuf, size_t bufsize) { return parse_token((const char **)&states->current_token, lbuf, bufsize); } @@ -217,7 +220,7 @@ const char *getstrtok(char *lbuf, size_t bufsize) int getid(void) { char token[16]; - const char *str = getstrtok(token, sizeof(token)); + const char *str = gettoken(token, sizeof(token)); int i = str ? atoi36(str) : 0; if (i < 0) { return -1; diff --git a/src/util/parser.h b/src/util/parser.h index 2ab7f1b75..ab62591a9 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -22,7 +22,7 @@ extern "C" { void parser_popstate(void); bool parser_end(void); const char *getstrtoken(void); - const char *getstrtok(char *lbuf, size_t bufsize); + const char *gettoken(char *lbuf, size_t bufsize); int getid(void); #define getshipid() getid() #define getfactionid() getid() diff --git a/src/util/parser.test.c b/src/util/parser.test.c index f5543a7cb..910c11fc3 100644 --- a/src/util/parser.test.c +++ b/src/util/parser.test.c @@ -3,13 +3,21 @@ #include -static void test_parser(CuTest *tc) { +static void test_gettoken(CuTest *tc) { + char token[128]; init_tokens_str("HELP ONE TWO THREE"); + CuAssertStrEquals(tc, "HELP", gettoken(token, sizeof(token))); + CuAssertStrEquals(tc, "HELP", token); + CuAssertStrEquals(tc, "ONE", gettoken(token, sizeof(token))); + CuAssertStrEquals(tc, "TWO", gettoken(token, sizeof(token))); + CuAssertStrEquals(tc, "THREE", gettoken(token, sizeof(token))); + CuAssertPtrEquals(tc, NULL, (void *)gettoken(token, sizeof(token))); + CuAssertStrEquals(tc, "", token); } CuSuite *get_parser_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_parser); + SUITE_ADD_TEST(suite, test_gettoken); return suite; } From 5ebf05f625bbc83124772f443b4caf4b9617ae99 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 22 Dec 2014 16:31:10 +0100 Subject: [PATCH 4/5] additional tests for the parser. move more parsing code out of config.c --- src/kernel/config.c | 14 -------------- src/kernel/config.h | 2 -- src/study.c | 3 ++- src/util/parser.c | 13 +++++++++++++ src/util/parser.h | 2 ++ src/util/parser.test.c | 29 +++++++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 17 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 6d7f778a4..65623235c 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -794,20 +794,6 @@ parse(keyword_t kword, int(*dofun) (unit *, struct order *), bool thisorder) } } -unsigned int getuint(void) -{ - char token[16]; - const char *s = gettoken(token, sizeof(token)); - return s ? atoip(s) : 0; -} - -int getint(void) -{ - char token[16]; - const char * s = gettoken(token, sizeof(token)); - return s ? atoi(s) : 0; -} - const struct race *findrace(const char *s, const struct locale *lang) { void **tokens = get_translations(lang, UT_RACES); diff --git a/src/kernel/config.h b/src/kernel/config.h index 037c2b968..67355aae7 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -109,8 +109,6 @@ extern "C" { void make_undead_unit(struct unit *); unsigned int atoip(const char *s); - unsigned int getuint(void); - int getint(void); param_t findparam(const char *s, const struct locale *lang); param_t findparam_ex(const char *s, const struct locale * lang); diff --git a/src/study.c b/src/study.c index 173bc9d08..04f9b9a30 100644 --- a/src/study.c +++ b/src/study.c @@ -58,7 +58,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static skill_t getskill(const struct locale *lang) { - const char * s = getstrtoken(); + char token[128]; + const char * s = gettoken(token, sizeof(token)); return s ? get_skill(s, lang) : NOSKILL; } diff --git a/src/util/parser.c b/src/util/parser.c index da2f3f521..3e3dbb374 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -217,6 +217,19 @@ const char *gettoken(char *lbuf, size_t bufsize) return parse_token((const char **)&states->current_token, lbuf, bufsize); } +int getint(void) +{ + char token[16]; + const char * s = gettoken(token, sizeof(token)); + return s ? atoi(s) : 0; +} + +unsigned int getuint(void) +{ + int n = getint(); + return (n < 0) ? 0 : n; +} + int getid(void) { char token[16]; diff --git a/src/util/parser.h b/src/util/parser.h index ab62591a9..f1e01393c 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -23,6 +23,8 @@ extern "C" { bool parser_end(void); const char *getstrtoken(void); const char *gettoken(char *lbuf, size_t bufsize); + unsigned int getuint(void); + int getint(void); int getid(void); #define getshipid() getid() #define getfactionid() getid() diff --git a/src/util/parser.test.c b/src/util/parser.test.c index 910c11fc3..961761188 100644 --- a/src/util/parser.test.c +++ b/src/util/parser.test.c @@ -15,9 +15,38 @@ static void test_gettoken(CuTest *tc) { CuAssertStrEquals(tc, "", token); } +static void test_skip_token(CuTest *tc) { + char token[128]; + init_tokens_str("HELP ONE TWO THREE"); + skip_token(); + CuAssertStrEquals(tc, "ONE", gettoken(token, sizeof(token))); +} + +static void test_getintegers(CuTest *tc) { + init_tokens_str("ii 666 666 -42 -42"); + CuAssertIntEquals(tc, 666, getid()); + CuAssertIntEquals(tc, 666, getint()); + CuAssertIntEquals(tc, 666, getuint()); + CuAssertIntEquals(tc, -42, getint()); + CuAssertIntEquals(tc, 0, getuint()); + CuAssertIntEquals(tc, 0, getint()); +} + +static void test_getstrtoken(CuTest *tc) { + init_tokens_str("HELP ONE TWO THREE"); + CuAssertStrEquals(tc, "HELP", getstrtoken()); + CuAssertStrEquals(tc, "ONE", getstrtoken()); + CuAssertStrEquals(tc, "TWO", getstrtoken()); + CuAssertStrEquals(tc, "THREE", getstrtoken()); + CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); +} + CuSuite *get_parser_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_skip_token); SUITE_ADD_TEST(suite, test_gettoken); + SUITE_ADD_TEST(suite, test_getintegers); + SUITE_ADD_TEST(suite, test_getstrtoken); return suite; } From b27491eccd7866358df168077ef359247d27fcef Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 23 Dec 2014 09:23:37 +0100 Subject: [PATCH 5/5] move atoip out of config (small helper) and test it. remove some unnecessary variables from laws.c --- src/kernel/config.c | 13 ------------- src/kernel/config.h | 2 -- src/laws.c | 13 ++----------- src/util/parser.c | 13 +++++++++++++ src/util/parser.h | 2 ++ src/util/parser.test.c | 7 +++++++ 6 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/kernel/config.c b/src/kernel/config.c index 65623235c..3f511ffd9 100644 --- a/src/kernel/config.c +++ b/src/kernel/config.c @@ -587,19 +587,6 @@ int change_hitpoints(unit * u, int value) return hp; } -unsigned int atoip(const char *s) -{ - int n; - - assert(s); - n = atoi(s); - - if (n < 0) - n = 0; - - return n; -} - bool unit_has_cursed_item(const unit * u) { item *itm = u->items; diff --git a/src/kernel/config.h b/src/kernel/config.h index 67355aae7..ea521d5c8 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -108,8 +108,6 @@ extern "C" { /* special units */ void make_undead_unit(struct unit *); - unsigned int atoip(const char *s); - param_t findparam(const char *s, const struct locale *lang); param_t findparam_ex(const char *s, const struct locale * lang); bool isparam(const char *s, const struct locale * lang, param_t param); diff --git a/src/laws.c b/src/laws.c index a7fd9a3f4..b8ea9fa2e 100755 --- a/src/laws.c +++ b/src/laws.c @@ -2017,19 +2017,15 @@ int mail_cmd(unit * u, struct order *ord) } case P_FACTION: - { - bool see = false; - n = getfactionid(); for (u2 = r->units; u2; u2 = u2->next) { if (u2->faction->no == n && seefaction(u->faction, r, u2, 0)) { - see = true; break; } } - if (!see) { + if (!u2) { cmistake(u, ord, 66, MSG_MESSAGE); break; } @@ -2041,21 +2037,17 @@ int mail_cmd(unit * u, struct order *ord) } mailfaction(u, n, ord, s); return 0; - } case P_UNIT: - { - bool see = false; n = getid(); for (u2 = r->units; u2; u2 = u2->next) { if (u2->no == n && cansee(u->faction, r, u2, 0)) { - see = true; break; } } - if (!see) { + if (!u2) { ADDMSG(&u->faction->msgs, msg_feedback(u, ord, "feedback_unit_not_found", "")); return 0; @@ -2081,7 +2073,6 @@ int mail_cmd(unit * u, struct order *ord) mailunit(r, u, n, ord, s); } return 0; - } case P_BUILDING: case P_GEBAEUDE: diff --git a/src/util/parser.c b/src/util/parser.c index 3e3dbb374..51e99a9b6 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -240,3 +240,16 @@ int getid(void) } return i; } + +unsigned int atoip(const char *s) +{ + int n; + + assert(s); + n = atoi(s); + + if (n < 0) + n = 0; + + return n; +} diff --git a/src/util/parser.h b/src/util/parser.h index f1e01393c..01804ab01 100644 --- a/src/util/parser.h +++ b/src/util/parser.h @@ -26,6 +26,8 @@ extern "C" { unsigned int getuint(void); int getint(void); int getid(void); + unsigned int atoip(const char *s); + #define getshipid() getid() #define getfactionid() getid() diff --git a/src/util/parser.test.c b/src/util/parser.test.c index 961761188..0c6e0059c 100644 --- a/src/util/parser.test.c +++ b/src/util/parser.test.c @@ -41,9 +41,16 @@ static void test_getstrtoken(CuTest *tc) { CuAssertPtrEquals(tc, NULL, (void *)getstrtoken()); } +static void test_atoip(CuTest *tc) { + CuAssertIntEquals(tc, 42, atoip("42")); + CuAssertIntEquals(tc, 0, atoip("-42")); + CuAssertIntEquals(tc, 0, atoip("NOPE")); +} + CuSuite *get_parser_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_atoip); SUITE_ADD_TEST(suite, test_skip_token); SUITE_ADD_TEST(suite, test_gettoken); SUITE_ADD_TEST(suite, test_getintegers);