diff --git a/scripts/tests/e2/undead.lua b/scripts/tests/e2/undead.lua index 4d8c9772b..c712111ba 100644 --- a/scripts/tests/e2/undead.lua +++ b/scripts/tests/e2/undead.lua @@ -29,7 +29,10 @@ function test_undead_reserve_other() u1:clear_orders() u1:add_order("RESERVIERE 1 Holz") process_orders() + + -- Intermittent Failure (clang): expected 0 but was 2 assert_equal(0, u1:get_item("log")) + assert_equal(2, u2:get_item("log")) end diff --git a/scripts/write-reports.lua b/scripts/write-reports.lua new file mode 100644 index 000000000..9010dddbd --- /dev/null +++ b/scripts/write-reports.lua @@ -0,0 +1,19 @@ +local path = 'scripts' +if config.install then + path = config.install .. '/' .. path +end +package.path = package.path .. ';' .. path .. '/?.lua;' .. path .. '/?/init.lua' +require 'eressea' +require 'eressea.xmlconf' -- read xml data + +local rules = {} +if config.rules then + rules = require('eressea.' .. config.rules) + eressea.log.info('loaded ' .. #rules .. ' modules for ' .. config.rules) +else + eressea.log.warning('no rule modules loaded, specify a game in eressea.ini or with -r') +end + +eressea.read_game(get_turn() .. '.dat') +init_reports() +write_reports() diff --git a/src/attributes/key.c b/src/attributes/key.c index 76a18c876..cd369de66 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -271,8 +271,11 @@ static int *keys_update(int *base, int key, int val) else { int sz = keys_size(n); if (n + 1 > sz) { + void * tmp; sz = keys_size(n + 1); - base = realloc(base, (sz * 2 + 1) * sizeof(int)); + tmp = realloc(base, (sz * 2 + 1) * sizeof(int)); + if (!tmp) abort(); + base = (int *)tmp; } base[0] = n + 1; kv = keys_get(base, l); diff --git a/src/chaos.c b/src/chaos.c index 615113656..925545369 100644 --- a/src/chaos.c +++ b/src/chaos.c @@ -54,6 +54,7 @@ static const terrain_type *chaosterrain(void) } if (numtypes > 0) { types = malloc(sizeof(terrain_type *) * numtypes); + if (!types) abort(); numtypes = 0; for (terrain = terrains(); terrain != NULL; terrain = terrain->next) { if ((terrain->flags & LAND_REGION) && terrain->herbs) { diff --git a/src/creport.c b/src/creport.c index 3ac9dffe9..71c283e89 100644 --- a/src/creport.c +++ b/src/creport.c @@ -17,9 +17,12 @@ without prior permission by the authors of Eressea. /* tweakable features */ #define RENDER_CRMESSAGES -#define BUFFERSIZE 32768 #define RESOURCECOMPAT +#define BUFFERSIZE 32768 +/* riesig, wegen spionage-messages :-( */ +static char g_bigbuf[BUFFERSIZE]; + #include /* modules include */ @@ -132,9 +135,12 @@ static const char *translate(const char *key, const char *value) t = junkyard; junkyard = junkyard->next; } - else + else { t = malloc(sizeof(translation)); + if (!t) abort(); + } t->key = str_strdup(key); + if (!t->key) abort(); t->value = value; t->next = translation_table[kk]; translation_table[kk] = t; @@ -264,13 +270,12 @@ cr_output_curses(struct stream *out, const faction * viewer, const void *obj, ob msg = msg_curse(c, obj, typ, self); if (msg) { - char buf[BUFFERSIZE]; if (!header) { header = 1; stream_printf(out, "EFFECTS\n"); } - nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); - stream_printf(out, "\"%s\"\n", buf); + nr_render(msg, viewer->locale, g_bigbuf, sizeof(g_bigbuf), viewer); + stream_printf(out, "\"%s\"\n", g_bigbuf); msg_release(msg); } a = a->next; @@ -571,28 +576,26 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) { struct mlist *m = msgs->begin; while (m) { - char crbuffer[BUFFERSIZE]; /* gross, wegen spionage-messages :-( */ bool printed = false; const struct message_type *mtype = m->msg->type; unsigned int hash = mtype->key; #ifdef RENDER_CRMESSAGES - char nrbuffer[1024 * 32]; - nrbuffer[0] = '\0'; - if (nr_render(m->msg, f->locale, nrbuffer, sizeof(nrbuffer), f) > 0) { + g_bigbuf[0] = '\0'; + if (nr_render(m->msg, f->locale, g_bigbuf, sizeof(g_bigbuf), f) > 0) { fprintf(F, "MESSAGE %d\n", message_id(m->msg)); fprintf(F, "%u;type\n", hash); - fwritestr(F, nrbuffer); + fwritestr(F, g_bigbuf); fputs(";rendered\n", F); printed = true; } #endif - crbuffer[0] = '\0'; - if (cr_render(m->msg, crbuffer, (const void *)f) == 0) { - if (crbuffer[0]) { + g_bigbuf[0] = '\0'; + if (cr_render(m->msg, g_bigbuf, (const void *)f) == 0) { + if (g_bigbuf[0]) { if (!printed) { fprintf(F, "MESSAGE %d\n", message_id(m->msg)); } - fputs(crbuffer, F); + fputs(g_bigbuf, F); } } else { @@ -605,6 +608,7 @@ static void render_messages(FILE * F, faction * f, message_list * msgs) kmt = kmt->nexthash; if (kmt == NULL) { kmt = (struct known_mtype *)malloc(sizeof(struct known_mtype)); + if (!kmt) abort(); kmt->nexthash = mtypehash[ihash]; kmt->mtype = mtype; mtypehash[ihash] = kmt; @@ -1218,7 +1222,7 @@ cr_borders(const region * r, const faction * f, seen_mode mode, FILE * F) void cr_output_resources(stream *out, const faction * f, const region *r, bool see_unit) { - char cbuf[BUFFERSIZE], *pos = cbuf; + char *pos = g_bigbuf; resource_report result[MAX_RAWMATERIALS]; int n, size = report_resources(r, result, MAX_RAWMATERIALS, f, see_unit); @@ -1251,8 +1255,8 @@ void cr_output_resources(stream *out, const faction * f, const region *r, bool s result[n].level); } } - if (pos != cbuf) { - swrite(cbuf, 1, pos - cbuf, out); + if (pos != g_bigbuf) { + swrite(g_bigbuf, 1, pos - g_bigbuf, out); } } diff --git a/src/kernel/config.h b/src/kernel/config.h index 95df10ae9..7789cd36d 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -31,8 +31,8 @@ extern "C" { struct param; struct _dictionary_; -#define DISPLAYSIZE 8192 /* max. L�nge einer Beschreibung, incl trailing 0 */ -#define ORDERSIZE (DISPLAYSIZE*2) /* max. length of an order */ +#define DISPLAYSIZE 4096 /* max. L�nge einer Beschreibung, incl trailing 0 */ +#define ORDERSIZE 4096 /* max. length of an order */ #define NAMESIZE 128 /* max. L�nge eines Namens, incl trailing 0 */ #define IDSIZE 16 /* max. L�nge einer no (als String), incl trailing 0 */ #define OBJECTIDSIZE (NAMESIZE+5+IDSIZE) /* max. L�nge der Strings, die diff --git a/src/main.c b/src/main.c index d51f55471..0dec070ce 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include "eressea.h" #ifdef USE_CURSES @@ -231,6 +232,10 @@ static int parse_args(int argc, char **argv) i = get_arg(argc, argv, 2, i, &arg, 0); turn = atoi(arg); break; + case 'w': + i = get_arg(argc, argv, 2, i, &arg, 0); + bcrypt_workfactor = arg ? atoi(arg) : 0xff; + break; case 'q': verbosity = 0; break; diff --git a/src/renumber.c b/src/renumber.c index a4653e1a0..e562a0285 100644 --- a/src/renumber.c +++ b/src/renumber.c @@ -167,7 +167,7 @@ int renumber_cmd(unit * u, order * ord) break; } s = gettoken(token, sizeof(token)); - if (*s == 0) { + if (s == NULL || *s == 0) { i = newcontainerid(); } else { diff --git a/src/renumber.test.c b/src/renumber.test.c index e5f9c5c33..f65011cf7 100644 --- a/src/renumber.test.c +++ b/src/renumber.test.c @@ -101,7 +101,12 @@ static void test_renumber_building(CuTest *tc) { no = u->building->no; uno = (no > 1) ? no - 1 : no + 1; lang = u->faction->locale; - u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_BUILDING]), itoa36(uno)); + u->thisorder = create_order(K_NUMBER, lang, LOC(lang, parameters[P_BUILDING])); + renumber_cmd(u, u->thisorder); + CuAssertTrue(tc, no != u->building->no); + free_order(u->thisorder); + + u->thisorder = create_order(K_NUMBER, lang, "%s %i", LOC(lang, parameters[P_BUILDING]), uno); renumber_cmd(u, u->thisorder); CuAssertIntEquals(tc, uno, u->building->no); test_teardown(); @@ -120,7 +125,7 @@ static void test_renumber_building_duplicate(CuTest *tc) { u->building = test_create_building(u->region, NULL); no = u->building->no; lang = f->locale; - u->thisorder = create_order(K_NUMBER, lang, "%s %s", LOC(lang, parameters[P_BUILDING]), itoa36(uno)); + u->thisorder = create_order(K_NUMBER, lang, "%s %i", LOC(lang, parameters[P_BUILDING]), uno); renumber_cmd(u, u->thisorder); CuAssertPtrNotNull(tc, test_find_messagetype(f->msgs, "error115")); CuAssertIntEquals(tc, no, u->building->no); diff --git a/src/report.c b/src/report.c index 045ec3c3f..d4e059f05 100644 --- a/src/report.c +++ b/src/report.c @@ -105,6 +105,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include +/* pre-C99 compatibility */ +#ifndef SIZE_MAX +#define SIZE_MAX ((size_t)(-1)) +#endif + #define ECHECK_VERSION "4.01" extern int *storms; @@ -1521,29 +1526,81 @@ static int count_allies_cb(struct allies *all, faction *af, int status, void *ud struct show_s { sbstring sbs; + stream *out; const faction *f; int num_allies; + int num_listed; + size_t maxlen; }; +/* TODO: does not test for non-ascii unicode spaces. */ +#define IS_UTF8_SPACE(pos) (*pos > 0 && *pos <= CHAR_MAX && isspace(*pos)) + +void pump_paragraph(sbstring *sbp, stream *out, size_t maxlen, bool isfinal) +{ + while (sbs_length(sbp) > maxlen) { + char *pos, *begin = sbp->begin; + while (*begin && IS_UTF8_SPACE(begin)) { + /* eat whitespace */ + ++begin; + } + pos = begin; + while (pos) { + char *next = strchr(pos+1, ' '); + if (next == NULL) { + if (isfinal) { + swrite(begin, 1, sbp->end - begin, out); + newline(out); + } + return; + } + else if (next > begin + maxlen) { + ptrdiff_t len = pos - begin; + swrite(begin, 1, len, out); + newline(out); + + while (*pos && IS_UTF8_SPACE(pos)) { + ++pos; + ++len; + } + sbs_substr(sbp, len, SIZE_MAX); + break; + } + pos = next; + } + } + if (isfinal) { + char *pos = sbp->begin; + while (*pos && IS_UTF8_SPACE(pos)) { + /* eat whitespace */ + ++pos; + } + swrite(pos, 1, sbp->end - pos, out); + newline(out); + } +} + static int show_allies_cb(struct allies *all, faction *af, int status, void *udata) { struct show_s * show = (struct show_s *)udata; const faction * f = show->f; - + sbstring *sbp = &show->sbs; int mode = alliance_status(f, af, status); - --show->num_allies; - if (sbs_length(&show->sbs) > 0) { - /* not the first entry */ - if (0 == show->num_allies) { - sbs_strcat(&show->sbs, LOC(f->locale, "list_and")); + + if (show->num_listed++ != 0) { + if (show->num_listed == show->num_allies) { + /* last entry */ + sbs_strcat(sbp, LOC(f->locale, "list_and")); } else { - sbs_strcat(&show->sbs, ", "); + /* neither first entry nor last*/ + sbs_strcat(sbp, ", "); } } - sbs_strcat(&show->sbs, factionname(af)); - sbs_strcat(&show->sbs, " ("); + sbs_strcat(sbp, factionname(af)); + pump_paragraph(sbp, show->out, show->maxlen, false); + sbs_strcat(sbp, " ("); if ((mode & HELP_ALL) == HELP_ALL) { - sbs_strcat(&show->sbs, LOC(f->locale, parameters[P_ANY])); + sbs_strcat(sbp, LOC(f->locale, parameters[P_ANY])); } else { int h, hh = 0; @@ -1573,58 +1630,60 @@ static int show_allies_cb(struct allies *all, faction *af, int status, void *uda } if (p != MAXPARAMS) { if (hh) { - sbs_strcat(&show->sbs, ", "); + sbs_strcat(sbp, ", "); } - sbs_strcat(&show->sbs, LOC(f->locale, parameters[p])); + sbs_strcat(sbp, LOC(f->locale, parameters[p])); hh = 1; } } } - sbs_strcat(&show->sbs, ")"); + if (show->num_allies == show->num_listed) { + sbs_strcat(sbp, ")."); + pump_paragraph(sbp, show->out, show->maxlen, true); + } + else { + sbs_strcat(sbp, ")"); + pump_paragraph(sbp, show->out, show->maxlen, false); + } return 0; } -static void -show_allies(const faction * f, struct allies * allies, char *buf, size_t size) +void report_allies(struct stream *out, size_t maxlen, const struct faction * f, struct allies * allies, const char *prefix) { int num_allies = 0; + + assert(maxlen <= REPORTWIDTH); allies_walk(allies, count_allies_cb, &num_allies); if (num_allies > 0) { struct show_s show; + char buf[REPORTWIDTH * 2]; show.f = f; + show.out = out; show.num_allies = num_allies; - sbs_init(&show.sbs, buf, size); + show.num_listed = 0; + show.maxlen = maxlen; + sbs_init(&show.sbs, buf, sizeof(buf)); + sbs_strcpy(&show.sbs, prefix); allies_walk(allies, show_allies_cb, &show); - sbs_strcat(&show.sbs, "."); } } static void allies(struct stream *out, const faction * f) { const group *g = f->groups; - char buf[16384]; + char prefix[64]; if (f->allies) { - int bytes; - size_t size = sizeof(buf); - bytes = snprintf(buf, size, "%s ", LOC(f->locale, "faction_help")); - size -= bytes; - show_allies(f, f->allies, buf + bytes, size); - paragraph(out, buf, 0, 0, 0); - newline(out); + snprintf(prefix, sizeof(prefix), "%s ", LOC(f->locale, "faction_help")); + report_allies(out, REPORTWIDTH, f, f->allies, prefix); } while (g) { if (g->allies) { - int bytes; - size_t size = sizeof(buf); - bytes = snprintf(buf, size, "%s %s ", g->name, LOC(f->locale, "group_help")); - size -= bytes; - show_allies(f, g->allies, buf + bytes, size); - paragraph(out, buf, 0, 0, 0); - newline(out); + snprintf(prefix, sizeof(prefix), "%s %s ", g->name, LOC(f->locale, "group_help")); + report_allies(out, REPORTWIDTH, f, g->allies, prefix); } g = g->next; } @@ -1982,8 +2041,6 @@ void report_travelthru(struct stream *out, region *r, const faction *f) } } -#include "util/bsdstring.h" - int report_plaintext(const char *filename, report_context * ctx, const char *bom) diff --git a/src/report.h b/src/report.h index bb3629497..307dba38b 100644 --- a/src/report.h +++ b/src/report.h @@ -14,21 +14,27 @@ #define H_GC_REPORT #include +#include #ifdef __cplusplus extern "C" { #endif struct stream; + struct sbstring; struct spellbook_entry; struct region; struct faction; struct locale; + struct allies; + void register_nr(void); void report_cleanup(void); void write_spaces(struct stream *out, size_t num); void report_travelthru(struct stream *out, struct region * r, const struct faction * f); void report_region(struct stream *out, const struct region * r, struct faction * f); + void report_allies(struct stream *out, size_t maxlen, const struct faction * f, struct allies * allies, const char *prefix); + void pump_paragraph(struct sbstring *sbp, struct stream *out, size_t maxlen, bool isfinal); void nr_spell_syntax(char *buf, size_t size, struct spellbook_entry * sbe, const struct locale *lang); void nr_spell(struct stream *out, struct spellbook_entry * sbe, const struct locale *lang); diff --git a/src/report.test.c b/src/report.test.c index 3c49b14fc..84f2f070d 100644 --- a/src/report.test.c +++ b/src/report.test.c @@ -3,6 +3,7 @@ #include "move.h" #include "travelthru.h" +#include #include #include #include @@ -143,6 +144,58 @@ static void test_report_region(CuTest *tc) { test_teardown(); } +static void test_report_allies(CuTest *tc) { + stream out = { 0 }; + char buf[1024]; + char exp[1024]; + size_t len, linebreak = 72; + struct locale *lang; + faction *f, *f1, *f2, *f3; + + test_setup(); + lang = test_create_locale(); + locale_setstring(lang, "list_and", " und "); + mstream_init(&out); + f = test_create_faction(NULL); + f->locale = lang; + f1 = test_create_faction(NULL); + f2 = test_create_faction(NULL); + f3 = test_create_faction(NULL); + snprintf(exp, sizeof(exp), "Wir helfen %s (%s).\n", + factionname(f1), + LOC(lang, parameters[P_GUARD])); + ally_set(&f->allies, f1, HELP_GUARD); + report_allies(&out, linebreak, f, f->allies, "Wir helfen "); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = 0; + CuAssertStrEquals(tc, exp, buf); + + out.api->rewind(out.handle); + ally_set(&f->allies, f2, HELP_GIVE); + ally_set(&f->allies, f3, HELP_ALL); + snprintf(exp, sizeof(exp), "Wir helfen %s (%s), %s (%s)", + factionname(f1), + LOC(lang, parameters[P_GUARD]), + factionname(f2), + LOC(lang, parameters[P_GIVE])); + linebreak = strlen(exp); + snprintf(exp, sizeof(exp), "Wir helfen %s (%s), %s (%s)\nund %s (%s).\n", + factionname(f1), + LOC(lang, parameters[P_GUARD]), + factionname(f2), + LOC(lang, parameters[P_GIVE]), + factionname(f3), + LOC(lang, parameters[P_ANY])); + report_allies(&out, linebreak, f, f->allies, "Wir helfen "); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = 0; + CuAssertStrEquals(tc, exp, buf); + + test_teardown(); +} + static void test_report_travelthru(CuTest *tc) { stream out = { 0 }; char buf[1024]; @@ -302,6 +355,7 @@ CuSuite *get_report_suite(void) SUITE_ADD_TEST(suite, test_write_many_spaces); SUITE_ADD_TEST(suite, test_report_travelthru); SUITE_ADD_TEST(suite, test_report_region); + SUITE_ADD_TEST(suite, test_report_allies); SUITE_ADD_TEST(suite, test_write_spell_syntax); return suite; } diff --git a/src/reports.c b/src/reports.c index 2148b2126..561bcecf2 100644 --- a/src/reports.c +++ b/src/reports.c @@ -64,7 +64,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include "kernel/attrib.h" #include "util/base36.h" -#include "util/bsdstring.h" #include "util/functions.h" #include "util/goodies.h" #include "util/language.h" @@ -1688,7 +1687,7 @@ int reports(void) faction *f; FILE *mailit; int retval = 0; - char path[4096]; + char path[PATH_MAX]; const char * rpath = reportpath(); log_info("Writing reports for turn %d:", turn); @@ -2157,7 +2156,7 @@ static void eval_resources(struct opstack **stack, const void *userdata) const char *rname = resourcename(res->type, (res->number != 1) ? NMF_PLURAL : 0); sbs_strcat(&sbs, str_itoa(res->number)); - sbs_strcat(&sbs, ""); + sbs_strcat(&sbs, " "); sbs_strcat(&sbs, LOC(lang, rname)); res = res->next; @@ -2209,41 +2208,49 @@ const char *get_mailcmd(const struct locale *loc) return result; } +static void print_trail(const faction *f, const region *r, + const struct locale *lang, struct sbstring *sbp) +{ + char buf[64]; + const char *trail = trailinto(r, lang); + const char *rn = f_regionid_s(r, f); + if (snprintf(buf, sizeof(buf), trail, rn) != 0) { + sbs_strcat(sbp, buf); + } +} + static void eval_trail(struct opstack **stack, const void *userdata) { /* order -> string */ const faction *report = (const faction *)userdata; const struct locale *lang = report ? report->locale : default_locale; const arg_regions *aregs = (const arg_regions *)opop(stack).v; char buf[512]; - size_t size = sizeof(buf) - 1; variant var; - char *bufp = buf; + sbstring sbs; #ifdef _SECURECRT_ERRCODE_VALUES_DEFINED - /* stupid MS broke snprintf */ + /* MSVC touches errno in snprintf */ int eold = errno; #endif + sbs_init(&sbs, buf, sizeof(buf)); if (aregs != NULL) { int i, handle_end = 0, begin = 0; handle_end = aregs->nregions; for (i = begin; i < handle_end; ++i) { region *r = aregs->regions[i]; - const char *trail = trailinto(r, lang); - const char *rn = f_regionid_s(r, report); + sbs_strcat(&sbs, ", "); - if (wrptr(&bufp, &size, snprintf(bufp, size, trail, rn)) != 0) - WARN_STATIC_BUFFER(); + print_trail(report, r, lang, &sbs); if (i + 2 < handle_end) { - bufp = STRLCPY(bufp, ", ", size); + sbs_strcat(&sbs, ", "); } else if (i + 1 < handle_end) { - bufp = STRLCPY(bufp, LOC(lang, "list_and"), size); + sbs_strcat(&sbs, LOC(lang, "list_and")); } } } - *bufp = 0; - var.v = strcpy(balloc((size_t)(bufp - buf + 1)), buf); + var.v = strcpy(balloc(sbs_length(&sbs)), buf); opush(stack, var); #ifdef _SECURECRT_ERRCODE_VALUES_DEFINED if (errno == ERANGE) { @@ -2252,11 +2259,9 @@ static void eval_trail(struct opstack **stack, const void *userdata) #endif } -void report_race_skills(const race *rc, char *zText, size_t length, const struct locale *lang) +void report_race_skills(const race *rc, const struct locale *lang, sbstring *sbp) { - size_t size = length - 1; int dh = 0, dh1 = 0, sk; - char *bufp = zText; for (sk = 0; sk < MAXSKILLS; ++sk) { if (skill_enabled(sk) && rc->bonus[sk] > -5) @@ -2265,29 +2270,30 @@ void report_race_skills(const race *rc, char *zText, size_t length, const struct for (sk = 0; sk < MAXSKILLS; sk++) { if (skill_enabled(sk) && rc->bonus[sk] > -5) { - size_t bytes; dh--; if (dh1 == 0) { dh1 = 1; } else { if (dh == 0) { - bytes = str_strlcpy(bufp, LOC(lang, "list_and"), size); + sbs_strcat(sbp, LOC(lang, "list_and")); } else { - bytes = str_strlcpy(bufp, ", ", size); + sbs_strcat(sbp, ", "); } - assert(bytes <= INT_MAX); - BUFFER_STRCAT(bufp, size, bytes); } - bytes = str_strlcpy(bufp, skillname((skill_t)sk, lang), - size); - assert(bytes <= INT_MAX); - BUFFER_STRCAT(bufp, size, (int)bytes); + sbs_strcat(sbp, skillname((skill_t)sk, lang)); } } } +void report_race_skills_depr(const race *rc, char *zText, size_t length, const struct locale *lang) +{ + sbstring sbs; + sbs_init(&sbs, zText, length); + report_race_skills(rc, lang, &sbs); +} + static void eval_direction(struct opstack **stack, const void *userdata) { const faction *report = (const faction *)userdata; diff --git a/src/reports.h b/src/reports.h index 14ac6da45..91af51bc2 100644 --- a/src/reports.h +++ b/src/reports.h @@ -121,7 +121,7 @@ extern "C" { const struct unit *owner, const struct faction *viewer); void report_warnings(struct faction *f, int now); void report_raceinfo(const struct race *rc, const struct locale *lang, struct sbstring *sbp); - void report_race_skills(const struct race *rc, char *zText, size_t length, const struct locale *lang); + void report_race_skills_depr(const struct race *rc, char *zText, size_t length, const struct locale *lang); void report_item(const struct unit *owner, const struct item *i, const struct faction *viewer, const char **name, const char **basename, int *number, bool singular); diff --git a/src/spells.c b/src/spells.c index 8e3abd253..b29e86ea9 100644 --- a/src/spells.c +++ b/src/spells.c @@ -592,7 +592,7 @@ static int sp_summon_familiar(castorder * co) msg_release(msg); make_familiar(caster, r, rc, zText); - report_race_skills(rc, zText, sizeof(zText), caster->faction->locale); + report_race_skills_depr(rc, zText, sizeof(zText), caster->faction->locale); ADDMSG(&caster->faction->msgs, msg_message("familiar_describe", "mage race skills", caster, rc, zText)); return cast_level; diff --git a/src/util/crmessage.c b/src/util/crmessage.c index 3e3b05177..e59ea474a 100644 --- a/src/util/crmessage.c +++ b/src/util/crmessage.c @@ -63,6 +63,7 @@ void tsf_register(const char *name, tostring_f fun) } if (tsf == NULL) { tsf = malloc(sizeof(tsf_list)); + if (!tsf) abort(); tsf->fun = fun; tsf->name = name; tsf->next = tostringfs; @@ -102,12 +103,14 @@ void crt_register(const struct message_type *mtype) } if (!crt) { crt = malloc(sizeof(crmessage_type)); + if (!crt) abort(); crt->mtype = mtype; crt->next = crtypes[hash]; crtypes[hash] = crt; if (mtype->nparameters > 0) { int i; crt->renderers = malloc(sizeof(tostring_f) * mtype->nparameters); + if (!crt->renderers) abort(); /* can be scrapped for memory vs. speed */ for (i = 0; i != mtype->nparameters; ++i) { crt->renderers[i] = tsf_find(mtype->types[i]->name); diff --git a/src/util/goodies.c b/src/util/goodies.c index fcfaa1013..a673e6e55 100644 --- a/src/util/goodies.c +++ b/src/util/goodies.c @@ -32,8 +32,11 @@ int *intlist_init(void) int *intlist_add(int *i_p, int i) { + void *tmp; i_p[0]++; - i_p = realloc(i_p, (i_p[0] + 1) * sizeof(int)); + tmp = realloc(i_p, (i_p[0] + 1) * sizeof(int)); + if (!tmp) abort(); + i_p = (int *)tmp; i_p[i_p[0]] = i; return (i_p); diff --git a/src/util/language.c b/src/util/language.c index afc9d01d0..de31075cc 100644 --- a/src/util/language.c +++ b/src/util/language.c @@ -83,7 +83,7 @@ locale *get_or_create_locale(const char *name) return *lp; } } - *lp = l = (locale *)calloc(sizeof(locale), 1); + *lp = l = (locale *)calloc(1, sizeof(locale)); assert_alloc(l); l->hashkey = hkey; l->name = str_strdup(name); @@ -206,6 +206,7 @@ void locale_setstring(locale * lang, const char *key, const char *value) } if (!find) { find = calloc(1, sizeof(struct locale_str)); + if (!find) abort(); find->nexthash = lang->strings[id]; lang->strings[id] = find; find->hashkey = hkey; diff --git a/src/util/lists.c b/src/util/lists.c index 81f9c9ab2..97e782795 100644 --- a/src/util/lists.c +++ b/src/util/lists.c @@ -120,6 +120,7 @@ unsigned int listlen(void *l) void addstrlist(strlist ** SP, const char *s) { strlist *slist = malloc(sizeof(strlist)); + if (!slist) abort(); slist->next = NULL; slist->s = str_strdup(s); addlist(SP, slist); diff --git a/src/util/log.c b/src/util/log.c index fd50ec700..26f745a3b 100644 --- a/src/util/log.c +++ b/src/util/log.c @@ -52,6 +52,7 @@ static log_t *loggers; log_t *log_create(int flags, void *data, log_fun call) { log_t *lgr = malloc(sizeof(log_t)); + if (!lgr) abort(); lgr->log = call; lgr->flags = flags; lgr->data = data; @@ -147,7 +148,7 @@ static const char *log_prefix(int level) { static int check_dupe(const char *format, int level) { static int last_type; /* STATIC_XCALL: used across calls */ - static char last_message[32]; /* STATIC_XCALL: used across calls */ + static char last_message[32] = { 0 }; /* STATIC_XCALL: used across calls */ static int dupes = 0; /* STATIC_XCALL: used across calls */ if (strncmp(last_message, format, sizeof(last_message)) == 0) { /* TODO: C6054: String 'last_message' might not be zero - terminated. */ diff --git a/src/util/message.c b/src/util/message.c index 47a8eb7af..fc645f3a2 100644 --- a/src/util/message.c +++ b/src/util/message.c @@ -41,6 +41,7 @@ register_argtype(const char *name, void(*free_arg) (variant), variant(*copy_arg) (variant), variant_type type) { arg_type *atype = (arg_type *)malloc(sizeof(arg_type)); + if (!atype) abort(); atype->name = name; atype->next = argtypes; atype->release = free_arg; @@ -90,7 +91,9 @@ message_type *mt_create(message_type * mtype, const char *args[], int nparameter int i; mtype->nparameters = nparameters; mtype->pnames = (char **)malloc(sizeof(char *) * nparameters); + if (!mtype->pnames) abort(); mtype->types = (arg_type **)malloc(sizeof(arg_type *) * nparameters); + if (!mtype->types) abort(); for (i = 0; args[i]; ++i) { const char *x = args[i]; const char *spos = strchr(x, ':'); @@ -103,8 +106,8 @@ message_type *mt_create(message_type * mtype, const char *args[], int nparameter assert(atype); } else { - char *cp; - cp = malloc(spos - x + 1); + char *cp = malloc(spos - x + 1); + if (!cp) abort(); memcpy(cp, x, spos - x); cp[spos - x] = '\0'; mtype->pnames[i] = cp; @@ -162,8 +165,10 @@ message_type *mt_new(const char *name, const char *section) return NULL; } mtype = (message_type *)malloc(sizeof(message_type)); + if (!mtype) abort(); mtype->key = 0; mtype->name = str_strdup(name); + if (!mtype->name) abort(); mtype->section = section_find(section); if (!mtype->section) { mtype->section = section_add(section); @@ -219,7 +224,6 @@ static void free_arg(const arg_type * atype, variant data) message *msg_create(const struct message_type *mtype, variant args[]) { - int i; message *msg; assert(mtype != NULL); @@ -228,11 +232,17 @@ message *msg_create(const struct message_type *mtype, variant args[]) return NULL; } msg = (message *)malloc(sizeof(message)); + if (!msg) abort(); msg->type = mtype; - msg->parameters = (variant *)(mtype->nparameters ? calloc(mtype->nparameters, sizeof(variant)) : NULL); msg->refcount = 1; - for (i = 0; i != mtype->nparameters; ++i) { - msg->parameters[i] = copy_arg(mtype->types[i], args[i]); + msg->parameters = NULL; + if (mtype->nparameters > 0) { + int i; + msg->parameters = (variant *)(mtype->nparameters ? calloc(mtype->nparameters, sizeof(variant)) : NULL); + if (!msg->parameters) abort(); + for (i = 0; i != mtype->nparameters; ++i) { + msg->parameters[i] = copy_arg(mtype->types[i], args[i]); + } } if (msg_log_create) msg_log_create(msg); diff --git a/src/util/nrmessage.c b/src/util/nrmessage.c index 1fdde6935..564abecb7 100644 --- a/src/util/nrmessage.c +++ b/src/util/nrmessage.c @@ -33,7 +33,19 @@ typedef struct nrmessage_type { } nrmessage_type; #define NRT_MAXHASH 1021 -static nrmessage_type *nrtypes[NRT_MAXHASH]; +static nrmessage_type *nrtypes[NRT_MAXHASH] = { 0 }; + +void free_nrmesssages(void) { + int i; + for (i = 0; i != NRT_MAXHASH; ++i) { + while (nrtypes[i]) { + nrmessage_type *nr = nrtypes[i]; + nrtypes[i] = nr->next; + free(nr->vars); + free(nr); + } + } +} const char *nrt_string(const struct message_type *mtype, const struct locale *lang) @@ -81,7 +93,8 @@ nrt_register(const struct message_type *mtype) int i; char zNames[256]; char *c = zNames; - nrt = malloc(sizeof(nrmessage_type)); + nrt = calloc(1, sizeof(nrmessage_type)); + if (!nrt) abort(); nrt->mtype = mtype; nrt->next = nrtypes[hash]; nrtypes[hash] = nrt; @@ -92,6 +105,7 @@ nrt_register(const struct message_type *mtype) c += str_strlcpy(c, mtype->pnames[i], sizeof(zNames)-(c-zNames)); } nrt->vars = str_strdup(zNames); + if (!nrt->vars) abort(); } } @@ -115,16 +129,3 @@ size_t size, const void *userdata) buffer[0] = 0; return 0; } - -void free_nrmesssages(void) { - int i; - for (i = 0; i != NRT_MAXHASH; ++i) { - while (nrtypes[i]) { - nrmessage_type *nr = nrtypes[i]; - nrtypes[i] = nr->next; - free(nr->vars); - free(nr); - } - } -} - diff --git a/src/util/parser.c b/src/util/parser.c index edcb5e3d6..f0090fdf3 100644 --- a/src/util/parser.c +++ b/src/util/parser.c @@ -58,6 +58,7 @@ void init_tokens_ex(const char *initstr, void *data, void (*dtor)(void *)) { if (states == NULL) { states = calloc(1, sizeof(parser_state)); + if (!states) abort(); } else if (states->dtor) { states->dtor(states->data); @@ -74,6 +75,7 @@ void init_tokens_str(const char *initstr) { void parser_pushstate(void) { parser_state *new_state = calloc(1, sizeof(parser_state)); + if (!new_state) abort(); new_state->current_token = NULL; new_state->next = states; states = new_state; diff --git a/src/util/password.c b/src/util/password.c index 61ae8f2a0..aab16acee 100644 --- a/src/util/password.c +++ b/src/util/password.c @@ -17,7 +17,7 @@ bool password_is_implemented(cryptalgo_t algo) { } const char * password_hash(const char * passwd, cryptalgo_t algo) { - if (algo == PASSWORD_BCRYPT) { + if (algo == PASSWORD_BCRYPT && bcrypt_workfactor != 0) { char salt[BCRYPT_HASHSIZE]; static char hash[BCRYPT_HASHSIZE]; int ret; @@ -32,9 +32,12 @@ const char * password_hash(const char * passwd, cryptalgo_t algo) { int password_verify(const char * pwhash, const char * passwd) { if (pwhash[0] == '$') { if (pwhash[1] == '2') { - int ret = bcrypt_checkpw(passwd, pwhash); - assert(ret != -1); - return (ret == 0) ? VERIFY_OK : VERIFY_FAIL; + if (bcrypt_workfactor > 0) { + int ret = bcrypt_checkpw(passwd, pwhash); + assert(ret != -1); + return (ret == 0) ? VERIFY_OK : VERIFY_FAIL; + } + return VERIFY_OK; } } return (strcmp(passwd, pwhash) == 0) ? VERIFY_OK : VERIFY_FAIL; diff --git a/src/util/pofile.c b/src/util/pofile.c index e1126ba0e..131994c37 100644 --- a/src/util/pofile.c +++ b/src/util/pofile.c @@ -74,7 +74,8 @@ int pofile_read(const char *filename, int (*callback)(const char *msgid, const c line = read_line(F); while (line) { char token[8]; - int err = sscanf(line, "%8s", token); + int err = sscanf(line, "%7s", token); + token[7] = 0; if (err == 1) { char *text = NULL; size_t size = 0, len = strlen(token); diff --git a/src/util/rand.c b/src/util/rand.c index f409cd0bb..3ab4490ab 100644 --- a/src/util/rand.c +++ b/src/util/rand.c @@ -132,6 +132,7 @@ void random_source_inject_array(double inject[], int size) { if (values) free(values); values = malloc(sizeof(double) * size); + if (!values) abort(); for (i=0; i < size; ++i) { values[i] = inject[i]; } diff --git a/src/util/strings.c b/src/util/strings.c index 4eac7856e..2f766fc5d 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -80,9 +80,10 @@ size_t str_strlcpy(char *dst, const char *src, size_t len) /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { - if (len != 0) - *d = '\0'; /* NUL-terminate dst */ - while (*s++); + if (len != 0) { + *d = '\0'; /* NUL-terminate dst */ + } + return (s - src) + strlen(s); /* count does not include NUL */ } return (s - src - 1); /* count does not include NUL */ @@ -287,8 +288,9 @@ void sbs_strcat(struct sbstring *sbs, const char *str) size_t len; assert(sbs); len = sbs->size - (sbs->end - sbs->begin); - len = str_strlcpy(sbs->end, str, len); - sbs->end += len; + str_strlcpy(sbs->end, str, len); + sbs->end += strlen(sbs->end); + assert(sbs->begin + sbs->size >= sbs->end); } void sbs_strcpy(struct sbstring *sbs, const char *str) @@ -298,10 +300,32 @@ void sbs_strcpy(struct sbstring *sbs, const char *str) len = sbs->size - 1; } sbs->end = sbs->begin + len; + assert(sbs->begin + sbs->size >= sbs->end); +} + +void sbs_substr(sbstring *sbs, ptrdiff_t pos, size_t len) +{ + if (pos > sbs->end - sbs->begin) { + /* starting past end of string, do nothing */ + sbs->end = sbs->begin; + } + if (pos >= 0) { + size_t sz = sbs->end - (sbs->begin + pos); + if (len > sz) len = sz; + if (len - pos > 0) { + memmove(sbs->begin, sbs->begin + pos, len); + } + else { + memcpy(sbs->begin, sbs->begin + pos, len); + } + sbs->end = sbs->begin + len; + sbs->end[0] = '\0'; + } } size_t sbs_length(const struct sbstring *sbs) { + assert(sbs->begin + sbs->size >= sbs->end); return sbs->end - sbs->begin; } diff --git a/src/util/strings.h b/src/util/strings.h index bf6299332..0b22f1b4a 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -53,6 +53,7 @@ extern "C" { void sbs_strcat(struct sbstring *sbs, const char *str); void sbs_strncat(struct sbstring *sbs, const char *str, size_t size); void sbs_strcpy(struct sbstring *sbs, const char *str); + void sbs_substr(struct sbstring *sbp, ptrdiff_t pos, size_t len); size_t sbs_length(const struct sbstring *sbs); /* benchmark for units: diff --git a/src/util/strings.test.c b/src/util/strings.test.c index 2205e538b..1c1ea8d72 100644 --- a/src/util/strings.test.c +++ b/src/util/strings.test.c @@ -115,16 +115,21 @@ static void test_str_strlcpy(CuTest * tc) memset(buffer, 0x7f, sizeof(buffer)); - CuAssertIntEquals(tc, 4, (int)str_strlcpy(buffer, "herp", 4)); - CuAssertStrEquals(tc, "her", buffer); - - CuAssertIntEquals(tc, 4, (int)str_strlcpy(buffer, "herp", 8)); /*-V666 */ + CuAssertIntEquals(tc, 4, (int)str_strlcpy(buffer, "herp", 8)); CuAssertStrEquals(tc, "herp", buffer); CuAssertIntEquals(tc, 0x7f, buffer[5]); + CuAssertIntEquals(tc, 4, (int)str_strlcpy(buffer, "herp", 4)); + CuAssertStrEquals(tc, "her", buffer); + CuAssertIntEquals(tc, 8, (int)str_strlcpy(buffer, "herpderp", 8)); CuAssertStrEquals(tc, "herpder", buffer); CuAssertIntEquals(tc, 0x7f, buffer[8]); + + CuAssertIntEquals(tc, 8, (int)str_strlcpy(buffer, "herpderp", 16)); + CuAssertStrEquals(tc, "herpderp", buffer); + CuAssertIntEquals(tc, 0x7f, buffer[9]); + errno = 0; } @@ -154,6 +159,69 @@ static void test_sbstring(CuTest * tc) CuAssertStrEquals(tc, "123456789012345", sbs.begin); } +static void test_sbs_strcat(CuTest * tc) +{ + char buffer[8]; + sbstring sbs; + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "AB"); + CuAssertStrEquals(tc, "AB", sbs.begin); + sbs_strcat(&sbs, "CD"); + CuAssertStrEquals(tc, "ABCD", sbs.begin); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcat(&sbs, "12345678901234567890"); + CuAssertStrEquals(tc, "1234567", sbs.begin); + sbs_strcat(&sbs, "12345678901234567890"); + CuAssertStrEquals(tc, "1234567", sbs.begin); + + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strncat(&sbs, "12345678901234567890", 4); + CuAssertStrEquals(tc, "1234", sbs.begin); + sbs_strncat(&sbs, "12345678901234567890", 4); + CuAssertStrEquals(tc, "1234123", sbs.begin); +} + +static void test_sbs_substr(CuTest * tc) +{ + char buffer[10]; + sbstring sbs; + + buffer[9] = 'A'; + sbs_init(&sbs, buffer, sizeof(buffer)); + sbs_strcpy(&sbs, "12345678"); + CuAssertStrEquals(tc, "12345678", buffer); + sbs_substr(&sbs, 0, 4); + CuAssertStrEquals(tc, "1234", buffer); + CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); + + sbs_strcpy(&sbs, "12345678"); + CuAssertStrEquals(tc, "12345678", buffer); + sbs_substr(&sbs, 4, 4); + CuAssertStrEquals(tc, "5678", buffer); + CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); + + sbs_strcpy(&sbs, "12345678"); + CuAssertStrEquals(tc, "12345678", buffer); + sbs_substr(&sbs, 2, 4); + CuAssertStrEquals(tc, "3456", buffer); + CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); + + sbs_strcpy(&sbs, "12345678"); + CuAssertStrEquals(tc, "12345678", buffer); + sbs_substr(&sbs, 4, 4); + CuAssertStrEquals(tc, "5678", buffer); + CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); + + sbs_strcpy(&sbs, "12345678"); + CuAssertStrEquals(tc, "12345678", buffer); + sbs_substr(&sbs, 4, 8); + CuAssertStrEquals(tc, "5678", buffer); + CuAssertIntEquals(tc, 4, (int)sbs_length(&sbs)); + CuAssertIntEquals(tc, 'A', buffer[9]); +} + CuSuite *get_strings_suite(void) { CuSuite *suite = CuSuiteNew(); @@ -166,5 +234,7 @@ CuSuite *get_strings_suite(void) SUITE_ADD_TEST(suite, test_str_strlcat); SUITE_ADD_TEST(suite, test_str_strlcpy); SUITE_ADD_TEST(suite, test_sbstring); + SUITE_ADD_TEST(suite, test_sbs_strcat); + SUITE_ADD_TEST(suite, test_sbs_substr); return suite; } diff --git a/src/util/umlaut.c b/src/util/umlaut.c index 00252fb02..c070acb55 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -118,6 +118,7 @@ char * transliterate(char * out, size_t size, const char * in) tnode * mknode(void) { tnode * node = (tnode *)calloc(1, sizeof(tnode)); + if (!node) abort(); node->refcount = 1; return node; } @@ -179,6 +180,7 @@ void addtoken(tnode ** root, const char *str, variant id) } ref = (tref *)malloc(sizeof(tref)); + if (!ref) abort(); ref->ucs = ucs; ref->node = node; ref->nexthash = tk->next[index]; @@ -221,11 +223,10 @@ void addtoken(tnode ** root, const char *str, variant id) } } -void freetokens(tnode * root) +void freetokens(tnode * node) { - tnode * node = root; int i; - for (i = 0; node && i != NODEHASHSIZE; ++i) { + for (i = 0; i != NODEHASHSIZE; ++i) { if (node->next[i]) { tref * ref = node->next[i]; while (ref) { @@ -237,6 +238,7 @@ void freetokens(tnode * root) node->next[i] = 0; } } + /* TODO: warning C6011: Dereferencing NULL pointer 'node'. */ if (--node->refcount == 0) { free(node); }