OSDN Git Service

Merge pull request #2954 from backwardsEric/sprintf-refactor-dice_to_string
authorHabu <habu1010+github@gmail.com>
Mon, 19 Dec 2022 11:48:16 +0000 (20:48 +0900)
committerGitHub <noreply@github.com>
Mon, 19 Dec 2022 11:48:16 +0000 (20:48 +0900)
Refactor dice_to_string() to avoid sprintf().  Does part of the work …

21 files changed:
src/artifact/random-art-generator.cpp
src/birth/auto-roller.cpp
src/floor/floor-save.cpp
src/io/write-diary.cpp
src/load/load-util.cpp
src/load/load-util.h
src/lore/lore-util.cpp
src/lore/lore-util.h
src/main/angband-initializer.cpp
src/room/rooms-pit-nest.cpp
src/target/target-describer.cpp
src/term/screen-processor.cpp
src/term/screen-processor.h
src/view/display-lore.cpp
src/view/display-lore.h
src/view/display-player.cpp
src/view/display-util.cpp
src/view/display-util.h
src/view/status-first-page.cpp
src/wizard/items-spoiler.cpp
src/wizard/monster-info-spoiler.cpp

index 4a0bd4a..de4ff90 100644 (file)
@@ -383,40 +383,39 @@ static int decide_random_art_power_level(ItemEntity *o_ptr, const bool a_cursed,
     return 3;
 }
 
