From 9f391039b5b78b4458752281852fc90bc9792cce Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 11 Dec 2017 18:20:21 +0100 Subject: [PATCH] more bsdstring removal, str_replace, unit tests. --- res/core/de/strings.xml | 4 ++-- src/battle.c | 8 ++++---- src/creport.c | 8 ++++---- src/gmtool.c | 6 +++--- src/kernel/alliance.c | 4 ++-- src/kernel/building.c | 6 +++--- src/kernel/connection.c | 10 ++++++---- src/kernel/order.c | 2 +- src/kernel/unit.c | 7 ++----- src/util/base36.c | 24 +++++++++++++++++------- src/util/base36.h | 12 ++++++++---- src/util/language.c | 10 +++++----- src/util/message.c | 4 ++-- src/util/strings.c | 37 +++++++++++++++++++++++++++++++++++-- src/util/strings.h | 5 +++-- src/util/strings.test.c | 33 ++++++++++++++++++++++++--------- 16 files changed, 121 insertions(+), 59 deletions(-) diff --git a/res/core/de/strings.xml b/res/core/de/strings.xml index ea4acf758..b06ff0445 100644 --- a/res/core/de/strings.xml +++ b/res/core/de/strings.xml @@ -7337,8 +7337,8 @@ - eine zu %d%% vollendete Straße - a road that is %d%% complete + eine zu $percent%% vollendete Straße + a road that is $percent% complete diff --git a/src/battle.c b/src/battle.c index a58b0ab63..c12e6d46e 100644 --- a/src/battle.c +++ b/src/battle.c @@ -189,7 +189,7 @@ static char *sidename(side * s) static char sidename_buf[4][SIDENAMEBUFLEN]; /* STATIC_RESULT: used for return, not across calls */ bufno = bufno % 4; - strlcpy(sidename_buf[bufno], factionname(s->stealthfaction ? s->stealthfaction : s->faction), SIDENAMEBUFLEN); + strncpy(sidename_buf[bufno], factionname(s->stealthfaction ? s->stealthfaction : s->faction), SIDENAMEBUFLEN); return sidename_buf[bufno++]; } @@ -2886,10 +2886,10 @@ static void print_header(battle * b) for (df = s->fighters; df; df = df->next) { if (is_attacker(df)) { if (first) { - bufp = STRLCPY(bufp, ", ", size); + strlcpy(bufp, ", ", size); } if (lastf) { - bufp = STRLCPY(bufp, lastf, size); + strlcpy(bufp, lastf, size); first = true; } if (seematrix(f, s)) @@ -3579,7 +3579,7 @@ static int battle_report(battle * b) if (komma) { bufp = STRLCPY(bufp, ", ", size); } - slprintf(buffer, sizeof(buffer), "%s %2d(%s): ", + snprintf(buffer, sizeof(buffer), "%s %2d(%s): ", loc_army, army_index(s), abbrev); bufp = STRLCPY(bufp, buffer, size); diff --git a/src/creport.c b/src/creport.c index 89cf4c9ce..3f3e1bfb8 100644 --- a/src/creport.c +++ b/src/creport.c @@ -516,7 +516,7 @@ static void report_crtypes(FILE * F, const struct locale *lang) assert(hash > 0); fprintf(F, "MESSAGETYPE %u\n", hash); fputc('\"', F); - fputs(escape_string(nrt_string(nrt), buffer, sizeof(buffer)), F); + fputs(str_escape(nrt_string(nrt), buffer, sizeof(buffer)), F); fputs("\";text\n", F); fprintf(F, "\"%s\";section\n", nrt_section(nrt)); } @@ -1067,7 +1067,7 @@ static void cr_reportspell(FILE * F, spell * sp, int level, const struct locale const char *name = translate(mkname("spell", sp->sname), spell_name(sp, lang)); - fprintf(F, "ZAUBER %d\n", hashstring(sp->sname)); + fprintf(F, "ZAUBER %d\n", str_hash(sp->sname)); fprintf(F, "\"%s\";name\n", name); fprintf(F, "%d;level\n", level); fprintf(F, "%d;rank\n", sp->rank); @@ -1115,7 +1115,7 @@ static char *cr_output_resource(char *buf, const resource_type *rtype, assert(rtype); name = resourcename(rtype, NMF_PLURAL); assert(name); - buf += sprintf(buf, "RESOURCE %u\n", hashstring(rtype->_name)); + buf += sprintf(buf, "RESOURCE %u\n", str_hash(rtype->_name)); tname = LOC(loc, name); assert(tname); tname = translate(name, tname); @@ -1663,7 +1663,7 @@ report_computer(const char *filename, report_context * ctx, const char *bom) if (ptype == NULL) continue; ch = resourcename(ptype->itype->rtype, 0); - fprintf(F, "TRANK %d\n", hashstring(ch)); + fprintf(F, "TRANK %d\n", str_hash(ch)); fprintf(F, "\"%s\";Name\n", translate(ch, LOC(f->locale, ch))); fprintf(F, "%d;Stufe\n", ptype->level); diff --git a/src/gmtool.c b/src/gmtool.c index fcb8cff8b..1fba47be6 100644 --- a/src/gmtool.c +++ b/src/gmtool.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include @@ -58,6 +57,7 @@ #include #include #include +#include #include static int g_quit; @@ -1228,7 +1228,7 @@ static void handlekey(state * st, int c) else if (findmode == 'F') { faction *f = select_faction(st); if (f != NULL) { - strlcpy(locate, itoa36(f->no), sizeof(locate)); + itoab_r(f->no, 36, locate, sizeof(locate)); findmode = 'f'; } else { @@ -1254,7 +1254,7 @@ static void handlekey(state * st, int c) region *first = (mr && mr->r && mr->r->next) ? mr->r->next : regions; if (findmode == 'f') { - slprintf(sbuffer, sizeof(sbuffer), "find-faction: %s", locate); + snprintf(sbuffer, sizeof(sbuffer), "find-faction: %s", locate); statusline(st->wnd_status->handle, sbuffer); f = findfaction(atoi36(locate)); if (f == NULL) { diff --git a/src/kernel/alliance.c b/src/kernel/alliance.c index f0cdf3bbd..ba3929f1f 100644 --- a/src/kernel/alliance.c +++ b/src/kernel/alliance.c @@ -28,7 +28,6 @@ without prior permission by the authors of Eressea. /* util includes */ #include #include -#include #include #include #include @@ -40,6 +39,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include alliance *alliances = NULL; @@ -422,7 +422,7 @@ const char *alliancename(const alliance * al) char *ibuf = idbuf[(++nextbuf) % 8]; if (al && al->name) { - slprintf(ibuf, sizeof(idbuf[0]), "%s (%s)", al->name, itoa36(al->id)); + snprintf(ibuf, sizeof(idbuf[0]), "%s (%s)", al->name, itoa36(al->id)); } else { return NULL; diff --git a/src/kernel/building.c b/src/kernel/building.c index ea01fe665..26d261e97 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -38,7 +38,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include @@ -54,6 +53,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* libc includes */ #include #include +#include #include #include @@ -372,7 +372,7 @@ building *new_building(const struct building_type * btype, region * r, bname = parameters[P_GEBAEUDE]; } assert(bname); - slprintf(buffer, sizeof(buffer), "%s %s", bname, itoa36(b->no)); + snprintf(buffer, sizeof(buffer), "%s %s", bname, itoa36(b->no)); b->name = strdup(bname); return b; } @@ -489,7 +489,7 @@ int bt_effsize(const building_type * btype, const building * b, int bsize) const char *write_buildingname(const building * b, char *ibuf, size_t size) { - slprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no)); + snprintf(ibuf, size, "%s (%s)", b->name, itoa36(b->no)); return ibuf; } diff --git a/src/kernel/connection.c b/src/kernel/connection.c index b630429fe..2cae4ec8f 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -25,19 +25,21 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "unit.h" #include -#include +#include #include #include #include -#include #include +#include +#include #include /* libc includes */ #include #include #include +#include #include int nextborder = 0; @@ -514,8 +516,8 @@ static const char *b_nameroad(const connection * b, const region * r, else { int percent = MAX(1, 100 * local / r->terrain->max_road); if (local) { - slprintf(buffer, sizeof(buffer), LOC(f->locale, mkname("border", - "a_road_percent")), percent); + const char *temp = LOC(f->locale, mkname("border", "a_road_percent")); + str_replace(buffer, sizeof(buffer), temp, "$percent", itoa10(percent)); } else { return LOC(f->locale, mkname("border", "a_road_connection")); diff --git a/src/kernel/order.c b/src/kernel/order.c index baf26f615..605f44be9 100644 --- a/src/kernel/order.c +++ b/src/kernel/order.c @@ -170,7 +170,7 @@ int stream_order(struct stream *out, const struct order *ord, const struct local char obuf[1024]; swrite(" ", 1, 1, out); if (escape) { - text = escape_string(text, obuf, sizeof(obuf)); + text = str_escape(text, obuf, sizeof(obuf)); } swrite(text, 1, strlen(text), out); } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index ee4da958c..87ccd5944 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -51,7 +51,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include -#include #include #include #include @@ -1458,9 +1457,7 @@ void default_name(const unit *u, char name[], int len) { else { result = parameters[P_UNIT]; } - strlcpy(name, result, len); - strlcat(name, " ", len); - strlcat(name, itoa36(u->no), len); + snprintf(name, len, "%s %s", result, itoa36(u->no)); } void name_unit(unit * u) @@ -1874,7 +1871,7 @@ static int nextbuf = 0; char *write_unitname(const unit * u, char *buffer, size_t size) { const char * name = unit_getname(u); - slprintf(buffer, size, "%s (%s)", name, itoa36(u->no)); + snprintf(buffer, size, "%s (%s)", name, itoa36(u->no)); buffer[size - 1] = 0; return buffer; } diff --git a/src/util/base36.c b/src/util/base36.c index 221ece870..ef7c38371 100644 --- a/src/util/base36.c +++ b/src/util/base36.c @@ -52,16 +52,14 @@ int atoi36(const char *str) return i * sign; } -const char *itoab(int i, int base) +const char *itoab_r(int i, int base, char *s, size_t len) { - static char sstr[80]; - char *s, *dst; + char *dst; static int index = 0; /* STATIC_XCALL: used across calls */ - s = sstr + (index * 20); - index = (index + 1) & 3; /* quick for % 4 */ - dst = s + 19; - (*dst--) = 0; + assert(len > 2); + dst = s + len - 2; + *dst = 0; if (i != 0) { int neg = 0; @@ -101,6 +99,18 @@ const char *itoab(int i, int base) return dst; } +const char *itoab(int i, int base) +{ + static char sstr[80]; + char *s; + static int index = 0; /* STATIC_XCALL: used across calls */ + + s = sstr + (index * 20); + index = (index + 1) & 3; /* quick for % 4 */ + + return itoab_r(i, base, s, 20); +} + const char *itoa36(int i) { return itoab(i, 36); diff --git a/src/util/base36.h b/src/util/base36.h index 650538219..804952ab7 100644 --- a/src/util/base36.h +++ b/src/util/base36.h @@ -18,15 +18,19 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_UTIL_BASE36 #define H_UTIL_BASE36 + +#include + #ifdef __cplusplus extern "C" { #endif + const char *itoab_r(int i, int base, char *result, size_t len); + const char *itoab(int i, int base); + const char *itoa36(int i); + const char *itoa10(int i); extern int atoi36(const char *s); - extern const char *itoab(int i, int base); - extern const char *itoa36(int i); - extern const char *itoa10(int i); - extern int i10toi36(int i); + int i10toi36(int i); #ifdef __cplusplus } diff --git a/src/util/language.c b/src/util/language.c index a1cda4d2f..8cd6188d2 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -56,7 +56,7 @@ unsigned int locale_index(const locale * lang) locale *get_locale(const char *name) { - unsigned int hkey = hashstring(name); + unsigned int hkey = str_hash(name); locale *l = locales; while (l && l->hashkey != hkey) l = l->next; @@ -68,7 +68,7 @@ static unsigned int nextlocaleindex = 0; locale *get_or_create_locale(const char *name) { locale *l; - unsigned int hkey = hashstring(name); + unsigned int hkey = str_hash(name); locale **lp = &locales; if (!locales) { @@ -120,7 +120,7 @@ void make_locales(const char *str) const char *locale_getstring(const locale * lang, const char *key) { - unsigned int hkey = hashstring(key); + unsigned int hkey = str_hash(key); unsigned int id = hkey & (SMAXHASH - 1); const struct locale_str *find; @@ -150,7 +150,7 @@ const char *locale_string(const locale * lang, const char *key, bool warn) assert(key); if (key != NULL) { - unsigned int hkey = hashstring(key); + unsigned int hkey = str_hash(key); unsigned int id = hkey & (SMAXHASH - 1); struct locale_str *find; @@ -188,7 +188,7 @@ const char *locale_string(const locale * lang, const char *key, bool warn) void locale_setstring(locale * lang, const char *key, const char *value) { - unsigned int hkey = hashstring(key); + unsigned int hkey = str_hash(key); unsigned int id = hkey & (SMAXHASH - 1); struct locale_str *find; if (!lang) { diff --git a/src/util/message.c b/src/util/message.c index e53010093..239863bd1 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -192,7 +192,7 @@ void mt_clear(void) { const message_type *mt_find(const char *name) { - unsigned int hash = hashstring(name) % MT_MAXHASH; + unsigned int hash = str_hash(name) % MT_MAXHASH; selist *ql = messagetypes[hash]; int qi; @@ -218,7 +218,7 @@ static unsigned int mt_id(const message_type * mtype) const message_type *mt_register(message_type * type) { - unsigned int hash = hashstring(type->name) % MT_MAXHASH; + unsigned int hash = str_hash(type->name) % MT_MAXHASH; selist **qlp = messagetypes + hash; if (selist_set_insert(qlp, type, NULL)) { diff --git a/src/util/strings.c b/src/util/strings.c index 4e7e17aa4..55d4ca5fb 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -45,7 +45,40 @@ char *set_string(char **s, const char *neu) return *s; } -unsigned int hashstring(const char *s) +void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value) +{ + size_t val_len = strlen(value); + size_t var_len = strlen(var); + char *s = buffer; + while (buffer + size > s) { + char *p = strstr(tmpl, var); + size_t len; + if (p) { + len = p - tmpl; + } + else { + len = strlen(tmpl); + } + if (len < size) { + memmove(s, tmpl, len); + tmpl += len; + s += len; + size -= len; + if (p && val_len < size) { + tmpl += var_len; + memmove(s, value, val_len); + s += val_len; + size -= val_len; + } + } + if (!p) { + break; + } + } + *s = 0; +} + +unsigned int str_hash(const char *s) { unsigned int key = 0; assert(s); @@ -55,7 +88,7 @@ unsigned int hashstring(const char *s) return key & 0x7FFFFFFF; } -const char *escape_string(const char *str, char *buffer, +const char *str_escape(const char *str, char *buffer, size_t len) { const char *start = strchr(str, '\"'); diff --git a/src/util/strings.h b/src/util/strings.h index 05a435e2c..f63299d93 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -25,9 +25,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. extern "C" { #endif + void str_replace(char *buffer, size_t size, const char *tmpl, const char *var, const char *value); + const char *str_escape(const char *str, char *buffer, size_t len); char *set_string(char **s, const char *neu); - unsigned int hashstring(const char *s); - const char *escape_string(const char *str, char *buffer, size_t len); + unsigned int str_hash(const char *s); unsigned int jenkins_hash(unsigned int a); unsigned int wang_hash(unsigned int a); diff --git a/src/util/strings.test.c b/src/util/strings.test.c index bcee29e47..60a0b5d37 100644 --- a/src/util/strings.test.c +++ b/src/util/strings.test.c @@ -4,21 +4,36 @@ #include #include "strings.h" -static void test_escape_string(CuTest * tc) +static void test_str_escape(CuTest * tc) { char scratch[64]; - CuAssertStrEquals(tc, "12345678901234567890", escape_string("12345678901234567890", scratch, 16)); - CuAssertStrEquals(tc, "123456789\\\"12345", escape_string("123456789\"1234567890", scratch, 16)); - CuAssertStrEquals(tc, "1234567890123456", escape_string("1234567890123456\"890", scratch, 16)); - CuAssertStrEquals(tc, "hello world", escape_string("hello world", scratch, sizeof(scratch))); - CuAssertStrEquals(tc, "hello \\\"world\\\"", escape_string("hello \"world\"", scratch, sizeof(scratch))); - CuAssertStrEquals(tc, "\\\"\\\\", escape_string("\"\\", scratch, sizeof(scratch))); - CuAssertStrEquals(tc, "\\\\", escape_string("\\", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "12345678901234567890", str_escape("12345678901234567890", scratch, 16)); + CuAssertStrEquals(tc, "123456789\\\"12345", str_escape("123456789\"1234567890", scratch, 16)); + CuAssertStrEquals(tc, "1234567890123456", str_escape("1234567890123456\"890", scratch, 16)); + CuAssertStrEquals(tc, "hello world", str_escape("hello world", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "hello \\\"world\\\"", str_escape("hello \"world\"", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "\\\"\\\\", str_escape("\"\\", scratch, sizeof(scratch))); + CuAssertStrEquals(tc, "\\\\", str_escape("\\", scratch, sizeof(scratch))); +} + +static void test_str_replace(CuTest * tc) +{ + char result[64]; + str_replace(result, sizeof(result), "Hello $who!", "$who", "World"); + CuAssertStrEquals(tc, "Hello World!", result); +} + +static void test_str_hash(CuTest * tc) +{ + CuAssertIntEquals(tc, 0, str_hash("")); + CuAssertIntEquals(tc, 140703196, str_hash("Hodor")); } CuSuite *get_strings_suite(void) { CuSuite *suite = CuSuiteNew(); - SUITE_ADD_TEST(suite, test_escape_string); + SUITE_ADD_TEST(suite, test_str_hash); + SUITE_ADD_TEST(suite, test_str_escape); + SUITE_ADD_TEST(suite, test_str_replace); return suite; }