diff --git a/src/creport.c b/src/creport.c index fefd7934e..1ce5c2a30 100644 --- a/src/creport.c +++ b/src/creport.c @@ -68,6 +68,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include /* libc includes */ #include @@ -176,7 +177,7 @@ static void print_items(FILE * F, item * items, const struct locale *lang) } static void -cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t typ) +cr_output_curses(stream *out, const faction * viewer, const void *obj, objtype_t typ) { bool header = false; attrib *a = NULL; @@ -258,10 +259,10 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty char buf[BUFFERSIZE]; if (!header) { header = 1; - fputs("EFFECTS\n", F); + stream_printf(out, "EFFECTS\n"); } nr_render(msg, viewer->locale, buf, sizeof(buf), viewer); - fprintf(F, "\"%s\"\n", buf); + stream_printf(out, "\"%s\"\n", buf); msg_release(msg); } a = a->next; @@ -272,9 +273,9 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty const char *key = resourcename(data->type->itype->rtype, 0); if (!header) { header = 1; - fputs("EFFECTS\n", F); + stream_printf(out, "EFFECTS\n"); } - fprintf(F, "\"%d %s\"\n", data->value, translate(key, + stream_printf(out, "\"%d %s\"\n", data->value, translate(key, LOC(default_locale, key))); } a = a->next; @@ -285,6 +286,13 @@ cr_output_curses(FILE * F, const faction * viewer, const void *obj, objtype_t ty } } +static void cr_output_curses_compat(FILE *F, const faction * viewer, const void *obj, objtype_t typ) { + // TODO: eliminate this function + stream strm; + fstream_init(&strm, F); + cr_output_curses(&strm, viewer, obj, typ); +} + static int cr_unit(variant var, char *buffer, const void *userdata) { unit *u = (unit *)var.v; @@ -636,7 +644,7 @@ faction * f) fprintf(F, "%d;Partei\n", fno); if (b->besieged) fprintf(F, "%d;Belagerer\n", b->besieged); - cr_output_curses(F, f, b, TYP_BUILDING); + cr_output_curses_compat(F, f, b, TYP_BUILDING); } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ @@ -682,30 +690,22 @@ const faction * f, const region * r) if (w != NODIRECTION) fprintf(F, "%d;Kueste\n", w); - cr_output_curses(F, f, sh, TYP_SHIP); + cr_output_curses_compat(F, f, sh, TYP_SHIP); } -static void -fwriteorder(FILE * F, const struct order *ord, const struct locale *lang, -bool escape) -{ +static int stream_order(stream *out, const struct order *ord) { + const char *str; char ebuf[1025]; char obuf[1024]; - const char *str = obuf; - fputc('"', F); write_order(ord, obuf, sizeof(obuf)); - if (escape) { - str = escape_string(obuf, ebuf, sizeof(ebuf)); - if (str == ebuf) { - ebuf[1024] = 0; - } + str = escape_string(obuf, ebuf, sizeof(ebuf)); + if (str == ebuf) { + ebuf[1024] = 0; } - if (str[0]) - fputs(str, F); - fputc('"', F); + return stream_printf(out, "\"%s\"\n", str); } -static void cr_output_spells(FILE * F, const unit * u, int maxlevel) +static void cr_output_spells(stream *out, const unit * u, int maxlevel) { spellbook * book = unit_get_spellbook(u); @@ -720,17 +720,20 @@ static void cr_output_spells(FILE * F, const unit * u, int maxlevel) spell * sp = sbe->sp; const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale)); if (!header) { - fputs("SPRUECHE\n", F); + stream_printf(out, "SPRUECHE\n"); header = 1; } - fprintf(F, "\"%s\"\n", name); + stream_printf(out, "\"%s\"\n", name); } } } } -/* prints all that belongs to a unit */ -static void cr_output_unit(FILE * F, const region * r, const faction * f, /* observers faction */ +/** prints all that belongs to a unit +* @param f observers faction +* @param u unit to report +*/ +void cr_output_unit(stream *out, const region * r, const faction * f, const unit * u, int mode) { /* Race attributes are always plural and item attributes always @@ -751,7 +754,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, const char *prefix; assert(u && u->number); - if (u != NULL || fval(u_race(u), RCF_INVISIBLE)) + if (fval(u_race(u), RCF_INVISIBLE)) return; if (!init) { @@ -763,11 +766,11 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, itemcloak = cu && curse_active(cu); } - fprintf(F, "EINHEIT %d\n", u->no); - fprintf(F, "\"%s\";Name\n", unit_getname(u)); + stream_printf(out, "EINHEIT %d\n", u->no); + stream_printf(out, "\"%s\";Name\n", unit_getname(u)); str = u_description(u, f->locale); if (str) { - fprintf(F, "\"%s\";Beschr\n", str); + stream_printf(out, "\"%s\";Beschr\n", str); } /* print faction information */ sf = visible_faction(f, u); @@ -784,41 +787,41 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, a = a_find(u->attribs, &at_group); if (a != NULL) { const group *g = (const group *)a->data.v; - fprintf(F, "%d;gruppe\n", g->gid); + stream_printf(out, "%d;gruppe\n", g->gid); } - fprintf(F, "%d;Partei\n", u->faction->no); + stream_printf(out, "%d;Partei\n", u->faction->no); if (sf != u->faction) - fprintf(F, "%d;Verkleidung\n", sf->no); + stream_printf(out, "%d;Verkleidung\n", sf->no); if (fval(u, UFL_ANON_FACTION)) - fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + stream_printf(out, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); if (otherfaction) { if (otherfaction != u->faction) { - fprintf(F, "%d;Anderepartei\n", otherfaction->no); + stream_printf(out, "%d;Anderepartei\n", otherfaction->no); } } mage = get_familiar_mage(u); if (mage) { - fprintf(F, "%u;familiarmage\n", mage->no); + stream_printf(out, "%u;familiarmage\n", mage->no); } } else { if (fval(u, UFL_ANON_FACTION)) { /* faction info is hidden */ - fprintf(F, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); + stream_printf(out, "%d;Parteitarnung\n", i2b(fval(u, UFL_ANON_FACTION))); } else { const attrib *a_otherfaction = a_find(u->attribs, &at_otherfaction); const faction *otherfaction = a_otherfaction ? get_otherfaction(a_otherfaction) : NULL; /* other unit. show visible faction, not u->faction */ - fprintf(F, "%d;Partei\n", sf->no); + stream_printf(out, "%d;Partei\n", sf->no); if (sf == f) { - fprintf(F, "1;Verraeter\n"); + stream_printf(out, "1;Verraeter\n"); } if (a_otherfaction) { if (otherfaction != u->faction) { if (alliedunit(u, f, HELP_FSTEALTH)) { - fprintf(F, "%d;Anderepartei\n", otherfaction->no); + stream_printf(out, "%d;Anderepartei\n", otherfaction->no); } } } @@ -826,53 +829,53 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, } if (prefix) { prefix = mkname("prefix", prefix); - fprintf(F, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, + stream_printf(out, "\"%s\";typprefix\n", translate(prefix, LOC(f->locale, prefix))); } if (u->faction != f && a_fshidden && a_fshidden->data.ca[0] == 1 && effskill(u, SK_STEALTH) >= 6) { - fprintf(F, "-1;Anzahl\n"); + stream_printf(out, "-1;Anzahl\n"); } else { - fprintf(F, "%d;Anzahl\n", u->number); + stream_printf(out, "%d;Anzahl\n", u->number); } pzTmp = get_racename(u->attribs); if (pzTmp) { - fprintf(F, "\"%s\";Typ\n", pzTmp); + stream_printf(out, "\"%s\";Typ\n", pzTmp); if (u->faction == f && fval(u_race(u), RCF_SHAPESHIFTANY)) { const char *zRace = rc_name_s(u_race(u), NAME_PLURAL); - fprintf(F, "\"%s\";wahrerTyp\n", + stream_printf(out, "\"%s\";wahrerTyp\n", translate(zRace, LOC(f->locale, zRace))); } } else { const race *irace = u_irace(u); const char *zRace = rc_name_s(irace, NAME_PLURAL); - fprintf(F, "\"%s\";Typ\n", + stream_printf(out, "\"%s\";Typ\n", translate(zRace, LOC(f->locale, zRace))); if (u->faction == f && irace != u_race(u)) { assert(skill_enabled(SK_STEALTH) || !"we're resetting this on load, so.. ircase should never be used"); zRace = rc_name_s(u_race(u), NAME_PLURAL); - fprintf(F, "\"%s\";wahrerTyp\n", + stream_printf(out, "\"%s\";wahrerTyp\n", translate(zRace, LOC(f->locale, zRace))); } } if (u->building) { assert(u->building->region); - fprintf(F, "%d;Burg\n", u->building->no); + stream_printf(out, "%d;Burg\n", u->building->no); } if (u->ship) { assert(u->ship->region); - fprintf(F, "%d;Schiff\n", u->ship->no); + stream_printf(out, "%d;Schiff\n", u->ship->no); } if (is_guard(u, GUARD_ALL) != 0) { - fprintf(F, "%d;bewacht\n", 1); + stream_printf(out, "%d;bewacht\n", 1); } if ((b = usiege(u)) != NULL) { - fprintf(F, "%d;belagert\n", b->no); + stream_printf(out, "%d;belagert\n", b->no); } /* additional information for own units */ if (u->faction == f || omniscient(f)) { @@ -884,48 +887,47 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, i = ualias(u); if (i > 0) - fprintf(F, "%d;temp\n", i); + stream_printf(out, "%d;temp\n", i); else if (i < 0) - fprintf(F, "%d;alias\n", -i); + stream_printf(out, "%d;alias\n", -i); i = get_money(u); - fprintf(F, "%d;Kampfstatus\n", u->status); - fprintf(F, "%d;weight\n", weight(u)); + stream_printf(out, "%d;Kampfstatus\n", u->status); + stream_printf(out, "%d;weight\n", weight(u)); if (fval(u, UFL_NOAID)) { - fputs("1;unaided\n", F); + stream_printf(out, "1;unaided\n"); } if (fval(u, UFL_STEALTH)) { i = u_geteffstealth(u); if (i >= 0) { - fprintf(F, "%d;Tarnung\n", i); + stream_printf(out, "%d;Tarnung\n", i); } } xc = uprivate(u); if (xc) { - fprintf(F, "\"%s\";privat\n", xc); + stream_printf(out, "\"%s\";privat\n", xc); } c = hp_status(u); if (c && *c && (u->faction == f || omniscient(f))) { - fprintf(F, "\"%s\";hp\n", translate(c, + stream_printf(out, "\"%s\";hp\n", translate(c, LOC(u->faction->locale, c))); } if (fval(u, UFL_HERO)) { - fputs("1;hero\n", F); + stream_printf(out, "1;hero\n"); } if (fval(u, UFL_HUNGER) && (u->faction == f)) { - fputs("1;hunger\n", F); + stream_printf(out, "1;hunger\n"); } if (is_mage(u)) { - fprintf(F, "%d;Aura\n", get_spellpoints(u)); - fprintf(F, "%d;Auramax\n", max_spellpoints(u->region, u)); + stream_printf(out, "%d;Aura\n", get_spellpoints(u)); + stream_printf(out, "%d;Auramax\n", max_spellpoints(u->region, u)); } /* default commands */ - fprintf(F, "COMMANDS\n"); + stream_printf(out, "COMMANDS\n"); for (ord = u->old_orders; ord; ord = ord->next) { /* this new order will replace the old defaults */ if (is_persistent(ord)) { - fwriteorder(F, ord, f->locale, true); - fputc('\n', F); + stream_order(out, ord); } } for (ord = u->orders; ord; ord = ord->next) { @@ -933,8 +935,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, if (u->old_orders && is_repeated(kwd)) continue; /* unit has defaults */ if (is_persistent(ord)) { - fwriteorder(F, ord, f->locale, true); - fputc('\n', F); + stream_order(out, ord); } } @@ -946,9 +947,9 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, int esk = eff_skill(u, sk, r); if (!pr) { pr = 1; - fprintf(F, "TALENTE\n"); + stream_printf(out, "TALENTE\n"); } - fprintf(F, "%d %d;%s\n", u->number * level_days(sv->level), esk, + stream_printf(out, "%d %d;%s\n", u->number * level_days(sv->level), esk, translate(mkname("skill", skillnames[sk]), skillname(sk, f->locale))); } @@ -958,7 +959,7 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, mage = get_mage(u); if (mage) { int i, maxlevel = effskill(u, SK_MAGIC); - cr_output_spells(F, u, maxlevel); + cr_output_spells(out, u, maxlevel); for (i = 0; i != MAXCOMBATSPELLS; ++i) { const spell *sp = mage->combatspells[i].sp; @@ -966,9 +967,9 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, const char *name = translate(mkname("spell", sp->sname), spell_name(sp, f->locale)); - fprintf(F, "KAMPFZAUBER %d\n", i); - fprintf(F, "\"%s\";name\n", name); - fprintf(F, "%d;level\n", mage->combatspells[i].level); + stream_printf(out, "KAMPFZAUBER %d\n", i); + stream_printf(out, "\"%s\";name\n", name); + stream_printf(out, "%d;level\n", mage->combatspells[i].level); } } } @@ -1001,12 +1002,21 @@ static void cr_output_unit(FILE * F, const region * r, const faction * f, continue; if (!pr) { pr = 1; - fputs("GEGENSTAENDE\n", F); + stream_printf(out, "GEGENSTAENDE\n"); } - fprintf(F, "%d;%s\n", in, translate(ic, LOC(f->locale, ic))); + stream_printf(out, "%d;%s\n", in, translate(ic, LOC(f->locale, ic))); } - cr_output_curses(F, f, u, TYP_UNIT); + cr_output_curses(out, f, u, TYP_UNIT); +} + +static void cr_output_unit_compat(FILE * F, const region * r, const faction * f, + const unit * u, int mode) +{ + // TODO: eliminate this function + stream strm; + fstream_init(&strm, F); + cr_output_unit(&strm, r, f, u, mode); } /* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ @@ -1377,7 +1387,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) if (r->land) { print_items(F, r->land->items, f->locale); } - cr_output_curses(F, f, r, TYP_REGION); + cr_output_curses_compat(F, f, r, TYP_REGION); cr_borders(ctx->seen, r, f, sr->mode, F); if (sr->mode == see_unit && is_astral(r) && !is_cursed(r->attribs, C_ASTRALBLOCK, 0)) { @@ -1469,7 +1479,7 @@ static void cr_output_region(FILE * F, report_context * ctx, seen_region * sr) if (u->building || u->ship || (stealthmod > INT_MIN && cansee(f, r, u, stealthmod))) { - cr_output_unit(F, r, f, u, sr->mode); + cr_output_unit_compat(F, r, f, u, sr->mode); } } } diff --git a/src/creport.h b/src/creport.h index 678f09ada..c2c2ff385 100644 --- a/src/creport.h +++ b/src/creport.h @@ -15,10 +15,16 @@ extern "C" { #endif + struct stream; + struct region; + struct faction; + struct unit; + void creport_cleanup(void); void register_cr(void); int crwritemap(const char *filename); + void cr_output_unit(struct stream *out, const struct region * r, const struct faction * f, const struct unit * u, int mode); #ifdef __cplusplus } diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 85e558fd2..310a407bd 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1708,6 +1708,16 @@ int unit_getcapacity(const unit * u) return walkingcapacity(u); } +void renumber_unit(unit *u, int no) { + uunhash(u); + if (!ualias(u)) { + attrib *a = a_add(&u->attribs, a_new(&at_alias)); + a->data.i = -u->no; + } + u->no = no; + uhash(u); +} + void unit_addorder(unit * u, order * ord) { order **ordp = &u->orders; diff --git a/src/kernel/unit.h b/src/kernel/unit.h index c84ccbdfe..631809bf9 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -127,6 +127,8 @@ extern "C" { int ualias(const struct unit *u); int weight(const struct unit *u); + void renumber_unit(struct unit *u, int no); + const struct race *u_irace(const struct unit *u); const struct race *u_race(const struct unit *u); void u_setrace(struct unit *u, const struct race *); diff --git a/src/laws.c b/src/laws.c index 3f68294fb..849a2597b 100755 --- a/src/laws.c +++ b/src/laws.c @@ -3022,13 +3022,7 @@ int renumber_cmd(unit * u, order * ord) break; } } - uunhash(u); - if (!ualias(u)) { - attrib *a = a_add(&u->attribs, a_new(&at_alias)); - a->data.i = -u->no; - } - u->no = i; - uhash(u); + renumber_unit(u, i); break; case P_SHIP: diff --git a/src/laws.h b/src/laws.h index 7eec612e3..987e3d2b0 100755 --- a/src/laws.h +++ b/src/laws.h @@ -56,15 +56,15 @@ extern "C" { extern int *age; - extern void new_units(void); - extern void defaultorders(void); - extern void quit(void); - extern void monthly_healing(void); - extern void renumber_factions(void); - extern void restack_units(void); - extern void update_long_order(struct unit *u); - extern void sinkships(struct region * r); - extern void do_enter(struct region *r, bool is_final_attempt); + void new_units(void); + void defaultorders(void); + void quit(void); + void monthly_healing(void); + void renumber_factions(void); + void restack_units(void); + void update_long_order(struct unit *u); + void sinkships(struct region * r); + void do_enter(struct region *r, bool is_final_attempt); extern int password_cmd(struct unit *u, struct order *ord); extern int banner_cmd(struct unit *u, struct order *ord); diff --git a/src/reports.c b/src/reports.c index 88b11e31d..cf9ac7342 100644 --- a/src/reports.c +++ b/src/reports.c @@ -52,6 +52,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include +#include #include /* libc includes */ @@ -2499,6 +2500,23 @@ static void log_orders(const struct message *msg) } } +int stream_printf(struct stream * out, const char *format, ...) { + va_list args; + int result; + char buffer[4096]; + size_t bytes = sizeof(buffer); + // TODO: should be in storage/stream.c (doesn't exist yet) + va_start(args, format); + result = vsnprintf(buffer, bytes, format, args); + if (result >= 0 && (size_t)result < bytes) { + bytes = (size_t)result; + // TODO: else = buffer too small + } + out->api->write(out->handle, buffer, bytes); + va_end(args); + return result; +} + void register_reports(void) { /* register datatypes for the different message objects */ diff --git a/src/reports.h b/src/reports.h index 93b3ab122..12cb198b0 100644 --- a/src/reports.h +++ b/src/reports.h @@ -153,6 +153,7 @@ extern "C" { void freestrlist(strlist * s); void split_paragraph(strlist ** SP, const char *s, unsigned int indent, unsigned int width, char mark); + int stream_printf(struct stream * out, const char *format, ...); #define GR_PLURAL 0x01 /* grammar: plural */ #define MAX_INVENTORY 128 /* maimum number of different items in an inventory */ diff --git a/src/reports.test.c b/src/reports.test.c index 9dd9f0913..89bca6e05 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -2,6 +2,7 @@ #include #include "reports.h" #include "report.h" +#include "creport.h" #include #include @@ -155,9 +156,32 @@ static void test_sparagraph(CuTest *tc) { CuAssertPtrEquals(tc, 0, sp->next->next->next); } +static void test_cr_unit(CuTest *tc) { + stream strm; + char line[1024]; + faction *f; + region *r; + unit *u; + + test_cleanup(); + f = test_create_faction(0); + r = test_create_region(0, 0, 0); + u = test_create_unit(f, r); + renumber_unit(u, 1234); + + mstream_init(&strm); + cr_output_unit(&strm, r, f, u, see_unit); + strm.api->rewind(strm.handle); + CuAssertIntEquals(tc, 0, strm.api->readln(strm.handle, line, sizeof(line))); + CuAssertStrEquals(tc, line, "EINHEIT 1234"); + mstream_done(&strm); + test_cleanup(); +} + CuSuite *get_reports_suite(void) { CuSuite *suite = CuSuiteNew(); + SUITE_ADD_TEST(suite, test_cr_unit); SUITE_ADD_TEST(suite, test_reorder_units); SUITE_ADD_TEST(suite, test_seen_faction); SUITE_ADD_TEST(suite, test_regionid); diff --git a/storage b/storage index 2bcd3b1e6..86b967441 160000 --- a/storage +++ b/storage @@ -1 +1 @@ -Subproject commit 2bcd3b1e64764321773672333bd133a61b35b840 +Subproject commit 86b96744157eb08c55998df4c12fa2e073005b49