-static void name_unnatural_random_artifact(PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level, GAME_TEXT *new_name)
+static std::string name_unnatural_random_artifact(PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level)
 {
+    GAME_TEXT new_name[1024] = "";
+
     if (!a_scroll) {
         get_random_name(o_ptr, new_name, o_ptr->is_protector(), power_level);
-        return;
+        return new_name;
     }
 
-    GAME_TEXT dummy_name[MAX_NLEN] = "";
     concptr ask_msg = _("このアーティファクトを何と名付けますか?", "What do you want to call the artifact? ");
     object_aware(player_ptr, o_ptr);
     object_known(o_ptr);
     o_ptr->ident |= IDENT_FULL_KNOWN;
     o_ptr->art_name = quark_add("");
     (void)screen_object(player_ptr, o_ptr, 0L);
-    if (!get_string(ask_msg, dummy_name, sizeof dummy_name) || !dummy_name[0]) {
+    if (!get_string(ask_msg, new_name, sizeof new_name) || !new_name[0]) {
         if (one_in_(2)) {
-            get_table_sindarin_aux(dummy_name);
+            get_table_sindarin_aux(new_name);
         } else {
-            get_table_name_aux(dummy_name);
+            get_table_name_aux(new_name);
         }
     }
 
-    sprintf(new_name, _("《%s》", "'%s'"), dummy_name);
     chg_virtue(player_ptr, V_INDIVIDUALISM, 2);
     chg_virtue(player_ptr, V_ENCHANT, 5);
+    return std::string(_("《", "'")).append(new_name).append(_("》", "'"));
 }
 
 static void generate_unnatural_random_artifact(
     PlayerType *player_ptr, ItemEntity *o_ptr, const bool a_scroll, const int power_level, const int max_powers, const int total_flags)
 {
-    GAME_TEXT new_name[1024];
-    strcpy(new_name, "");
-    name_unnatural_random_artifact(player_ptr, o_ptr, a_scroll, power_level, new_name);
-    o_ptr->art_name = quark_add(new_name);
+    auto new_name = name_unnatural_random_artifact(player_ptr, o_ptr, a_scroll, power_level);
+    o_ptr->art_name = quark_add(new_name.data());
     msg_format_wizard(player_ptr, CHEAT_OBJECT,
         _("パワー %d で 価値%ld のランダムアーティファクト生成 バイアスは「%s」", "Random artifact generated - Power:%d Value:%d Bias:%s."), max_powers,
         total_flags, artifact_bias_name[o_ptr->artifact_bias]);
index 45f519b..5ecbb13 100644 (file)
@@ -13,6 +13,7 @@
 #include "system/player-type-definition.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
+#include "term/z-form.h"
 #include "util/int-char-converter.h"
 
 /*! オートローラの能力値的要求水準 / Autoroll limit */
@@ -161,29 +162,32 @@ static void decide_initial_stat(PlayerType *player_ptr, int *cval)
 
 /*!
  * @brief オートローラの設定能力値行を作成する
- * @param cur カーソル文字列を入れるバッファ
  * @param cval 設定能力値配列
  * @param cs カーソル位置(能力値番号)
+ * @return カーソル文字列
  */
-static void cursor_of_adjusted_stat(char *cur, int *cval, int cs)
+static std::string cursor_of_adjusted_stat(const int *cval, int cs)
 {
-    char inp[80], maxv[80];
     auto j = rp_ptr->r_adj[cs] + cp_ptr->c_adj[cs] + ap_ptr->a_adj[cs];
     auto m = adjust_stat(17, j);
+    char maxv[20];
     if (m > 18) {
-        sprintf(maxv, "18/%02d", (m - 18));
+        strnfmt(maxv, sizeof(maxv), "18/%02d", (m - 18));
     } else {
-        sprintf(maxv, "%2d", m);
+        strnfmt(maxv, sizeof(maxv), "%2d", m);
     }
 
     m = adjust_stat(cval[cs], j);
+    char inp[20];
     if (m > 18) {
-        sprintf(inp, "18/%02d", (m - 18));
+        strnfmt(inp, sizeof(inp), "18/%02d", (m - 18));
     } else {
-        sprintf(inp, "%2d", m);
+        strnfmt(inp, sizeof(inp), "%2d", m);
     }
 
-    sprintf(cur, "%6s       %2d   %+3d  %+3d  %+3d  =  %6s  %6s", stat_names[cs], cval[cs], rp_ptr->r_adj[cs], cp_ptr->c_adj[cs], ap_ptr->a_adj[cs], inp, maxv);
+    char cur[60];
+    strnfmt(cur, sizeof(cur), "%6s       %2d   %+3d  %+3d  %+3d  =  %6s  %6s", stat_names[cs], cval[cs], rp_ptr->r_adj[cs], cp_ptr->c_adj[cs], ap_ptr->a_adj[cs], inp, maxv);
+    return cur;
 }
 
 /*!
@@ -192,14 +196,16 @@ static void cursor_of_adjusted_stat(char *cur, int *cval, int cs)
  */
 static void display_autoroller_chance(int *cval)
 {
-    char buf[320];
+    concptr buf;
+    char work[60];
     autoroll_chance = get_autoroller_prob(cval);
     if (autoroll_chance == -999) {
-        sprintf(buf, _("確率: 不可能(合計86超)       ", "Prob: Impossible(>86 tot stats)"));
+        buf = _("確率: 不可能(合計86超)       ", "Prob: Impossible(>86 tot stats)");
     } else if (autoroll_chance < 1) {
-        sprintf(buf, _("確率: 非常に容易(1/10000以上)", "Prob: Quite Easy(>1/10000)     "));
+        buf = _("確率: 非常に容易(1/10000以上)", "Prob: Quite Easy(>1/10000)     ");
     } else {
-        sprintf(buf, _("確率: 約 1/%8d00             ", "Prob: ~ 1/%8d00                "), autoroll_chance);
+        strnfmt(work, sizeof(work), _("確率: 約 1/%8d00             ", "Prob: ~ 1/%8d00                "), autoroll_chance);
+        buf = work;
     }
     put_str(buf, 23, 25);
 }
@@ -218,15 +224,13 @@ bool get_stat_limits(PlayerType *player_ptr)
     int cval[A_MAX]{};
     decide_initial_stat(player_ptr, cval);
 
-    char buf[320];
-    char cur[160];
     for (int i = 0; i < A_MAX; i++) {
-        cursor_of_adjusted_stat(buf, cval, i);
-        put_str(buf, 14 + i, 10);
+        put_str(cursor_of_adjusted_stat(cval, i).data(), 14 + i, 10);
     }
 
     display_autoroller_chance(cval);
 
+    std::string cur;
     int cs = 0;
     int os = A_MAX;
     while (true) {
@@ -236,14 +240,14 @@ bool get_stat_limits(PlayerType *player_ptr)
             } else if (os == A_MAX) {
                 c_put_str(TERM_WHITE, _("決定する", "Accept"), 21, 35);
             } else if (os < A_MAX) {
-                c_put_str(TERM_WHITE, cur, 14 + os, 10);
+                c_put_str(TERM_WHITE, cur.data(), 14 + os, 10);
             }
 
             if (cs == A_MAX) {
                 c_put_str(TERM_YELLOW, _("決定する", "Accept"), 21, 35);
             } else {
-                cursor_of_adjusted_stat(cur, cval, cs);
-                c_put_str(TERM_YELLOW, cur, 14 + cs, 10);
+                cur = cursor_of_adjusted_stat(cval, cs);
+                c_put_str(TERM_YELLOW, cur.data(), 14 + cs, 10);
             }
 
             os = cs;
@@ -367,7 +371,6 @@ bool get_chara_limits(PlayerType *player_ptr, chara_limit_type *chara_limit_ptr)
 {
 #define MAXITEMS 8
 
-    char buf[80], cur[80];
     concptr itemname[] = { _("年齢", "age"), _("身長(インチ)", "height"), _("体重(ポンド)", "weight"), _("社会的地位", "social class") };
 
     clear_from(10);
@@ -442,14 +445,16 @@ bool get_chara_limits(PlayerType *player_ptr, chara_limit_type *chara_limit_ptr)
     }
 
     for (int i = 0; i < 4; i++) {
-        sprintf(buf, "%-12s (%3d - %3d)", itemname[i], mval[i * 2], mval[i * 2 + 1]);
+        char buf[40];
+        strnfmt(buf, sizeof(buf), "%-12s (%3d - %3d)", itemname[i], mval[i * 2], mval[i * 2 + 1]);
         put_str(buf, 14 + i, 20);
         for (int j = 0; j < 2; j++) {
-            sprintf(buf, "     %3d", cval[i * 2 + j]);
+            strnfmt(buf, sizeof(buf), "     %3d", cval[i * 2 + j]);
             put_str(buf, 14 + i, 45 + 8 * j);
         }
     }
 
+    char cur[40] = "";
     int cs = 0;
     int os = MAXITEMS;
     while (true) {
@@ -464,7 +469,7 @@ bool get_chara_limits(PlayerType *player_ptr, chara_limit_type *chara_limit_ptr)
             if (cs == MAXITEMS) {
                 c_put_str(TERM_YELLOW, accept, 19, 35);
             } else {
-                sprintf(cur, "     %3d", cval[cs]);
+                strnfmt(cur, sizeof(cur), "     %3d", cval[cs]);
                 c_put_str(TERM_YELLOW, cur, 14 + cs / 2, 45 + 8 * (cs % 2));
             }
 
index 04b550e..5b138fa 100644 (file)
 #include "system/monster-entity.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "term/z-form.h"
 #include "util/angband-files.h"
 #include "view/display-messages.h"
 
+static std::string get_saved_floor_name(int level)
+{
+    char ext[32];
+    strnfmt(ext, sizeof(ext), ".F%02d", level);
+    return std::string(savefile).append(ext);
+}
+
 static void check_saved_tmp_files(const int fd, bool *force)
 {
     if (fd >= 0) {
@@ -54,18 +62,17 @@ static void check_saved_tmp_files(const int fd, bool *force)
  */
 void init_saved_floors(PlayerType *player_ptr, bool force)
 {
-    char floor_savefile[sizeof(savefile) + 32];
     int fd = -1;
     BIT_FLAGS mode = 0644;
     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
         saved_floor_type *sf_ptr = &saved_floors[i];
-        sprintf(floor_savefile, "%s.F%02d", savefile, i);
+        std::string floor_savefile = get_saved_floor_name(i);
         safe_setuid_grab(player_ptr);
-        fd = fd_make(floor_savefile, mode);
+        fd = fd_make(floor_savefile.data(), mode);
         safe_setuid_drop();
         check_saved_tmp_files(fd, &force);
         safe_setuid_grab(player_ptr);
-        (void)fd_kill(floor_savefile);
+        (void)fd_kill(floor_savefile.data());
         safe_setuid_drop();
         sf_ptr->floor_id = 0;
     }
@@ -84,16 +91,14 @@ void init_saved_floors(PlayerType *player_ptr, bool force)
  */
 void clear_saved_floor_files(PlayerType *player_ptr)
 {
-    char floor_savefile[sizeof(savefile) + 32];
     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
         saved_floor_type *sf_ptr = &saved_floors[i];
         if ((sf_ptr->floor_id == 0) || (sf_ptr->floor_id == player_ptr->floor_id)) {
             continue;
         }
 
-        sprintf(floor_savefile, "%s.F%02d", savefile, i);
         safe_setuid_grab(player_ptr);
-        (void)fd_kill(floor_savefile);
+        (void)fd_kill(get_saved_floor_name(i).data());
         safe_setuid_drop();
     }
 }
@@ -126,7 +131,6 @@ saved_floor_type *get_sf_ptr(FLOOR_IDX floor_id)
  */
 void kill_saved_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
 {
-    char floor_savefile[sizeof(savefile) + 32];
     if (!sf_ptr || (sf_ptr->floor_id == 0)) {
         return;
     }
@@ -137,9 +141,8 @@ void kill_saved_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
         return;
     }
 
-    sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
     safe_setuid_grab(player_ptr);
-    (void)fd_kill(floor_savefile);
+    (void)fd_kill(get_saved_floor_name((int)sf_ptr->savefile_id).data());
     safe_setuid_drop();
     sf_ptr->floor_id = 0;
 }
index 7df61a0..b47f5a4 100644 (file)
@@ -15,6 +15,7 @@
 #include "system/floor-type-definition.h"
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
+#include "term/z-form.h"
 #include "util/angband-files.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-messages.h"
@@ -54,10 +55,10 @@ concptr get_ordinal_number_suffix(int num)
  */
 static bool open_diary_file(FILE **fff, bool *disable_diary)
 {
-    GAME_TEXT file_name[MAX_NLEN];
-    sprintf(file_name, _("playrecord-%s.txt", "playrec-%s.txt"), savefile_base);
+    std::string file_name = _("playrecord-", "playrec-");
+    file_name.append(savefile_base).append(".txt");
     char buf[1024];
-    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, file_name);
+    path_build(buf, sizeof(buf), ANGBAND_DIR_USER, file_name.data());
     *fff = angband_fopen(buf, "a");
     if (*fff) {
         return true;
@@ -72,32 +73,31 @@ static bool open_diary_file(FILE **fff, bool *disable_diary)
 /*!
  * @brief フロア情報を日記に追加する
  * @param player_ptr プレイヤーへの参照ポインタ
- * @return クエストID
+ * @return クエストIDとレベルノートのペア
  */
-static QuestId write_floor(PlayerType *player_ptr, concptr *note_level, char *note_level_buf)
+static std::pair<QuestId, std::string> write_floor(PlayerType *player_ptr)
 {
     auto *floor_ptr = player_ptr->current_floor_ptr;
     auto q_idx = quest_number(player_ptr, floor_ptr->dun_level);
     if (!write_level) {
-        return q_idx;
+        return make_pair(q_idx, std::string());
     }
 
     if (floor_ptr->inside_arena) {
-        *note_level = _("アリーナ:", "Arena:");
+        return make_pair(q_idx, std::string(_("アリーナ:", "Arena:")));
     } else if (!floor_ptr->dun_level) {
-        *note_level = _("地上:", "Surface:");
+        return make_pair(q_idx, std::string(_("地上:", "Surface:")));
     } else if (inside_quest(q_idx) && quest_type::is_fixed(q_idx) && !((q_idx == QuestId::OBERON) || (q_idx == QuestId::SERPENT))) {
-        *note_level = _("クエスト:", "Quest:");
+        return make_pair(q_idx, std::string(_("クエスト:", "Quest:")));
     } else {
+        char desc[40];
 #ifdef JP
-        sprintf(note_level_buf, "%d階(%s):", (int)floor_ptr->dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
+        strnfmt(desc, sizeof(desc), "%d階(%s):", (int)floor_ptr->dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
 #else
-        sprintf(note_level_buf, "%s L%d:", dungeons_info[player_ptr->dungeon_idx].name.data(), (int)floor_ptr->dun_level);
+        strnfmt(desc, sizeof(desc), "%s L%d:", dungeons_info[player_ptr->dungeon_idx].name.data(), (int)floor_ptr->dun_level);
 #endif
-        *note_level = note_level_buf;
+        return make_pair(q_idx, std::string(desc));
     }
-
-    return q_idx;
 }
 
 /*!
@@ -186,9 +186,7 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
     parse_fixed_map(player_ptr, QUEST_DEFINITION_LIST, 0, 0, 0, 0);
     player_ptr->current_floor_ptr->quest_number = old_quest;
 
-    concptr note_level = "";
-    char note_level_buf[40];
-    write_floor(player_ptr, &note_level, note_level_buf);
+    const auto [q_idx, note_level] = write_floor(player_ptr);
 
     FILE *fff = nullptr;
     if (!open_diary_file(&fff, &disable_diary)) {
@@ -203,7 +201,7 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
             break;
         }
 
-        fprintf(fff, _(" %2d:%02d %20s クエスト「%s」を達成した。\n", " %2d:%02d %20s completed quest '%s'.\n"), hour, min, note_level, q_ref.name);
+        fprintf(fff, _(" %2d:%02d %20s クエスト「%s」を達成した。\n", " %2d:%02d %20s completed quest '%s'.\n"), hour, min, note_level.data(), q_ref.name);
         break;
     }
     case DIARY_FIX_QUEST_F: {
@@ -211,19 +209,15 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
             break;
         }
 
-        fprintf(fff, _(" %2d:%02d %20s クエスト「%s」から命からがら逃げ帰った。\n", " %2d:%02d %20s ran away from quest '%s'.\n"), hour, min, note_level, q_ref.name);
+        fprintf(fff, _(" %2d:%02d %20s クエスト「%s」から命からがら逃げ帰った。\n", " %2d:%02d %20s ran away from quest '%s'.\n"), hour, min, note_level.data(), q_ref.name);
         break;
     }
     case DIARY_RAND_QUEST_C: {
-        GAME_TEXT name[MAX_NLEN];
-        strcpy(name, monraces_info[q_ref.r_idx].name.data());
-        fprintf(fff, _(" %2d:%02d %20s ランダムクエスト(%s)を達成した。\n", " %2d:%02d %20s completed random quest '%s'\n"), hour, min, note_level, name);
+        fprintf(fff, _(" %2d:%02d %20s ランダムクエスト(%s)を達成した。\n", " %2d:%02d %20s completed random quest '%s'\n"), hour, min, note_level.data(), monraces_info[q_ref.r_idx].name.data());
         break;
     }
     case DIARY_RAND_QUEST_F: {
-        GAME_TEXT name[MAX_NLEN];
-        strcpy(name, monraces_info[q_ref.r_idx].name.data());
-        fprintf(fff, _(" %2d:%02d %20s ランダムクエスト(%s)から逃げ出した。\n", " %2d:%02d %20s ran away from quest '%s'.\n"), hour, min, note_level, name);
+        fprintf(fff, _(" %2d:%02d %20s ランダムクエスト(%s)から逃げ出した。\n", " %2d:%02d %20s ran away from quest '%s'.\n"), hour, min, note_level.data(), monraces_info[q_ref.r_idx].name.data());
         break;
     }
     case DIARY_TO_QUEST: {
@@ -232,7 +226,7 @@ int exe_write_diary_quest(PlayerType *player_ptr, int type, QuestId num)
         }
 
         fprintf(fff, _(" %2d:%02d %20s クエスト「%s」へと突入した。\n", " %2d:%02d %20s entered the quest '%s'.\n"),
-            hour, min, note_level, q_ref.name);
+            hour, min, note_level.data(), q_ref.name);
         break;
     }
     default:
@@ -271,9 +265,7 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
         return -1;
     }
 
-    concptr note_level = "";
-    char note_level_buf[40];
-    auto q_idx = write_floor(player_ptr, &note_level, note_level_buf);
+    const auto [q_idx, note_level] = write_floor(player_ptr);
 
     bool do_level = true;
     switch (type) {
@@ -292,31 +284,31 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
             fprintf(fff, "%s\n", note);
             do_level = false;
         } else {
-            fprintf(fff, " %2d:%02d %20s %s\n", hour, min, note_level, note);
+            fprintf(fff, " %2d:%02d %20s %s\n", hour, min, note_level.data(), note);
         }
 
         break;
     }
     case DIARY_ART: {
-        fprintf(fff, _(" %2d:%02d %20s %sを発見した。\n", " %2d:%02d %20s discovered %s.\n"), hour, min, note_level, note);
+        fprintf(fff, _(" %2d:%02d %20s %sを発見した。\n", " %2d:%02d %20s discovered %s.\n"), hour, min, note_level.data(), note);
         break;
     }
     case DIARY_ART_SCROLL: {
-        fprintf(fff, _(" %2d:%02d %20s 巻物によって%sを生成した。\n", " %2d:%02d %20s created %s by scroll.\n"), hour, min, note_level, note);
+        fprintf(fff, _(" %2d:%02d %20s 巻物によって%sを生成した。\n", " %2d:%02d %20s created %s by scroll.\n"), hour, min, note_level.data(), note);
         break;
     }
     case DIARY_UNIQUE: {
-        fprintf(fff, _(" %2d:%02d %20s %sを倒した。\n", " %2d:%02d %20s defeated %s.\n"), hour, min, note_level, note);
+        fprintf(fff, _(" %2d:%02d %20s %sを倒した。\n", " %2d:%02d %20s defeated %s.\n"), hour, min, note_level.data(), note);
         break;
     }
     case DIARY_MAXDEAPTH: {
-        fprintf(fff, _(" %2d:%02d %20s %sの最深階%d階に到達した。\n", " %2d:%02d %20s reached level %d of %s for the first time.\n"), hour, min, note_level,
+        fprintf(fff, _(" %2d:%02d %20s %sの最深階%d階に到達した。\n", " %2d:%02d %20s reached level %d of %s for the first time.\n"), hour, min, note_level.data(),
             _(dungeons_info[player_ptr->dungeon_idx].name.data(), num),
             _(num, dungeons_info[player_ptr->dungeon_idx].name.data()));
         break;
     }
     case DIARY_TRUMP: {
-        fprintf(fff, _(" %2d:%02d %20s %s%sの最深階を%d階にセットした。\n", " %2d:%02d %20s reset recall level of %s to %d %s.\n"), hour, min, note_level, note,
+        fprintf(fff, _(" %2d:%02d %20s %s%sの最深階を%d階にセットした。\n", " %2d:%02d %20s reset recall level of %s to %d %s.\n"), hour, min, note_level.data(), note,
             _(dungeons_info[num].name.data(), (int)max_dlv[num]),
             _((int)max_dlv[num], dungeons_info[num].name.data()));
         break;
@@ -327,43 +319,43 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
                      : !(player_ptr->current_floor_ptr->dun_level + num)
                          ? _("地上", "the surface")
                          : format(_("%d階", "level %d"), player_ptr->current_floor_ptr->dun_level + num);
-        fprintf(fff, _(" %2d:%02d %20s %sへ%s。\n", " %2d:%02d %20s %s %s.\n"), hour, min, note_level, _(to, note), _(note, to));
+        fprintf(fff, _(" %2d:%02d %20s %sへ%s。\n", " %2d:%02d %20s %s %s.\n"), hour, min, note_level.data(), _(to, note), _(note, to));
         break;
     }
     case DIARY_RECALL: {
         if (!num) {
             fprintf(fff, _(" %2d:%02d %20s 帰還を使って%sの%d階へ下りた。\n", " %2d:%02d %20s recalled to dungeon level %d of %s.\n"),
-                hour, min, note_level, _(dungeons_info[player_ptr->dungeon_idx].name.data(), (int)max_dlv[player_ptr->dungeon_idx]),
+                hour, min, note_level.data(), _(dungeons_info[player_ptr->dungeon_idx].name.data(), (int)max_dlv[player_ptr->dungeon_idx]),
                 _((int)max_dlv[player_ptr->dungeon_idx], dungeons_info[player_ptr->dungeon_idx].name.data()));
         } else {
-            fprintf(fff, _(" %2d:%02d %20s 帰還を使って地上へと戻った。\n", " %2d:%02d %20s recalled from dungeon to surface.\n"), hour, min, note_level);
+            fprintf(fff, _(" %2d:%02d %20s 帰還を使って地上へと戻った。\n", " %2d:%02d %20s recalled from dungeon to surface.\n"), hour, min, note_level.data());
         }
 
         break;
     }
     case DIARY_TELEPORT_LEVEL: {
         fprintf(fff, _(" %2d:%02d %20s レベル・テレポートで脱出した。\n", " %2d:%02d %20s got out using teleport level.\n"),
-            hour, min, note_level);
+            hour, min, note_level.data());
         break;
     }
     case DIARY_BUY: {
-        fprintf(fff, _(" %2d:%02d %20s %sを購入した。\n", " %2d:%02d %20s bought %s.\n"), hour, min, note_level, note);
+        fprintf(fff, _(" %2d:%02d %20s %sを購入した。\n", " %2d:%02d %20s bought %s.\n"), hour, min, note_level.data(), note);
         break;
     }
     case DIARY_SELL: {
-        fprintf(fff, _(" %2d:%02d %20s %sを売却した。\n", " %2d:%02d %20s sold %s.\n"), hour, min, note_level, note);
+        fprintf(fff, _(" %2d:%02d %20s %sを売却した。\n", " %2d:%02d %20s sold %s.\n"), hour, min, note_level.data(), note);
         break;
     }
     case DIARY_ARENA: {
         if (num < 0) {
             int n = -num;
             fprintf(fff, _(" %2d:%02d %20s 闘技場の%d%s回戦で、%sの前に敗れ去った。\n", " %2d:%02d %20s beaten by %s in the %d%s fight.\n"),
-                hour, min, note_level, _(n, note), _("", n), _(note, get_ordinal_number_suffix(n)));
+                hour, min, note_level.data(), _(n, note), _("", n), _(note, get_ordinal_number_suffix(n)));
             break;
         }
 
         fprintf(fff, _(" %2d:%02d %20s 闘技場の%d%s回戦(%s)に勝利した。\n", " %2d:%02d %20s won the %d%s fight (%s).\n"),
-            hour, min, note_level, num, _("", get_ordinal_number_suffix(num)), note);
+            hour, min, note_level.data(), num, _("", get_ordinal_number_suffix(num)), note);
 
         if (num == MAX_ARENA_MONS) {
             fprintf(fff, _("                 闘技場のすべての敵に勝利し、チャンピオンとなった。\n",
@@ -374,7 +366,7 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
         break;
     }
     case DIARY_FOUND: {
-        fprintf(fff, _(" %2d:%02d %20s %sを識別した。\n", " %2d:%02d %20s identified %s.\n"), hour, min, note_level, note);
+        fprintf(fff, _(" %2d:%02d %20s %sを識別した。\n", " %2d:%02d %20s identified %s.\n"), hour, min, note_level.data(), note);
         break;
     }
     case DIARY_WIZ_TELE: {
@@ -382,7 +374,7 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
         concptr to = !floor_ref.is_in_dungeon()
                          ? _("地上", "the surface")
                          : format(_("%d階(%s)", "level %d of %s"), floor_ref.dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
-        fprintf(fff, _(" %2d:%02d %20s %sへとウィザード・テレポートで移動した。\n", " %2d:%02d %20s wizard-teleported to %s.\n"), hour, min, note_level, to);
+        fprintf(fff, _(" %2d:%02d %20s %sへとウィザード・テレポートで移動した。\n", " %2d:%02d %20s wizard-teleported to %s.\n"), hour, min, note_level.data(), to);
         break;
     }
     case DIARY_PAT_TELE: {
@@ -390,11 +382,11 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
         concptr to = !floor_ref.is_in_dungeon()
                          ? _("地上", "the surface")
                          : format(_("%d階(%s)", "level %d of %s"), floor_ref.dun_level, dungeons_info[player_ptr->dungeon_idx].name.data());
-        fprintf(fff, _(" %2d:%02d %20s %sへとパターンの力で移動した。\n", " %2d:%02d %20s used Pattern to teleport to %s.\n"), hour, min, note_level, to);
+        fprintf(fff, _(" %2d:%02d %20s %sへとパターンの力で移動した。\n", " %2d:%02d %20s used Pattern to teleport to %s.\n"), hour, min, note_level.data(), to);
         break;
     }
     case DIARY_LEVELUP: {
-        fprintf(fff, _(" %2d:%02d %20s レベルが%dに上がった。\n", " %2d:%02d %20s reached player level %d.\n"), hour, min, note_level, num);
+        fprintf(fff, _(" %2d:%02d %20s レベルが%dに上がった。\n", " %2d:%02d %20s reached player level %d.\n"), hour, min, note_level.data(), num);
         break;
     }
     case DIARY_GAMESTART: {
@@ -403,13 +395,13 @@ errr exe_write_diary(PlayerType *player_ptr, int type, int num, concptr note)
         if (num) {
             fprintf(fff, "%s %s", note, ctime(&ct));
         } else {
-            fprintf(fff, " %2d:%02d %20s %s %s", hour, min, note_level, note, ctime(&ct));
+            fprintf(fff, " %2d:%02d %20s %s %s", hour, min, note_level.data(), note, ctime(&ct));
         }
 
         break;
     }
     case DIARY_NAMED_PET: {
-        fprintf(fff, " %2d:%02d %20s ", hour, min, note_level);
+        fprintf(fff, " %2d:%02d %20s ", hour, min, note_level.data());
         write_diary_pet(fff, num, note);
         break;
     }
index a4f9020..8c12b2a 100644 (file)
@@ -23,7 +23,7 @@ byte kanji_code = 0;
  * @details
  * Avoid the top two lines, to avoid interference with "msg_print()".
  */
-void load_note(concptr msg)
+void load_note(std::string_view msg)
 {
     static TERM_LEN y = 2;
     prt(msg, y, 0);
index 5e464c8..ec3a46f 100644 (file)
@@ -5,6 +5,7 @@
 #include <algorithm>
 #include <bitset>
 #include <string>
+#include <string_view>
 
 extern FILE *loading_savefile;
 extern uint32_t loading_savefile_version;
@@ -13,7 +14,7 @@ extern uint32_t v_check;
 extern uint32_t x_check;
 extern byte kanji_code;
 
-void load_note(concptr msg);
+void load_note(std::string_view msg);
 byte sf_get(void);
 bool rd_bool();
 byte rd_byte();
index a18d963..d8ecb9c 100644 (file)
@@ -64,7 +64,7 @@ lore_type *initialize_lore_type(lore_type *lore_ptr, MonsterRaceId r_idx, monste
  * @brief モンスターの思い出メッセージをあらかじめ指定された関数ポインタに基づき出力する
  * @param str 出力文字列
  */
-void hooked_roff(concptr str)
+void hooked_roff(std::string_view str)
 {
     hook_c_roff(TERM_WHITE, str);
 }
index 40497dc..c7f0347 100644 (file)
@@ -13,6 +13,7 @@
 #include "system/angband.h"
 #include "util/flag-group.h"
 #include <string>
+#include <string_view>
 #include <unordered_map>
 
 enum class MonsterRaceId : int16_t;
@@ -80,11 +81,11 @@ enum monster_lore_mode {
     MONSTER_LORE_DEBUG
 };
 
-typedef void (*hook_c_roff_pf)(TERM_COLOR attr, concptr str);
+using hook_c_roff_pf = void (*)(TERM_COLOR attr, std::string_view str);
 extern hook_c_roff_pf hook_c_roff;
 
 lore_type *initialize_lore_type(lore_type *lore_ptr, MonsterRaceId r_idx, monster_lore_mode mode);
-void hooked_roff(concptr str);
+void hooked_roff(std::string_view str);
 
 enum WHO_WORD_TYPE { WHO = 0,
     WHOSE = 1,
index 7584a2d..e4f3c5b 100644 (file)
@@ -182,9 +182,9 @@ static void init_note_no_term(concptr str)
  * functions are "supposed" to work under any conditions.
  * </pre>
  */
-static void init_angband_aux(concptr why)
+static void init_angband_aux(const std::string &why)
 {
-    plog(why);
+    plog(why.data());
     plog(_("'lib'ディレクトリが存在しないか壊れているようです。", "The 'lib' directory is probably missing or broken."));
     plog(_("ひょっとするとアーカイブが正しく解凍されていないのかもしれません。", "The 'lib' directory is probably missing or broken."));
     plog(_("該当する'README'ファイルを読んで確認してみて下さい。", "See the 'README' file for more information."));
@@ -218,8 +218,9 @@ void init_angband(PlayerType *player_ptr, bool no_term)
     path_build(buf, sizeof(buf), ANGBAND_DIR_FILE, _("news_j.txt", "news.txt"));
     int fd = fd_open(buf, O_RDONLY);
     if (fd < 0) {
-        char why[sizeof(buf) + 128];
-        sprintf(why, _("'%s'ファイルにアクセスできません!", "Cannot access the '%s' file!"), buf);
+        std::string why = _("'", "Cannot access the '");
+        why.append(buf);
+        why.append(_("'ファイルにアクセスできません!", "' file!"));
         init_angband_aux(why);
     }
 
@@ -251,8 +252,9 @@ void init_angband(PlayerType *player_ptr, bool no_term)
         fd = fd_make(buf, file_permission);
         safe_setuid_drop();
         if (fd < 0) {
-            char why[sizeof(buf) + 128];
-            sprintf(why, _("'%s'ファイルを作成できません!", "Cannot create the '%s' file!"), buf);
+            std::string why = _("'", "Cannot create the '");
+            why.append(buf);
+            why.append(_("'ファイルを作成できません!", "' file!"));
             init_angband_aux(why);
         }
     }
@@ -341,9 +343,7 @@ void init_angband(PlayerType *player_ptr, bool no_term)
     init_note(_("[データの初期化中... (アロケーション)]", "[Initializing arrays... (alloc)]"));
     init_alloc();
     init_note(_("[ユーザー設定ファイルを初期化しています...]", "[Initializing user pref files...]"));
-    strcpy(buf, "pref.prf");
-    process_pref_file(player_ptr, buf);
-    sprintf(buf, "pref-%s.prf", ANGBAND_SYS);
-    process_pref_file(player_ptr, buf);
+    process_pref_file(player_ptr, "pref.prf");
+    process_pref_file(player_ptr, std::string("pref-").append(ANGBAND_SYS).append(".prf").data());
     init_note(_("[初期化終了]", "[Initialization complete]"));
 }
index 1509747..ed462e8 100644 (file)
@@ -67,50 +67,46 @@ static int pick_vault_type(FloorType *floor_ptr, std::vector<nest_pit_type> &l_p
  * Hack -- Get the string describing subtype of pit/nest
  * Determined in prepare function (some pit/nest only)
  */
-static concptr pit_subtype_string(int type, bool nest)
+static std::string pit_subtype_string(int type, bool nest)
 {
-    static char inner_buf[256] = "";
-    inner_buf[0] = '\0';
     if (nest) {
         switch (type) {
         case NEST_TYPE_CLONE:
-            sprintf(inner_buf, "(%s)", monraces_info[vault_aux_race].name.data());
-            break;
+            return std::string("(").append(monraces_info[vault_aux_race].name).append(1, ')');
         case NEST_TYPE_SYMBOL_GOOD:
         case NEST_TYPE_SYMBOL_EVIL:
-            sprintf(inner_buf, "(%c)", vault_aux_char);
-            break;
+            return std::string("(").append(1, vault_aux_char).append(1, ')');
         }
 
-        return inner_buf;
+        return std::string();
     }
 
     /* Pits */
     switch (type) {
     case PIT_TYPE_SYMBOL_GOOD:
     case PIT_TYPE_SYMBOL_EVIL:
-        sprintf(inner_buf, "(%c)", vault_aux_char);
+        return std::string("(").append(1, vault_aux_char).append(1, ')');
         break;
     case PIT_TYPE_DRAGON:
         if (vault_aux_dragon_mask4.has_all_of({ MonsterAbilityType::BR_ACID, MonsterAbilityType::BR_ELEC, MonsterAbilityType::BR_FIRE, MonsterAbilityType::BR_COLD, MonsterAbilityType::BR_POIS })) {
-            strcpy(inner_buf, _("(万色)", "(multi-hued)"));
+            return _("(万色)", "(multi-hued)");
         } else if (vault_aux_dragon_mask4.has(MonsterAbilityType::BR_ACID)) {
-            strcpy(inner_buf, _("(酸)", "(acid)"));
+            return _("(酸)", "(acid)");
         } else if (vault_aux_dragon_mask4.has(MonsterAbilityType::BR_ELEC)) {
-            strcpy(inner_buf, _("(稲妻)", "(lightning)"));
+            return _("(稲妻)", "(lightning)");
         } else if (vault_aux_dragon_mask4.has(MonsterAbilityType::BR_FIRE)) {
-            strcpy(inner_buf, _("(火炎)", "(fire)"));
+            return _("(火炎)", "(fire)");
         } else if (vault_aux_dragon_mask4.has(MonsterAbilityType::BR_COLD)) {
-            strcpy(inner_buf, _("(冷気)", "(frost)"));
+            return _("(冷気)", "(frost)");
         } else if (vault_aux_dragon_mask4.has(MonsterAbilityType::BR_POIS)) {
-            strcpy(inner_buf, _("(毒)", "(poison)"));
+            return _("(毒)", "(poison)");
         } else {
-            strcpy(inner_buf, _("(未定義)", "(undefined)"));
+            return _("(未定義)", "(undefined)");
         }
         break;
     }
 
-    return inner_buf;
+    return std::string();
 }
 
 /*
@@ -374,7 +370,7 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     msg_format_wizard(
-        player_ptr, CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, true));
+        player_ptr, CHEAT_DUNGEON, _("モンスター部屋(nest)(%s%s)を生成します。", "Monster nest (%s%s)"), n_ptr->name, pit_subtype_string(cur_nest_type, true).data());
 
     /* Place some monsters */
     for (y = yval - 2; y <= yval + 2; y++) {
@@ -628,7 +624,7 @@ bool build_type6(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     msg_format_wizard(
-        player_ptr, CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, false));
+        player_ptr, CHEAT_DUNGEON, _("モンスター部屋(pit)(%s%s)を生成します。", "Monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, false).data());
 
     /* Select the entries */
     for (i = 0; i < 8; i++) {
@@ -959,7 +955,7 @@ bool build_type13(PlayerType *player_ptr, dun_data_type *dd_ptr)
     }
 
     msg_format_wizard(
-        player_ptr, CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, false));
+        player_ptr, CHEAT_DUNGEON, _("%s%sの罠ピットが生成されました。", "Trapped monster pit (%s%s)"), n_ptr->name, pit_subtype_string(cur_pit_type, false).data());
 
     /* Select the entries */
     for (i = 0; i < 8; i++) {
index 67e1ae8..0f60941 100644 (file)
@@ -38,6 +38,7 @@
 #include "target/target-types.h"
 #include "term/screen-processor.h"
 #include "term/term-color-types.h"
+#include "term/z-form.h"
 #include "timed-effect/player-hallucination.h"
 #include "timed-effect/timed-effects.h"
 #include "util/bit-flags-calculator.h"
@@ -98,18 +99,16 @@ static eg_type *initialize_eg_type(PlayerType *player_ptr, eg_type *eg_ptr, POSI
 /*
  * Evaluate number of kill needed to gain level
  */
-static void evaluate_monster_exp(PlayerType *player_ptr, char *buf, MonsterEntity *m_ptr)
+static std::string evaluate_monster_exp(PlayerType *player_ptr, MonsterEntity *m_ptr)
 {
     MonsterRaceInfo *ap_r_ptr = &monraces_info[m_ptr->ap_r_idx];
     if ((player_ptr->lev >= PY_MAX_LEVEL) || PlayerRace(player_ptr).equals(PlayerRaceType::ANDROID)) {
-        sprintf(buf, "**");
-        return;
+        return "**";
     }
 
     if (!ap_r_ptr->r_tkills || m_ptr->mflag2.has(MonsterConstantFlagType::KAGE)) {
         if (!w_ptr->wizard) {
-            sprintf(buf, "??");
-            return;
+            return "??";
         }
     }
 
@@ -129,7 +128,7 @@ static void evaluate_monster_exp(PlayerType *player_ptr, char *buf, MonsterEntit
     s64b_div(&exp_adv, &exp_adv_frac, exp_mon, exp_mon_frac);
 
     auto num = std::min<uint>(999, exp_adv_frac);
-    sprintf(buf, "%03ld", (long int)num);
+    return format("%03ld", (long int)num);
 }
 
 static void describe_scan_result(PlayerType *player_ptr, eg_type *eg_ptr)
@@ -169,9 +168,9 @@ static ProcessResult describe_hallucinated_target(PlayerType *player_ptr, eg_typ
 
     concptr name = _("何か奇妙な物", "something strange");
 #ifdef JP
-    sprintf(eg_ptr->out_val, "%s%s%s%s [%s]", eg_ptr->s1, name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-    sprintf(eg_ptr->out_val, "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, name, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, name, eg_ptr->info);
 #endif
     prt(eg_ptr->out_val, 0, 0);
     move_cursor_relative(eg_ptr->y, eg_ptr->x);
@@ -199,7 +198,6 @@ static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
     GAME_TEXT m_name[MAX_NLEN];
     monster_desc(player_ptr, m_name, eg_ptr->m_ptr, MD_INDEF_VISIBLE);
     while (true) {
-        char acount[10];
         if (recall) {
             if (describe_grid_lore(player_ptr, eg_ptr)) {
                 return;
@@ -209,12 +207,12 @@ static void describe_grid_monster(PlayerType *player_ptr, eg_type *eg_ptr)
             continue;
         }
 
-        evaluate_monster_exp(player_ptr, acount, eg_ptr->m_ptr);
+        std::string acount = evaluate_monster_exp(player_ptr, eg_ptr->m_ptr);
 #ifdef JP
-        sprintf(eg_ptr->out_val, "[%s]%s%s(%s)%s%s [r思 %s%s]", acount, eg_ptr->s1, m_name, look_mon_desc(eg_ptr->m_ptr, 0x01), eg_ptr->s2, eg_ptr->s3,
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "[%s]%s%s(%s)%s%s [r思 %s%s]", acount.data(), eg_ptr->s1, m_name, look_mon_desc(eg_ptr->m_ptr, 0x01), eg_ptr->s2, eg_ptr->s3,
             eg_ptr->x_info, eg_ptr->info);
 #else
-        sprintf(eg_ptr->out_val, "[%s]%s%s%s%s(%s) [r, %s%s]", acount, eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, m_name, look_mon_desc(eg_ptr->m_ptr, 0x01),
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "[%s]%s%s%s%s(%s) [r, %s%s]", acount.data(), eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, m_name, look_mon_desc(eg_ptr->m_ptr, 0x01),
             eg_ptr->x_info, eg_ptr->info);
 #endif
         prt(eg_ptr->out_val, 0, 0);
@@ -254,9 +252,9 @@ static uint16_t describe_monster_item(PlayerType *player_ptr, eg_type *eg_ptr)
         o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
         describe_flavor(player_ptr, o_name, o_ptr, 0);
 #ifdef JP
-        sprintf(eg_ptr->out_val, "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-        sprintf(eg_ptr->out_val, "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
 #endif
         prt(eg_ptr->out_val, 0, 0);
         move_cursor_relative(eg_ptr->y, eg_ptr->x);
@@ -325,9 +323,9 @@ static int16_t describe_footing(PlayerType *player_ptr, eg_type *eg_ptr)
     o_ptr = &player_ptr->current_floor_ptr->o_list[eg_ptr->floor_list[0]];
     describe_flavor(player_ptr, o_name, o_ptr, 0);
 #ifdef JP
-    sprintf(eg_ptr->out_val, "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-    sprintf(eg_ptr->out_val, "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
 #endif
     prt(eg_ptr->out_val, 0, 0);
     move_cursor_relative(eg_ptr->y, eg_ptr->x);
@@ -342,9 +340,9 @@ static int16_t describe_footing_items(eg_type *eg_ptr)
     }
 
 #ifdef JP
-    sprintf(eg_ptr->out_val, "%s %d個のアイテム%s%s ['x'で一覧, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s %d個のアイテム%s%s ['x'で一覧, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-    sprintf(eg_ptr->out_val, "%s%s%sa pile of %d items [x,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%sa pile of %d items [x,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
 #endif
     prt(eg_ptr->out_val, 0, 0);
     move_cursor_relative(eg_ptr->y, eg_ptr->x);
@@ -364,9 +362,9 @@ static char describe_footing_many_items(PlayerType *player_ptr, eg_type *eg_ptr,
         (void)show_floor_items(player_ptr, 0, eg_ptr->y, eg_ptr->x, min_width, AllMatchItemTester());
         show_gold_on_floor = false;
 #ifdef JP
-        sprintf(eg_ptr->out_val, "%s %d個のアイテム%s%s [Enterで次へ, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s %d個のアイテム%s%s [Enterで次へ, %s]", eg_ptr->s1, (int)eg_ptr->floor_num, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-        sprintf(eg_ptr->out_val, "%s%s%sa pile of %d items [Enter,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%sa pile of %d items [Enter,%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, (int)eg_ptr->floor_num, eg_ptr->info);
 #endif
         prt(eg_ptr->out_val, 0, 0);
         eg_ptr->query = inkey();
@@ -418,9 +416,9 @@ static int16_t describe_footing_sight(PlayerType *player_ptr, eg_type *eg_ptr, I
     eg_ptr->boring = false;
     describe_flavor(player_ptr, o_name, o_ptr, 0);
 #ifdef JP
-    sprintf(eg_ptr->out_val, "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, o_name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-    sprintf(eg_ptr->out_val, "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, o_name, eg_ptr->info);
 #endif
     prt(eg_ptr->out_val, 0, 0);
     move_cursor_relative(eg_ptr->y, eg_ptr->x);
@@ -504,27 +502,27 @@ static void describe_grid_monster_all(eg_type *eg_ptr)
 {
     if (!w_ptr->wizard) {
 #ifdef JP
-        sprintf(eg_ptr->out_val, "%s%s%s%s[%s]", eg_ptr->s1, eg_ptr->name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s]", eg_ptr->s1, eg_ptr->name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info);
 #else
-        sprintf(eg_ptr->out_val, "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name, eg_ptr->info);
+        strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s]", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name, eg_ptr->info);
 #endif
         return;
     }
 
-    char f_idx_str[32];
+    std::string f_idx_str;
     if (eg_ptr->g_ptr->mimic) {
-        sprintf(f_idx_str, "%d/%d", eg_ptr->g_ptr->feat, eg_ptr->g_ptr->mimic);
+        f_idx_str = format("%d/%d", eg_ptr->g_ptr->feat, eg_ptr->g_ptr->mimic);
     } else {
-        sprintf(f_idx_str, "%d", eg_ptr->g_ptr->feat);
+        f_idx_str = std::to_string(eg_ptr->g_ptr->feat);
     }
 
 #ifdef JP
-    sprintf(eg_ptr->out_val, "%s%s%s%s[%s] %x %s %d %d %d (%d,%d) %d", eg_ptr->s1, eg_ptr->name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info,
-        (uint)eg_ptr->g_ptr->info, f_idx_str, eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y,
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s[%s] %x %s %d %d %d (%d,%d) %d", eg_ptr->s1, eg_ptr->name, eg_ptr->s2, eg_ptr->s3, eg_ptr->info,
+        (uint)eg_ptr->g_ptr->info, f_idx_str.data(), eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y,
         (int)eg_ptr->x, travel.cost[eg_ptr->y][eg_ptr->x]);
 #else
-    sprintf(eg_ptr->out_val, "%s%s%s%s [%s] %x %s %d %d %d (%d,%d)", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name, eg_ptr->info, eg_ptr->g_ptr->info,
-        f_idx_str, eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y, (int)eg_ptr->x);
+    strnfmt(eg_ptr->out_val, sizeof(eg_ptr->out_val), "%s%s%s%s [%s] %x %s %d %d %d (%d,%d)", eg_ptr->s1, eg_ptr->s2, eg_ptr->s3, eg_ptr->name, eg_ptr->info, eg_ptr->g_ptr->info,
+        f_idx_str.data(), eg_ptr->g_ptr->dists[FLOW_NORMAL], eg_ptr->g_ptr->costs[FLOW_NORMAL], eg_ptr->g_ptr->when, (int)eg_ptr->y, (int)eg_ptr->x);
 #endif
 }
 
index 1e1dc29..24c3162 100644 (file)
@@ -123,7 +123,7 @@ void prt(std::string_view sv, TERM_LEN row, TERM_LEN col)
  * This function will correctly handle any width up to the maximum legal
  * value of 256, though it works best for a standard 80 character width.
  */
-void c_roff(TERM_COLOR a, concptr str)
+void c_roff(TERM_COLOR a, std::string_view str)
 {
     int w, h;
     (void)term_get_size(&w, &h);
@@ -135,7 +135,7 @@ void c_roff(TERM_COLOR a, concptr str)
         return;
     }
 
-    for (concptr s = str; *s; s++) {
+    for (auto s = str.begin(); s != str.end(); s++) {
         char ch;
 #ifdef JP
         int k_flag = iskanji(*s);
@@ -250,7 +250,7 @@ void c_roff(TERM_COLOR a, concptr str)
 /*
  * As above, but in "white"
  */
-void roff(concptr str)
+void roff(std::string_view str)
 {
     /* Spawn */
     c_roff(TERM_WHITE, str);
index 0007ba8..ad1d4dc 100644 (file)
@@ -17,6 +17,6 @@ void c_put_str(TERM_COLOR attr, std::string_view sv, TERM_LEN row, TERM_LEN col)
 void put_str(std::string_view sv, TERM_LEN row, TERM_LEN col);
 void c_prt(TERM_COLOR attr, std::string_view sv, TERM_LEN row, TERM_LEN col);
 void prt(std::string_view sv, TERM_LEN row, TERM_LEN col);
-void c_roff(TERM_COLOR attr, concptr str);
-void roff(concptr str);
+void c_roff(TERM_COLOR attr, std::string_view str);
+void roff(std::string_view str);
 void clear_from(int row);
index 8c69cee..5a1402f 100644 (file)
@@ -116,7 +116,7 @@ void display_roff(PlayerType *player_ptr)
  * @param roff_func 出力処理を行う関数ポインタ
  * @todo ここのroff_funcの引数にFILE* を追加しないとspoiler_file をローカル関数化することができないと判明した、保留.
  */
-void output_monster_spoiler(MonsterRaceId r_idx, void (*roff_func)(TERM_COLOR attr, concptr str))
+void output_monster_spoiler(MonsterRaceId r_idx, hook_c_roff_pf roff_func)
 {
     hook_c_roff = roff_func;
     PlayerType dummy;
index aaafec6..5126c9f 100644 (file)
@@ -8,7 +8,7 @@ class PlayerType;
 void roff_top(MonsterRaceId r_idx);
 void screen_roff(PlayerType *player_ptr, MonsterRaceId r_idx, monster_lore_mode mode);
 void display_roff(PlayerType *player_ptr);
-void output_monster_spoiler(MonsterRaceId r_idx, void (*roff_func)(TERM_COLOR attr, concptr str));
+void output_monster_spoiler(MonsterRaceId r_idx, hook_c_roff_pf roff_func);
 void display_kill_numbers(lore_type *lore_ptr);
 bool display_where_to_appear(lore_type *lore_ptr);
 void display_random_move(lore_type *lore_ptr);
index 1cb2a7b..b24bfc4 100644 (file)
@@ -321,7 +321,7 @@ std::optional<int> display_player(PlayerType *player_ptr, const int tmp_mode)
     display_player_basic_info(player_ptr);
     display_magic_realms(player_ptr);
     if (PlayerClass(player_ptr).equals(PlayerClassType::CHAOS_WARRIOR) || (player_ptr->muta.has(PlayerMutationType::CHAOS_GIFT))) {
-        display_player_one_line(ENTRY_PATRON, patron_list[player_ptr->chaos_patron].name.data(), TERM_L_BLUE);
+        display_player_one_line(ENTRY_PATRON, patron_list[player_ptr->chaos_patron].name, TERM_L_BLUE);
     }
 
     display_phisique(player_ptr);
index 3ed0143..4e50dc0 100644 (file)
@@ -66,7 +66,7 @@ const std::vector<disp_player_line> disp_player_lines = {
  * @param val 値を保管した文字列ポインタ
  * @param attr 項目表示の色
  */
-void display_player_one_line(int entry, concptr val, TERM_COLOR attr)
+void display_player_one_line(int entry, std::string_view val, TERM_COLOR attr)
 {
     auto head = disp_player_lines[entry].header;
     auto head_len = strlen(head);
@@ -75,17 +75,16 @@ void display_player_one_line(int entry, concptr val, TERM_COLOR attr)
     auto len = disp_player_lines[entry].len;
     term_putstr(col, row, -1, TERM_WHITE, head);
 
-    if (!val) {
-        return;
-    }
-
     if (len <= 0) {
         term_putstr(col + head_len, row, -1, attr, val);
         return;
     }
 
     int val_len = len - head_len;
-    char buf[40];
-    sprintf(buf, "%*.*s", val_len, val_len, val);
-    term_putstr(col + head_len, row, -1, attr, buf);
+    std::string str;
+    if (val_len > static_cast<int>(val.length())) {
+        str.append(val_len - val.length(), ' ');
+    }
+    str.append(val);
+    term_putstr(col + head_len, row, -1, attr, str);
 }
index 9008587..13c251d 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 
 #include "system/angband.h"
+#include <string_view>
 
-void display_player_one_line(int entry, concptr val, TERM_COLOR attr);
+void display_player_one_line(int entry, std::string_view val, TERM_COLOR attr);
index fcbc732..6d64c36 100644 (file)
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
 #include "term/term-color-types.h"
+#include "term/z-form.h"
 #include "util/bit-flags-calculator.h"
 #include "view/display-util.h"
 
-static TERM_COLOR likert_color = TERM_WHITE;
-
 /*!
  * @brief
  * @param player_ptr プレイヤーへの参照ポインタ
@@ -177,86 +176,64 @@ static int strengthen_basedam(PlayerType *player_ptr, ItemEntity *o_ptr, int bas
  * Returns a "rating" of x depending on y
  * @param x 技能値
  * @param y 技能値に対するランク基準比
+ * @return スキル レベルのテキスト説明とその説明のカラー インデックスのペア
  */
-static concptr likert(int x, int y)
+static std::pair<std::string, TERM_COLOR> likert(int x, int y)
 {
-    static char dummy[20] = "", dummy2[20] = "";
-    memset(dummy, 0, strlen(dummy));
-    memset(dummy2, 0, strlen(dummy2));
-    if (y <= 0) {
-        y = 1;
-    }
+    std::string desc;
 
     if (show_actual_value) {
-        sprintf(dummy, "%3d-", x);
+        desc = format("%3d-", x);
     }
 
     if (x < 0) {
-        likert_color = TERM_L_DARK;
-        strcat(dummy, _("最低", "Very Bad"));
-        return dummy;
+        return make_pair(desc.append(_("最低", "Very Bad")), TERM_L_DARK);
+    }
+
+    if (y <= 0) {
+        y = 1;
     }
 
     switch ((x / y)) {
     case 0:
     case 1: {
-        likert_color = TERM_RED;
-        strcat(dummy, _("悪い", "Bad"));
-        break;
+        return make_pair(desc.append(_("悪い", "Bad")), TERM_RED);
     }
     case 2: {
-        likert_color = TERM_L_RED;
-        strcat(dummy, _("劣る", "Poor"));
-        break;
+        return make_pair(desc.append(_("劣る", "Poor")), TERM_L_RED);
     }
     case 3:
     case 4: {
-        likert_color = TERM_ORANGE;
-        strcat(dummy, _("普通", "Fair"));
-        break;
+        return make_pair(desc.append(_("普通", "Fair")), TERM_ORANGE);
     }
     case 5: {
-        likert_color = TERM_YELLOW;
-        strcat(dummy, _("良い", "Good"));
-        break;
+        return make_pair(desc.append(_("良い", "Good")), TERM_YELLOW);
     }
     case 6: {
-        likert_color = TERM_YELLOW;
-        strcat(dummy, _("大変良い", "Very Good"));
-        break;
+        return make_pair(desc.append(_("大変良い", "Very Good")), TERM_YELLOW);
     }
     case 7:
     case 8: {
-        likert_color = TERM_L_GREEN;
-        strcat(dummy, _("卓越", "Excellent"));
-        break;
+        return make_pair(desc.append(_("卓越", "Excellent")), TERM_L_GREEN);
     }
     case 9:
     case 10:
     case 11:
     case 12:
     case 13: {
-        likert_color = TERM_GREEN;
-        strcat(dummy, _("超越", "Superb"));
-        break;
+        return make_pair(desc.append(_("超越", "Superb")), TERM_GREEN);
     }
     case 14:
     case 15:
     case 16:
     case 17: {
-        likert_color = TERM_BLUE;
-        strcat(dummy, _("英雄的", "Heroic"));
-        break;
+        return make_pair(desc.append(_("英雄的", "Heroic")), TERM_BLUE);
     }
     default: {
-        likert_color = TERM_VIOLET;
-        sprintf(dummy2, _("伝説的[%d]", "Legendary[%d]"), (int)((((x / y) - 17) * 5) / 2));
-        strcat(dummy, dummy2);
-        break;
+        desc.append(format(_("伝説的[%d]", "Legendary[%d]"), (int)((((x / y) - 17) * 5) / 2)));
+        return make_pair(desc, TERM_VIOLET);
     }
     }
-
-    return dummy;
 }
 
 /*!
@@ -354,35 +331,32 @@ static void display_first_page(PlayerType *player_ptr, int xthb, int *damage, in
     int xfos = player_ptr->skill_fos;
     int xdig = player_ptr->skill_dig;
 
-    concptr desc = likert(xthn, 12);
-    display_player_one_line(ENTRY_SKILL_FIGHT, desc, likert_color);
-
-    desc = likert(xthb, 12);
-    display_player_one_line(ENTRY_SKILL_SHOOT, desc, likert_color);
+    auto sd = likert(xthn, 12);
+    display_player_one_line(ENTRY_SKILL_FIGHT, sd.first, sd.second);
 
-    desc = likert(xsav, 7);
-    display_player_one_line(ENTRY_SKILL_SAVING, desc, likert_color);
+    sd = likert(xthb, 12);
+    display_player_one_line(ENTRY_SKILL_SHOOT, sd.first, sd.second);
 
-    desc = likert((xstl > 0) ? xstl : -1, 1);
-    display_player_one_line(ENTRY_SKILL_STEALTH, desc, likert_color);
+    sd = likert(xsav, 7);
+    display_player_one_line(ENTRY_SKILL_SAVING, sd.first, sd.second);
 
-    desc = likert(xfos, 6);
-    display_player_one_line(ENTRY_SKILL_PERCEP, desc, likert_color);
+    sd = likert((xstl > 0) ? xstl : -1, 1);
+    display_player_one_line(ENTRY_SKILL_STEALTH, sd.first, sd.second);
 
-    desc = likert(xsrh, 6);
-    display_player_one_line(ENTRY_SKILL_SEARCH, desc, likert_color);
+    sd = likert(xfos, 6);
+    display_player_one_line(ENTRY_SKILL_PERCEP, sd.first, sd.second);
 
-    desc = likert(xdis, 8);
-    display_player_one_line(ENTRY_SKILL_DISARM, desc, likert_color);
+    sd = likert(xsrh, 6);
+    display_player_one_line(ENTRY_SKILL_SEARCH, sd.first, sd.second);
 
-    desc = likert(xdev, 6);
-    display_player_one_line(ENTRY_SKILL_DEVICE, desc, likert_color);
+    sd = likert(xdis, 8);
+    display_player_one_line(ENTRY_SKILL_DISARM, sd.first, sd.second);
 
-    desc = likert(xdev, 6);
-    display_player_one_line(ENTRY_SKILL_DEVICE, desc, likert_color);
+    sd = likert(xdev, 6);
+    display_player_one_line(ENTRY_SKILL_DEVICE, sd.first, sd.second);
 
-    desc = likert(xdig, 4);
-    display_player_one_line(ENTRY_SKILL_DIG, desc, likert_color);
+    sd = likert(xdig, 4);
+    display_player_one_line(ENTRY_SKILL_DIG, sd.first, sd.second);
 
     if (!muta_att) {
         display_player_one_line(ENTRY_BLOWS, format("%d+%d", blows1, blows2), TERM_L_BLUE);
@@ -392,6 +366,7 @@ static void display_first_page(PlayerType *player_ptr, int xthb, int *damage, in
 
     display_player_one_line(ENTRY_SHOTS, format("%d.%02d", shots, shot_frac), TERM_L_BLUE);
 
+    concptr desc;
     if ((damage[0] + damage[1]) == 0) {
         desc = "nil!";
     } else {
index 111b3e9..9ca700c 100644 (file)
@@ -9,6 +9,7 @@
 #include "system/baseitem-info.h"
 #include "system/item-entity.h"
 #include "system/player-type-definition.h"
+#include "term/z-form.h"
 #include "util/angband-files.h"
 #include "view/display-messages.h"
 #include "wizard/spoiler-util.h"
@@ -26,7 +27,7 @@
  * @param value 価値を返すバッファ参照ポインタ
  * @param bi_id ベースアイテムID
  */
-static void describe_baseitem_info(PlayerType *player_ptr, char *name, char *damage_desc, char *weight_desc, char *chance_desc, DEPTH *level, PRICE *value, short bi_id)
+static void describe_baseitem_info(PlayerType *player_ptr, char *name, std::string *damage_desc, std::string *weight_desc, std::string *chance_desc, DEPTH *level, PRICE *value, short bi_id)
 {
     ItemEntity forge;
     auto *q_ptr = &forge;
@@ -43,18 +44,17 @@ static void describe_baseitem_info(PlayerType *player_ptr, char *name, char *dam
     }
 
     describe_flavor(player_ptr, name, q_ptr, OD_NAME_ONLY | OD_STORE);
-    strcpy(damage_desc, "");
     switch (q_ptr->bi_key.tval()) {
     case ItemKindType::SHOT:
     case ItemKindType::BOLT:
     case ItemKindType::ARROW:
-        sprintf(damage_desc, "%dd%d", q_ptr->dd, q_ptr->ds);
+        *damage_desc = format("%dd%d", q_ptr->dd, q_ptr->ds);
         break;
     case ItemKindType::HAFTED:
     case ItemKindType::POLEARM:
     case ItemKindType::SWORD:
     case ItemKindType::DIGGING:
-        sprintf(damage_desc, "%dd%d", q_ptr->dd, q_ptr->ds);
+        *damage_desc = format("%dd%d", q_ptr->dd, q_ptr->ds);
         break;
     case ItemKindType::BOOTS:
     case ItemKindType::GLOVES:
@@ -65,24 +65,23 @@ static void describe_baseitem_info(PlayerType *player_ptr, char *name, char *dam
     case ItemKindType::SOFT_ARMOR:
     case ItemKindType::HARD_ARMOR:
     case ItemKindType::DRAG_ARMOR:
-        sprintf(damage_desc, "%d", q_ptr->ac);
+        *damage_desc = format("%d", q_ptr->ac);
         break;
     default:
+        damage_desc->clear();
         break;
     }
 
-    strcpy(chance_desc, "");
+    chance_desc->clear();
     const auto &baseitem = baseitems_info[q_ptr->bi_id];
     for (auto i = 0U; i < baseitem.alloc_tables.size(); i++) {
         const auto &[level, chance] = baseitem.alloc_tables[i];
-        char chance_aux[20] = "";
         if (chance > 0) {
-            sprintf(chance_aux, "%s%3dF:%+4d", (i != 0 ? "/" : ""), level, 100 / chance);
-            strcat(chance_desc, chance_aux);
+            chance_desc->append(format("%s%3dF:%+4d", (i != 0 ? "/" : ""), level, 100 / chance));
         }
     }
 
-    sprintf(weight_desc, "%3d.%d", (int)(q_ptr->weight / 10), (int)(q_ptr->weight % 10));
+    *weight_desc = format("%3d.%d", (int)(q_ptr->weight / 10), (int)(q_ptr->weight % 10));
 }
 
 /*!
@@ -131,12 +130,12 @@ SpoilerOutputResultType spoil_obj_desc(concptr fname)
         for (const auto &bi_id : whats) {
             DEPTH e;
             PRICE v;
-            char wgt[80];
-            char chance[80];
-            char dam[80];
+            std::string wgt, chance, dam;
             PlayerType dummy;
-            describe_baseitem_info(&dummy, buf, dam, wgt, chance, &e, &v, bi_id);
-            fprintf(spoiler_file, "  %-35s%8s%7s%5d %-40s%9ld\n", buf, dam, wgt, static_cast<int>(e), chance, static_cast<long>(v));
+            describe_baseitem_info(&dummy, buf, &dam, &wgt, &chance, &e, &v, bi_id);
+            fprintf(spoiler_file, "  %-35s%8s%7s%5d %-40s%9ld\n", buf,
+                dam.data(), wgt.data(), static_cast<int>(e), chance.data(),
+                static_cast<long>(v));
         }
     }
 
index f1af5a0..cd0fc4e 100644 (file)
@@ -159,10 +159,10 @@ SpoilerOutputResultType spoil_mon_desc(concptr fname, std::function<bool(const M
  * @param attr 未使用
  * @param str 文字列参照ポインタ
  */
-static void roff_func(TERM_COLOR attr, concptr str)
+static void roff_func(TERM_COLOR attr, std::string_view str)
 {
     (void)attr;
-    spoil_out(str);
+    spoil_out(str.data());
 }
 
 /*!