From c0c06f06134bb1dcd2060fecba5a98745a84de28 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 27 Nov 2018 22:20:30 +0100 Subject: [PATCH 1/7] version number increment --- src/kernel/version.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/version.c b/src/kernel/version.c index 0cfad7b73..92a7a6b1e 100644 --- a/src/kernel/version.c +++ b/src/kernel/version.c @@ -7,7 +7,7 @@ #ifndef ERESSEA_VERSION /* the version number, if it was not passed to make with -D */ -#define ERESSEA_VERSION "3.18.0" +#define ERESSEA_VERSION "3.19.0" #endif const char *eressea_version(void) { From 56f54a62e8cce95758c6b8b98a8425f6cec8be26 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 28 Nov 2018 12:45:48 +0100 Subject: [PATCH 2/7] print spells with sbstring --- src/report.c | 103 ++++++++++++++++++--------------------------------- 1 file changed, 36 insertions(+), 67 deletions(-) diff --git a/src/report.c b/src/report.c index d4e059f05..b0e3891fa 100644 --- a/src/report.c +++ b/src/report.c @@ -234,19 +234,18 @@ paragraph(struct stream *out, const char *str, ptrdiff_t indent, int hanging_ind } while (*begin); } -static size_t write_spell_modifier(const spell * sp, int flag, const char * str, bool cont, char * bufp, size_t size) { +static bool write_spell_modifier(const spell * sp, int flag, const char * str, bool cont, sbstring *sbp) { if (sp->sptyp & flag) { - size_t bytes = 0; if (cont) { - bytes = str_strlcpy(bufp, ", ", size); + sbs_strcat(sbp, ", "); } else { - bytes = str_strlcpy(bufp, " ", size); + sbs_strcat(sbp, " "); } - bytes += str_strlcpy(bufp + bytes, str, size - bytes); - return bytes; + sbs_strcat(sbp, str); + return true; } - return 0; + return cont; } void nr_spell_syntax(char *buf, size_t size, spellbook_entry * sbe, const struct locale *lang) @@ -435,11 +434,11 @@ void nr_spell_syntax(char *buf, size_t size, spellbook_entry * sbe, const struct void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *lang) { - int bytes, k, itemanz, costtyp; + int k, itemanz, costtyp; + bool cont; char buf[4096]; - char *startp, *bufp = buf; - size_t size = sizeof(buf) - 1; const spell *sp = spellref_get(&sbe->spref); + sbstring sbs; newline(out); centre(out, spell_name(sp, lang), true); @@ -447,29 +446,22 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la paragraph(out, LOC(lang, "nr_spell_description"), 0, 0, 0); paragraph(out, spell_info(sp, lang), 2, 0, 0); - bytes = (int)str_strlcpy(bufp, LOC(lang, "nr_spell_type"), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_init(&sbs, buf, sizeof(buf)); + sbs_strcat(&sbs, LOC(lang, "nr_spell_type")); + sbs_strcat(&sbs, " "); - if (size) { - *bufp++ = ' '; - --size; - } if (sp->sptyp & PRECOMBATSPELL) { - bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_precombat"), size); + sbs_strcat(&sbs, LOC(lang, "sptype_precombat")); } else if (sp->sptyp & COMBATSPELL) { - bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_combat"), size); + sbs_strcat(&sbs, LOC(lang, "sptype_combat")); } else if (sp->sptyp & POSTCOMBATSPELL) { - bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_postcombat"), size); + sbs_strcat(&sbs, LOC(lang, "sptype_postcombat")); } else { - bytes = (int)str_strlcpy(bufp, LOC(lang, "sptype_normal"), size); + sbs_strcat(&sbs, LOC(lang, "sptype_normal")); } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - *bufp = 0; paragraph(out, buf, 0, 0, 0); sprintf(buf, "%s %d", LOC(lang, "nr_spell_level"), sbe->level); @@ -484,61 +476,38 @@ void nr_spell(struct stream *out, spellbook_entry * sbe, const struct locale *la itemanz = sp->components[k].amount; costtyp = sp->components[k].cost; if (itemanz > 0) { - size = sizeof(buf) - 1; - bufp = buf; + sbs_init(&sbs, buf, sizeof(buf)); if (sp->sptyp & SPELLLEVEL) { - bytes = - snprintf(bufp, size, " %d %s", itemanz, LOC(lang, resourcename(rtype, - itemanz != 1))); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, str_itoa(itemanz)); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(lang, resourcename(rtype, itemanz != 1))); + if (costtyp == SPC_LEVEL || costtyp == SPC_LINEAR) { - bytes = snprintf(bufp, size, " * %s", LOC(lang, "nr_level")); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " * "); + sbs_strcat(&sbs, LOC(lang, "nr_level")); } } else { - bytes = snprintf(bufp, size, "%d %s", itemanz, LOC(lang, resourcename(rtype, itemanz != 1))); - if (wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } + sbs_strcat(&sbs, str_itoa(itemanz)); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(lang, resourcename(rtype, itemanz != 1))); } - *bufp = 0; paragraph(out, buf, 2, 2, '-'); } } - size = sizeof(buf) - 1; - bufp = buf; - bytes = (int)str_strlcpy(buf, LOC(lang, "nr_spell_modifiers"), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_substr(&sbs, 0, 0); + sbs_strcat(&sbs, LOC(lang, "nr_spell_modifiers")); - startp = bufp; - bytes = (int)write_spell_modifier(sp, FARCASTING, LOC(lang, "smod_far"), startp != bufp, bufp, size); - if (bytes && wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); + cont = false; + cont = write_spell_modifier(sp, FARCASTING, LOC(lang, "smod_far"), cont, &sbs); + cont = write_spell_modifier(sp, OCEANCASTABLE, LOC(lang, "smod_sea"), cont, &sbs); + cont = write_spell_modifier(sp, ONSHIPCAST, LOC(lang, "smod_ship"), cont, &sbs); + cont = write_spell_modifier(sp, NOTFAMILIARCAST, LOC(lang, "smod_nofamiliar"), cont, &sbs); + if (!cont) { + write_spell_modifier(sp, NOTFAMILIARCAST, LOC(lang, "smod_none"), cont, &sbs); } - bytes = (int)write_spell_modifier(sp, OCEANCASTABLE, LOC(lang, "smod_sea"), startp != bufp, bufp, size); - if (bytes && wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } - bytes = (int)write_spell_modifier(sp, ONSHIPCAST, LOC(lang, "smod_ship"), startp != bufp, bufp, size); - if (bytes && wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } - bytes = (int)write_spell_modifier(sp, NOTFAMILIARCAST, LOC(lang, "smod_nofamiliar"), startp != bufp, bufp, size); - if (bytes && wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } - if (startp == bufp) { - bytes = (int)write_spell_modifier(sp, NOTFAMILIARCAST, LOC(lang, "smod_none"), startp != bufp, bufp, size); - if (bytes && wrptr(&bufp, &size, bytes) != 0) { - WARN_STATIC_BUFFER(); - } - } - *bufp = 0; paragraph(out, buf, 0, 0, 0); paragraph(out, LOC(lang, "nr_spell_syntax"), 0, 0, 0); From 0590fc09abc1b787d04704c560abb51302cb8d4e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 28 Nov 2018 17:56:49 +0100 Subject: [PATCH 3/7] add a str_adopt constructor for sbstring. --- src/util/strings.c | 12 +++++++++++- src/util/strings.h | 1 + src/util/strings.test.c | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/util/strings.c b/src/util/strings.c index 2f766fc5d..0ee0bd79c 100644 --- a/src/util/strings.c +++ b/src/util/strings.c @@ -263,13 +263,23 @@ char *str_strdup(const char *s) { void sbs_init(struct sbstring *sbs, char *buffer, size_t size) { assert(sbs); - assert(size>0); + assert(size > 0); sbs->begin = buffer; sbs->size = size; sbs->end = buffer; buffer[0] = '\0'; } +void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size) +{ + size_t len = strlen(buffer); + assert(sbs); + assert(size > len); + sbs->begin = buffer; + sbs->size = size; + sbs->end = buffer + len; +} + void sbs_strncat(struct sbstring *sbs, const char *str, size_t size) { size_t len; diff --git a/src/util/strings.h b/src/util/strings.h index 0b22f1b4a..1e98a0968 100644 --- a/src/util/strings.h +++ b/src/util/strings.h @@ -50,6 +50,7 @@ extern "C" { } sbstring; void sbs_init(struct sbstring *sbs, char *buffer, size_t size); + void sbs_adopt(struct sbstring *sbs, char *buffer, size_t size); 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); diff --git a/src/util/strings.test.c b/src/util/strings.test.c index 1c1ea8d72..5b8db0473 100644 --- a/src/util/strings.test.c +++ b/src/util/strings.test.c @@ -157,6 +157,10 @@ static void test_sbstring(CuTest * tc) CuAssertStrEquals(tc, "12345678901234", sbs.begin); sbs_strncat(&sbs, "567890", 6); CuAssertStrEquals(tc, "123456789012345", sbs.begin); + + sbs_adopt(&sbs, buffer + 2, sizeof(buffer) - 2); + CuAssertStrEquals(tc, "3456789012345", sbs.begin); + CuAssertIntEquals(tc, 13, sbs_length(&sbs)); } static void test_sbs_strcat(CuTest * tc) From 2fe5c0e0f7c97caf4d72b8d746f4803f0a4fad0e Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 28 Nov 2018 18:30:50 +0100 Subject: [PATCH 4/7] split region reporting into more and smaller functions. --- src/report.c | 278 ++++++++++++++++++++++++--------------------------- 1 file changed, 130 insertions(+), 148 deletions(-) diff --git a/src/report.c b/src/report.c index b0e3891fa..4bac3d2d7 100644 --- a/src/report.c +++ b/src/report.c @@ -750,9 +750,9 @@ static void prices(struct stream *out, const region * r, const faction * f) const luxury_type *sale = NULL; struct demand *dmd; message *m; - int bytes, n = 0; - char buf[4096], *bufp = buf; - size_t size = sizeof(buf) - 1; + int n = 0; + char buf[4096]; + sbstring sbs; if (r->land == NULL || r->land->demands == NULL) return; @@ -766,64 +766,40 @@ static void prices(struct stream *out, const region * r, const faction * f) m = msg_message("nr_market_sale", "product price", sale->itype->rtype, sale->price); - - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + nr_render(m, f->locale, buf, sizeof(buf), f); msg_release(m); + sbs_adopt(&sbs, buf, sizeof(buf)); if (n > 0) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_intro"), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcpy(&sbs, " "); + sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_intro")); + sbs_strcpy(&sbs, " "); for (dmd = r->land->demands; dmd; dmd = dmd->next) { if (dmd->value > 0) { + size_t size = sizeof(buf) - sbs_length(&sbs); + /* FIXME: this is a bad hack, cause by how msg_message works. */ m = msg_message("nr_market_price", "product price", dmd->type->itype->rtype, dmd->value * dmd->type->price); - bytes = (int)nr_render(m, f->locale, bufp, size, f); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + size = nr_render(m, f->locale, sbs.end, size, f); + sbs.end += size; msg_release(m); n--; if (n == 0) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_end"), - size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_end")); } else if (n == 1) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_final"), - size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcpy(&sbs, " "); + sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_final")); + sbs_strcpy(&sbs, " "); } else { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_trade_next"), - size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_next")); + sbs_strcpy(&sbs, " "); } } } } - /* Schreibe Paragraphen */ - *bufp = 0; paragraph(out, buf, 0, 0, 0); } @@ -849,74 +825,27 @@ bool see_border(const connection * b, const faction * f, const region * r) #define MAX_EDGES 16 -void report_region(struct stream *out, const region * r, faction * f) +struct edge { + char *name; + bool transparent; + bool block; + bool exist[MAXDIRECTIONS]; + direction_t lastd; +}; + +static void report_region_description(struct stream *out, const region * r, faction * f, const bool see[]) { int n; bool dh; - direction_t d; int trees; int saplings; attrib *a; const char *tname; - struct edge { - char *name; - bool transparent; - bool block; - bool exist[MAXDIRECTIONS]; - direction_t lastd; - } edges[MAX_EDGES]; - int ne = 0; - bool see[MAXDIRECTIONS]; - char buf[8192]; + char buf[4096]; char *bufp = buf; size_t size = sizeof(buf); int bytes; - assert(out); - assert(f); - assert(r); - - memset(edges, 0, sizeof(edges)); - for (d = 0; d != MAXDIRECTIONS; d++) { - /* Nachbarregionen, die gesehen werden, ermitteln */ - region *r2 = rconnect(r, d); - connection *b; - see[d] = true; - if (!r2) - continue; - for (b = get_borders(r, r2); b;) { - int e; - struct edge *match = NULL; - bool transparent = b->type->transparent(b, f); - const char *name = border_name(b, r, f, GF_DETAILED | GF_ARTICLE); - - if (!transparent) { - see[d] = false; - } - if (!see_border(b, f, r)) { - b = b->next; - continue; - } - for (e = 0; e!=ne; ++e) { - struct edge *edg = edges + e; - if (edg->transparent == transparent && 0 == strcmp(name, edg->name)) { - match = edg; - break; - } - } - if (match == NULL) { - match = edges + ne; - match->name = str_strdup(name); - match->transparent = transparent; - ++ne; - assert(ne < MAX_EDGES); - } - match->lastd = d; - match->exist[d] = true; - b = b->next; - } - } - bytes = (int)f_regionid(r, f, bufp, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); @@ -981,7 +910,7 @@ void report_region(struct stream *out, const region * r, faction * f) for (n = 0; n < numresults; ++n) { if (result[n].number >= 0 && result[n].level >= 0) { - const char * name = resourcename(result[n].rtype, result[n].number!=1); + const char * name = resourcename(result[n].rtype, result[n].number != 1); bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, LOC(f->locale, name), result[n].level); if (wrptr(&bufp, &size, bytes) != 0) @@ -1089,7 +1018,7 @@ void report_region(struct stream *out, const region * r, faction * f) WARN_STATIC_BUFFER(); } else { - int nrd = 0; + int d, nrd = 0; /* Nachbarregionen, die gesehen werden, ermitteln */ for (d = 0; d != MAXDIRECTIONS; d++) { @@ -1167,6 +1096,41 @@ void report_region(struct stream *out, const region * r, faction * f) } *bufp = 0; paragraph(out, buf, 0, 0, 0); +} + +/** + * Zeige Wirkungen permanenter Sprüche. + */ +static void report_region_curses(struct stream *out, const region * r, faction * f, struct edge edges[], int nedges) { + nr_curses(out, 0, f, TYP_REGION, r); + + if (nedges > 0) { + int e; + newline(out); + for (e = 0; e != nedges; ++e) { + message *msg; + int d; + + for (d = 0; d != MAXDIRECTIONS; ++d) { + if (edges[e].exist[d]) { + char buf[512]; + msg = msg_message(edges[e].transparent ? "nr_border_transparent" : "nr_border_opaque", + "object dir", edges[e].name, d); + nr_render(msg, f->locale, buf, sizeof(buf), f); + msg_release(msg); + paragraph(out, buf, 0, 0, 0); + } + } + free(edges[e].name); + } + } +} + +static void report_region_schemes(struct stream *out, const region * r, faction * f) { + char buf[4096]; + char *bufp = buf; + size_t size = sizeof(buf); + int bytes; if (r->seen.mode >= seen_unit && is_astral(r) && !is_cursed(r->attribs, &ct_astralblock)) { @@ -1204,29 +1168,62 @@ void report_region(struct stream *out, const region * r, faction * f) paragraph(out, buf, 0, 0, 0); } } +} - /* Wirkungen permanenter Sprüche */ - nr_curses(out, 0, f, TYP_REGION, r); - n = 0; +void report_region(struct stream *out, const region * r, faction * f) +{ + int d, ne = 0; + bool see[MAXDIRECTIONS]; + struct edge edges[MAX_EDGES]; - if (ne > 0) { - int e; - newline(out); - for (e = 0; e != ne; ++e) { - message *msg; + assert(out); + assert(f); + assert(r); - for (d = 0; d != MAXDIRECTIONS; ++d) { - if (edges[e].exist[d]) { - msg = msg_message(edges[e].transparent ? "nr_border_transparent" : "nr_border_opaque", - "object dir", edges[e].name, d); - nr_render(msg, f->locale, buf, sizeof(buf), f); - msg_release(msg); - paragraph(out, buf, 0, 0, 0); + memset(edges, 0, sizeof(edges)); + for (d = 0; d != MAXDIRECTIONS; d++) { + /* Nachbarregionen, die gesehen werden, ermitteln */ + region *r2 = rconnect(r, d); + connection *b; + see[d] = true; + if (!r2) + continue; + for (b = get_borders(r, r2); b;) { + int e; + struct edge *match = NULL; + bool transparent = b->type->transparent(b, f); + const char *name = border_name(b, r, f, GF_DETAILED | GF_ARTICLE); + + if (!transparent) { + see[d] = false; + } + if (!see_border(b, f, r)) { + b = b->next; + continue; + } + for (e = 0; e != ne; ++e) { + struct edge *edg = edges + e; + if (edg->transparent == transparent && 0 == strcmp(name, edg->name)) { + match = edg; + break; } } - free(edges[e].name); + if (match == NULL) { + match = edges + ne; + match->name = str_strdup(name); + match->transparent = transparent; + ++ne; + assert(ne < MAX_EDGES); + } + match->lastd = d; + match->exist[d] = true; + b = b->next; } } + + report_region_description(out, r, f, see); + report_region_schemes(out, r, f); + report_region_curses(out, r, f, edges, ne); } static void statistics(struct stream *out, const region * r, const faction * f) @@ -2024,13 +2021,12 @@ report_plaintext(const char *filename, report_context * ctx, attrib *a; message *m; unsigned char op; - int maxh, bytes, ix = WANT_OPTION(O_STATISTICS); + int maxh, ix = WANT_OPTION(O_STATISTICS); int wants_stats = (f->options & ix); FILE *F = fopen(filename, "w"); stream strm = { 0 }, *out = &strm; - char buf[8192]; - char *bufp; - size_t size; + char buf[1024]; + sbstring sbs; if (F == NULL) { perror(filename); @@ -2134,26 +2130,19 @@ report_plaintext(const char *filename, report_context * ctx, centre(out, buf, true); } - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(buf, size, "%s:", LOC(f->locale, "nr_options")); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_init(&sbs, buf, sizeof(buf)); + sbs_strcat(&sbs, LOC(f->locale, "nr_options")); + sbs_strcat(&sbs, ":"); for (op = 0; op != MAXOPTIONS; op++) { if (f->options & WANT_OPTION(op) && options[op]) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, options[op]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, options[op])); - flag++; + ++flag; } } if (flag > 0) { newline(out); - *bufp = 0; centre(out, buf, true); } @@ -2192,28 +2181,21 @@ report_plaintext(const char *filename, report_context * ctx, centre(out, buf, true); newline(out); - bufp = buf; - size = sizeof(buf) - 1; - bytes = snprintf(bufp, size, "%s: ", LOC(f->locale, "nr_herbsrequired")); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_init(&sbs, buf, sizeof(buf)); + sbs_strcat(&sbs, LOC(f->locale, "nr_herbsrequired")); + sbs_strcat(&sbs, ":"); if (itype->construction) { requirement *rm = itype->construction->materials; while (rm->number) { - bytes = - (int)str_strlcpy(bufp, LOC(f->locale, resourcename(rm->rtype, 0)), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, LOC(f->locale, resourcename(rm->rtype, 0))); ++rm; - if (rm->number) - bytes = (int)str_strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + if (rm->number) { + sbs_strcat(&sbs, ", "); + } } assert(!rm->rtype); } - *bufp = 0; centre(out, buf, true); newline(out); description = mkname("describe", pname); From d3713be6bdffaef16cd921ec404966304e85f541 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 28 Nov 2018 20:18:22 +0100 Subject: [PATCH 5/7] more sbstring use in reports. fix paragraph lines with very long words, indirectly test through region report. --- src/report.c | 253 ++++++++++++++++++---------------------------- src/report.test.c | 39 ++++++- 2 files changed, 135 insertions(+), 157 deletions(-) diff --git a/src/report.c b/src/report.c index 4bac3d2d7..f1a3bbaa4 100644 --- a/src/report.c +++ b/src/report.c @@ -745,6 +745,13 @@ static void rp_battles(struct stream *out, faction * f) } } +static void append_message(sbstring *sbp, message *m, const faction * f) { + /* FIXME: this is a bad hack, cause by how msg_message works. */ + size_t size = sbp->size - sbs_length(sbp); + size = nr_render(m, f->locale, sbp->end, size, f); + sbp->end += size; +} + static void prices(struct stream *out, const region * r, const faction * f) { const luxury_type *sale = NULL; @@ -777,12 +784,9 @@ static void prices(struct stream *out, const region * r, const faction * f) for (dmd = r->land->demands; dmd; dmd = dmd->next) { if (dmd->value > 0) { - size_t size = sizeof(buf) - sbs_length(&sbs); - /* FIXME: this is a bad hack, cause by how msg_message works. */ m = msg_message("nr_market_price", "product price", dmd->type->itype->rtype, dmd->value * dmd->type->price); - size = nr_render(m, f->locale, sbs.end, size, f); - sbs.end += size; + append_message(&sbs, m, f); msg_release(m); n--; if (n == 0) { @@ -833,6 +837,15 @@ struct edge { direction_t lastd; }; +static void report_region_resource(sbstring *sbp, const struct locale *lang, const struct resource_type *rtype, int n) { + if (n != 0) { + sbs_strcat(sbp, ", "); + sbs_strcat(sbp, str_itoa(n)); + sbs_strcat(sbp, " "); + sbs_strcat(sbp, LOC(lang, resourcename(rtype, (n != 1) ? GR_PLURAL : 0))); + } +} + static void report_region_description(struct stream *out, const region * r, faction * f, const bool see[]) { int n; @@ -842,66 +855,61 @@ static void report_region_description(struct stream *out, const region * r, fact attrib *a; const char *tname; char buf[4096]; - char *bufp = buf; - size_t size = sizeof(buf); - int bytes; + sbstring sbs; - bytes = (int)f_regionid(r, f, bufp, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + f_regionid(r, f, buf, sizeof(buf)); + sbs_adopt(&sbs, buf, sizeof(buf)); if (r->seen.mode == seen_travel) { - bytes = snprintf(bufp, size, " (%s)", LOC(f->locale, "see_travel")); + sbs_strcat(&sbs, " ("); + sbs_strcat(&sbs, LOC(f->locale, "see_travel")); + sbs_strcat(&sbs, ")"); } else if (r->seen.mode == seen_neighbour) { - bytes = snprintf(bufp, size, " (%s)", LOC(f->locale, "see_neighbour")); + sbs_strcat(&sbs, " ("); + sbs_strcat(&sbs, LOC(f->locale, "see_neighbour")); + sbs_strcat(&sbs, ")"); } else if (r->seen.mode == seen_lighthouse) { - bytes = snprintf(bufp, size, " (%s)", LOC(f->locale, "see_lighthouse")); + sbs_strcat(&sbs, " ("); + sbs_strcat(&sbs, LOC(f->locale, "see_lighthouse")); + sbs_strcat(&sbs, ")"); } - else { - bytes = 0; - } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); /* Terrain */ - bytes = (int)str_strlcpy(bufp, ", ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - tname = terrain_name(r); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, tname), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, ", "); + sbs_strcat(&sbs, LOC(f->locale, tname)); + pump_paragraph(&sbs, out, REPORTWIDTH, false); /* Trees */ trees = rtrees(r, 2); saplings = rtrees(r, 1); if (max_production(r)) { if (trees > 0 || saplings > 0) { - bytes = snprintf(bufp, size, ", %d/%d ", trees, saplings); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, ", "); + sbs_strcat(&sbs, str_itoa(trees)); + sbs_strcat(&sbs, "/"); + sbs_strcat(&sbs, str_itoa(saplings)); + sbs_strcat(&sbs, " "); if (fval(r, RF_MALLORN)) { if (trees == 1) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mallorntree"), size); + sbs_strcat(&sbs, LOC(f->locale, "nr_mallorntree")); } else { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mallorntree_p"), size); + sbs_strcat(&sbs, LOC(f->locale, "nr_mallorntree_p")); } } else if (trees == 1) { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "tree"), size); + sbs_strcat(&sbs, LOC(f->locale, "tree")); } else { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "tree_p"), size); + sbs_strcat(&sbs, LOC(f->locale, "tree_p")); } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } } + pump_paragraph(&sbs, out, REPORTWIDTH, false); /* iron & stone */ if (r->seen.mode >= seen_unit) { @@ -911,111 +919,71 @@ static void report_region_description(struct stream *out, const region * r, fact for (n = 0; n < numresults; ++n) { if (result[n].number >= 0 && result[n].level >= 0) { const char * name = resourcename(result[n].rtype, result[n].number != 1); - bytes = snprintf(bufp, size, ", %d %s/%d", result[n].number, - LOC(f->locale, name), result[n].level); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, ", "); + sbs_strcat(&sbs, str_itoa(result[n].number)); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, name)); + sbs_strcat(&sbs, "/"); + sbs_strcat(&sbs, str_itoa(result[n].level)); } } } /* peasants & silver */ - if (rpeasants(r)) { - int p = rpeasants(r); - bytes = snprintf(bufp, size, ", %d", p); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + n = rpeasants(r); + if (n) { + sbs_strcat(&sbs, ", "); + sbs_strcat(&sbs, str_itoa(n)); if (r->land->ownership) { const char *str = LOC(f->locale, mkname("morale", itoa10(region_get_morale(r)))); - bytes = snprintf(bufp, size, " %s", str); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, str); } - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = - (int)str_strlcpy(bufp, LOC(f->locale, p == 1 ? "peasant" : "peasant_p"), - size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, n != 1 ? "peasant_p" : "peasant")); + if (is_mourning(r, turn + 1)) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_mourning"), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, "nr_mourning")); } } - if (rmoney(r) && r->seen.mode >= seen_travel) { - bytes = snprintf(bufp, size, ", %d ", rmoney(r)); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = - (int)str_strlcpy(bufp, LOC(f->locale, resourcename(get_resourcetype(R_SILVER), - rmoney(r) != 1)), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + if (r->seen.mode >= seen_travel) { + report_region_resource(&sbs, f->locale, get_resourcetype(R_SILVER), rmoney(r)); } /* Pferde */ - - if (rhorses(r)) { - bytes = snprintf(bufp, size, ", %d ", rhorses(r)); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = - (int)str_strlcpy(bufp, LOC(f->locale, resourcename(get_resourcetype(R_HORSE), - (rhorses(r) > 1) ? GR_PLURAL : 0)), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - } - bytes = (int)str_strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + report_region_resource(&sbs, f->locale, get_resourcetype(R_HORSE), rhorses(r)); + sbs_strcat(&sbs, "."); if (r->land && r->land->display && r->land->display[0]) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, r->land->display, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, r->land->display); n = r->land->display[strlen(r->land->display) - 1]; if (n != '!' && n != '?' && n != '.') { - bytes = (int)str_strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, "."); } } if (rule_region_owners()) { const faction *owner = region_get_owner(r); - message *msg; if (owner != NULL) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + message *msg; + + sbs_strcat(&sbs, " "); msg = msg_message("nr_region_owner", "faction", owner); - bytes = (int)nr_render(msg, f->locale, bufp, size, f); + append_message(&sbs, msg, f); msg_release(msg); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); } } - a = a_find(r->attribs, &at_overrideroads); + pump_paragraph(&sbs, out, REPORTWIDTH, false); + a = a_find(r->attribs, &at_overrideroads); if (a) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, (char *)a->data.v, size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, (const char *)a->data.v); } else { int d, nrd = 0; @@ -1025,8 +993,8 @@ static void report_region_description(struct stream *out, const region * r, fact if (see[d] && rconnect(r, d)) nrd++; } - /* list directions */ + /* list directions */ dh = false; for (d = 0; d != MAXDIRECTIONS; d++) { if (see[d]) { @@ -1035,36 +1003,25 @@ static void report_region_description(struct stream *out, const region * r, fact continue; nrd--; if (dh) { - char regname[4096]; + char regname[128], trail[256]; if (nrd == 0) { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_nb_final"), size); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, "nr_nb_final")); } else { - bytes = (int)str_strlcpy(bufp, LOC(f->locale, "nr_nb_next"), size); + sbs_strcat(&sbs, LOC(f->locale, "nr_nb_next")); } - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, directions[d]), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, LOC(f->locale, directions[d])); + sbs_strcat(&sbs, " "); f_regionid(r2, f, regname, sizeof(regname)); - bytes = snprintf(bufp, size, trailinto(r2, f->locale), regname); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + snprintf(trail, sizeof(trail), trailinto(r2, f->locale), regname); + sbs_strcat(&sbs, trail); } else { - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - MSG(("nr_vicinitystart", "dir region", d, r2), bufp, size, f->locale, - f); - bufp += strlen(bufp); + message * msg = msg_message("nr_vicinitystart", "dir region", d, r2); + sbs_strcat(&sbs, " "); + append_message(&sbs, msg, f); + msg_release(msg); dh = true; } } @@ -1073,29 +1030,15 @@ static void report_region_description(struct stream *out, const region * r, fact for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; a = a->next) { spec_direction *spd = (spec_direction *)(a->data.v); - bytes = (int)str_strlcpy(bufp, " ", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, spd->desc), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, " (\"", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, LOC(f->locale, spd->keyword), size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, "\")", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); - bytes = (int)str_strlcpy(bufp, ".", size); - if (wrptr(&bufp, &size, bytes) != 0) - WARN_STATIC_BUFFER(); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, spd->desc)); + sbs_strcat(&sbs, " (\""); + sbs_strcat(&sbs, LOC(f->locale, spd->keyword)); + sbs_strcat(&sbs, "\")."); dh = 1; } } - *bufp = 0; - paragraph(out, buf, 0, 0, 0); + pump_paragraph(&sbs, out, REPORTWIDTH, true); } /** @@ -1521,15 +1464,19 @@ void pump_paragraph(sbstring *sbp, stream *out, size_t maxlen, bool isfinal) return; } else if (next > begin + maxlen) { - ptrdiff_t len = pos - begin; + ptrdiff_t len; + if (pos == begin) { + /* there was no space before the break, line will be too long */ + pos = next; + } + len = pos - begin; swrite(begin, 1, len, out); newline(out); while (*pos && IS_UTF8_SPACE(pos)) { ++pos; - ++len; } - sbs_substr(sbp, len, SIZE_MAX); + sbs_substr(sbp, pos - begin, SIZE_MAX); break; } pos = next; diff --git a/src/report.test.c b/src/report.test.c index 84f2f070d..601df8eb0 100644 --- a/src/report.test.c +++ b/src/report.test.c @@ -106,12 +106,30 @@ static void test_report_region(CuTest *tc) { rsettrees(r, 0, 1); rsettrees(r, 1, 2); rsettrees(r, 2, 3); - region_setname(r, "Hodor"); f = test_create_faction(NULL); f->locale = lang; u = test_create_unit(f, r); set_level(u, SK_QUARRYING, 1); + region_setname(r, "1234567890123456789012345678901234567890"); + r->seen.mode = seen_travel; + report_region(&out, r, f); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = '\0'; + CuAssertStrEquals(tc, "1234567890123456789012345678901234567890 (0,0) (durchgereist), Ebene, 3/2\nBlumen, 5 Bauern, 2 Silber, 7 Pferde.\n", buf); + + out.api->rewind(out.handle); + region_setname(r, "12345678901234567890123456789012345678901234567890123456789012345678901234567890"); + r->seen.mode = seen_travel; + report_region(&out, r, f); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = '\0'; + CuAssertStrEquals(tc, "12345678901234567890123456789012345678901234567890123456789012345678901234567890\n(0,0) (durchgereist), Ebene, 3/2 Blumen, 5 Bauern, 2 Silber, 7 Pferde.\n", buf); + + out.api->rewind(out.handle); + region_setname(r, "Hodor"); r->seen.mode = seen_travel; report_region(&out, r, f); out.api->rewind(out.handle); @@ -119,27 +137,40 @@ static void test_report_region(CuTest *tc) { buf[len] = '\0'; CuAssertStrEquals(tc, "Hodor (0,0) (durchgereist), Ebene, 3/2 Blumen, 5 Bauern, 2 Silber, 7 Pferde.\n", buf); - r->seen.mode = seen_unit; out.api->rewind(out.handle); + r->seen.mode = seen_unit; report_region(&out, r, f); out.api->rewind(out.handle); len = out.api->read(out.handle, buf, sizeof(buf)); buf[len] = '\0'; CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 135 Steine/1, 5 Bauern, 2 Silber, 7 Pferde.\n", buf); + out.api->rewind(out.handle); r->resources->amount = 1; r->land->peasants = 1; r->land->horses = 1; r->land->money = 1; - r->seen.mode = seen_unit; - out.api->rewind(out.handle); report_region(&out, r, f); out.api->rewind(out.handle); len = out.api->read(out.handle, buf, sizeof(buf)); buf[len] = '\0'; CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 3/2 Blumen, 1 Stein/1, 1 Bauer, 1 Silber, 1 Pferd.\n", buf); + r->land->peasants = 0; + r->land->horses = 0; + r->land->money = 0; + rsettrees(r, 0, 0); + rsettrees(r, 1, 0); + rsettrees(r, 2, 0); + + out.api->rewind(out.handle); + report_region(&out, r, f); + out.api->rewind(out.handle); + len = out.api->read(out.handle, buf, sizeof(buf)); + buf[len] = '\0'; + CuAssertStrEquals(tc, "Hodor (0,0), Ebene, 1 Stein/1.\n", buf); + mstream_done(&out); test_teardown(); } From 88792e1d097e1c9be2ec13c8aa1e58738c4b0dd6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Wed, 28 Nov 2018 20:57:17 +0100 Subject: [PATCH 6/7] fix display of luxury prices, period at end of description. --- src/report.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/report.c b/src/report.c index f1a3bbaa4..eadf40354 100644 --- a/src/report.c +++ b/src/report.c @@ -778,9 +778,9 @@ static void prices(struct stream *out, const region * r, const faction * f) sbs_adopt(&sbs, buf, sizeof(buf)); if (n > 0) { - sbs_strcpy(&sbs, " "); - sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_intro")); - sbs_strcpy(&sbs, " "); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, "nr_trade_intro")); + sbs_strcat(&sbs, " "); for (dmd = r->land->demands; dmd; dmd = dmd->next) { if (dmd->value > 0) { @@ -790,16 +790,16 @@ static void prices(struct stream *out, const region * r, const faction * f) msg_release(m); n--; if (n == 0) { - sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_end")); + sbs_strcat(&sbs, LOC(f->locale, "nr_trade_end")); } else if (n == 1) { - sbs_strcpy(&sbs, " "); - sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_final")); - sbs_strcpy(&sbs, " "); + sbs_strcat(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, "nr_trade_final")); + sbs_strcat(&sbs, " "); } else { - sbs_strcpy(&sbs, LOC(f->locale, "nr_trade_next")); - sbs_strcpy(&sbs, " "); + sbs_strcat(&sbs, LOC(f->locale, "nr_trade_next")); + sbs_strcat(&sbs, " "); } } } @@ -984,6 +984,7 @@ static void report_region_description(struct stream *out, const region * r, fact if (a) { sbs_strcat(&sbs, " "); sbs_strcat(&sbs, (const char *)a->data.v); + sbs_strcat(&sbs, "."); } else { int d, nrd = 0; @@ -1026,6 +1027,7 @@ static void report_region_description(struct stream *out, const region * r, fact } } } + sbs_strcat(&sbs, "."); /* Spezielle Richtungen */ for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; a = a->next) { @@ -1042,9 +1044,9 @@ static void report_region_description(struct stream *out, const region * r, fact } /** - * Zeige Wirkungen permanenter Sprüche. + * Show roads and certain magic effects. */ -static void report_region_curses(struct stream *out, const region * r, faction * f, struct edge edges[], int nedges) { +static void report_region_edges(struct stream *out, const region * r, faction * f, struct edge edges[], int nedges) { nr_curses(out, 0, f, TYP_REGION, r); if (nedges > 0) { @@ -1166,7 +1168,7 @@ void report_region(struct stream *out, const region * r, faction * f) report_region_description(out, r, f, see); report_region_schemes(out, r, f); - report_region_curses(out, r, f, edges, ne); + report_region_edges(out, r, f, edges, ne); } static void statistics(struct stream *out, const region * r, const faction * f) @@ -1577,7 +1579,7 @@ void report_allies(struct stream *out, size_t maxlen, const struct faction * f, show.num_listed = 0; show.maxlen = maxlen; sbs_init(&show.sbs, buf, sizeof(buf)); - sbs_strcpy(&show.sbs, prefix); + sbs_strcat(&show.sbs, prefix); allies_walk(allies, show_allies_cb, &show); } From 3c703653aa701806f8f96fb08c2697a34a35521a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 29 Nov 2018 06:46:08 +0100 Subject: [PATCH 7/7] oops. broke test again with another case of too many periods. --- src/report.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/report.c b/src/report.c index eadf40354..8486d9e09 100644 --- a/src/report.c +++ b/src/report.c @@ -1027,7 +1027,9 @@ static void report_region_description(struct stream *out, const region * r, fact } } } - sbs_strcat(&sbs, "."); + if (dh) { + sbs_strcat(&sbs, "."); + } /* Spezielle Richtungen */ for (a = a_find(r->attribs, &at_direction); a && a->type == &at_direction; a = a->next) {