OSDN Git Service

[Refactor] 各パーサをstd::string系の処理を利用して書き直し
authoriks <iks3@users.noreply.github.com>
Sat, 24 Apr 2021 14:04:08 +0000 (23:04 +0900)
committeriks <iks3@users.noreply.github.com>
Sat, 8 May 2021 19:08:23 +0000 (04:08 +0900)
同時にエラーコードのenumへ置換。

33 files changed:
src/flavor/object-flavor.cpp
src/grid/feature-flag-types.h
src/info-reader/artifact-reader.cpp
src/info-reader/artifact-reader.h
src/info-reader/dungeon-reader.cpp
src/info-reader/dungeon-reader.h
src/info-reader/ego-reader.cpp
src/info-reader/ego-reader.h
src/info-reader/feature-info-tokens-table.cpp
src/info-reader/feature-info-tokens-table.h
src/info-reader/feature-reader.cpp
src/info-reader/feature-reader.h
src/info-reader/general-parser.cpp
src/info-reader/general-parser.h
src/info-reader/info-reader-util.cpp
src/info-reader/info-reader-util.h
src/info-reader/kind-info-tokens-table.cpp
src/info-reader/kind-info-tokens-table.h
src/info-reader/kind-reader.cpp
src/info-reader/kind-reader.h
src/info-reader/magic-reader.cpp
src/info-reader/magic-reader.h
src/info-reader/race-info-tokens-table.cpp
src/info-reader/race-info-tokens-table.h
src/info-reader/race-reader.cpp
src/info-reader/race-reader.h
src/info-reader/skill-reader.cpp
src/info-reader/skill-reader.h
src/info-reader/vault-reader.cpp
src/info-reader/vault-reader.h
src/main/angband-headers.h
src/main/info-initializer.cpp
src/monster-race/race-flags8.h

index 9da8e20..352553d 100644 (file)
@@ -266,23 +266,30 @@ void flavor_init(void)
  */
 void strip_name(char *buf, KIND_OBJECT_IDX k_idx)
 {
-    object_kind *k_ptr = &k_info[k_idx];
-    concptr str = k_ptr->name.c_str();
-    while ((*str == ' ') || (*str == '&') || (*str == '#'))
-        str++;
+    auto k_ptr = &k_info[k_idx];
+    auto tok = str_split(k_ptr->name, ' ');
+    std::string name = "";
+    for (auto s : tok) {
+        if (s == "" || s == "~" || s == "&" || s == "#")
+            continue;
+
+        auto offset = 0;
+        auto endpos = s.size();
+        auto is_kanji = false;
 
-    char *t;
-    for (t = buf; *str; str++) {
+        if (s[0] == '~' || s[0] == '#')
+            offset++;
 #ifdef JP
-        if (iskanji(*str)) {
-            *t++ = *str++;
-            *t++ = *str;
-            continue;
-        }
+        if (s.size() > 2)
+            is_kanji = iskanji(s[endpos - 2]);
+
 #endif
-        if (*str != '~' && *str != '#')
-            *t++ = *str;
+        if (!is_kanji && (s[endpos - 1] == '~' || s[endpos - 1] == '#'))
+            endpos--;
+
+        name += s.substr(offset, endpos);
     }
 
-    *t = '\0';
+    name += " ";
+    strcpy(buf, name.c_str());
 }
index 0367a8d..2631f27 100644 (file)
@@ -51,6 +51,7 @@ enum feature_flag_type : int {
     FF_CAN_PASS = 55, /*!< 通過可能な地形である */
     FF_CAN_DIG = 57, /*!< 掘削コマンドの対象となる地形である */
     FF_TREE = 83, /*!< 木の生えた地形である */
+    FF_PLANT = 88, //!< 植物の生えた地形である
     FF_SPECIAL = 96, /*!< クエストやダンジョンに関わる特別な地形である */
     FF_HURT_DISI = 97, /*!< 分解属性の対象となる地形である */
     FF_QUEST_ENTER = 98, /*!< クエストの入り口である */
index 3e7bdd2..3203b2f 100644 (file)
@@ -1,32 +1,31 @@
 #include "info-reader/artifact-reader.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/kind-info-tokens-table.h"
+#include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
 #include "object-enchant/tr-types.h"
 #include "system/artifact-type-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-#include <string>
 
 /*!
  * @brief テキストトークンを走査してフラグを一つ得る(アーティファクト用) /
  * Grab one activation index flag
  * @param a_ptr 保管先のアーティファクト構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーがあった場合1、エラーがない場合0を返す
+ * @return 見つかったらtrue
  */
-static errr grab_one_artifact_flag(artifact_type *a_ptr, concptr what)
+static bool grab_one_artifact_flag(artifact_type *a_ptr, std::string_view what)
 {
-    if (k_info_flags.find(what) != k_info_flags.end()) {
-        add_flag(a_ptr->flags, k_info_flags[what]);
-        return 0;
-    }
+    if (info_grab_one_flag(a_ptr->flags, k_info_flags, what))
+        return true;
 
     if (EnumClassFlagGroup<TRG>::grab_one_flag(a_ptr->gen_flags, k_info_gen_flags, what))
-        return 0;
+        return true;
 
-    msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what);
-    return 1;
+    msg_format(_("未知の伝説のアイテム・フラグ '%s'。", "Unknown artifact flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -36,25 +35,21 @@ static errr grab_one_artifact_flag(artifact_type *a_ptr, concptr what)
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_a_info(char *buf, angband_header *head)
+errr parse_a_info(std::string_view buf, angband_header *head)
 {
     static artifact_type *a_ptr = NULL;
-    char *s, *t;
-    if (buf[0] == 'N') {
-        s = angband_strchr(buf + 2, ':');
-        if (!s)
-            return 1;
+    const auto &tokens = str_split(buf, ':', false, 10);
 
-        *s++ = '\0';
-#ifdef JP
-        if (!*s)
-            return 1;
-#endif
-        int i = atoi(buf + 2);
+    if (tokens[0] == "N") {
+        // N:index:name_ja
+        if (tokens.size() < 3 || tokens[1].size() == 0)
+            return PARSE_ERROR_GENERIC;
+
+        auto i = std::stoi(tokens[1]);
         if (i < error_idx)
-            return 4;
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         a_ptr = &a_info[i];
@@ -62,92 +57,88 @@ errr parse_a_info(char *buf, angband_header *head)
         add_flag(a_ptr->flags, TR_IGNORE_ELEC);
         add_flag(a_ptr->flags, TR_IGNORE_FIRE);
         add_flag(a_ptr->flags, TR_IGNORE_COLD);
+
 #ifdef JP
-        a_ptr->name = std::string(s);
+        a_ptr->name = tokens[2];
 #endif
-    } else if (!a_ptr) {
-        return 3;
-    }
-#ifdef JP
-    /* 英語名を読むルーチンを追加 */
-    /* 'E' から始まる行は英語名としている */
-    else if (buf[0] == 'E') {
-        /* nothing to do */
-    }
-#else
-    else if (buf[0] == 'E') {
-        s = buf + 2;
-        a_ptr->name = std::string(s);
-    }
+    } else if (!a_ptr)
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if (tokens[0] == "E") {
+        // E:name_en
+#ifndef JP
+        if (tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        a_ptr->name = tokens[1];
 #endif
-    else if (buf[0] == 'D') {
+    } else if (tokens[0] == "D") {
+        // D:JapaneseText
+        // D:$EnglishText
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
 #ifdef JP
-        if (buf[2] == '$')
-            return 0;
-        s = buf + 2;
+        if (tokens[1][0] == '$')
+            return PARSE_ERROR_NONE;
+        a_ptr->text.append(buf.substr(2));
 #else
-        if (buf[2] != '$')
-            return 0;
-        s = buf + 3;
+        if (tokens[1][0] != '$')
+            return PARSE_ERROR_NONE;
+        a_ptr->text.append(buf.substr(3));
 #endif
-        a_ptr->text.append(s);
-    } else if (buf[0] == 'I') {
-        int tval, sval, pval;
-        if (3 != sscanf(buf + 2, "%d:%d:%d", &tval, &sval, &pval))
-            return 1;
+    } else if (tokens[0] == "I") {
+        // I:tval:sval:pval
+        if (tokens.size() < 4)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        a_ptr->tval = (tval_type)tval;
-        a_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval;
-        a_ptr->pval = (PARAMETER_VALUE)pval;
-    } else if (buf[0] == 'W') {
-        int level, rarity, wgt;
-        long cost;
-        if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", &level, &rarity, &wgt, &cost))
-            return 1;
+        info_set_value(a_ptr->tval, tokens[1]);
+        info_set_value(a_ptr->sval, tokens[2]);
+        info_set_value(a_ptr->pval, tokens[3]);
+    } else if (tokens[0] == "W") {
+        // W:level:ratiry:weight:cost
+        if (tokens.size() < 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        a_ptr->level = (DEPTH)level;
-        a_ptr->rarity = (RARITY)rarity;
-        a_ptr->weight = (WEIGHT)wgt;
-        a_ptr->cost = (PRICE)cost;
-    } else if (buf[0] == 'P') {
-        int ac, hd1, hd2, th, td, ta;
-        if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &ac, &hd1, &hd2, &th, &td, &ta))
-            return 1;
+        info_set_value(a_ptr->level, tokens[1]);
+        info_set_value(a_ptr->rarity, tokens[2]);
+        info_set_value(a_ptr->weight, tokens[3]);
+        info_set_value(a_ptr->cost, tokens[4]);
+    } else if (tokens[0] == "P") {
+        // P:ac:dd:ds:to_h:to_d:to_a
+        if (tokens.size() < 6)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        a_ptr->ac = (ARMOUR_CLASS)ac;
-        a_ptr->dd = (DICE_NUMBER)hd1;
-        a_ptr->ds = (DICE_SID)hd2;
-        a_ptr->to_h = (HIT_PROB)th;
-        a_ptr->to_d = (HIT_POINT)td;
-        a_ptr->to_a = (ARMOUR_CLASS)ta;
-    } else if (buf[0] == 'U') {
-        byte n;
-        n = grab_one_activation_flag(buf + 2);
-        if (n > 0) {
-            a_ptr->act_idx = n;
-        } else {
-            return 5;
-        }
-    } else if (buf[0] == 'F') {
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
+        const auto &dice = str_split(tokens[2], 'd', false, 2);
+        if (dice.size() != 2)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
 
-            if (*t) {
-                *t++ = '\0';
-                while ((*t == ' ') || (*t == '|'))
-                    t++;
-            }
+        info_set_value(a_ptr->ac, tokens[1]);
+        info_set_value(a_ptr->dd, dice[0]);
+        info_set_value(a_ptr->ds, dice[1]);
+        info_set_value(a_ptr->to_h, tokens[3]);
+        info_set_value(a_ptr->to_d, tokens[4]);
+        info_set_value(a_ptr->to_a, tokens[5]);
+    } else if (tokens[0] == "U") {
+        // U:activation_flag
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        auto n = grab_one_activation_flag(tokens[1].c_str());
+        if (n <= 0)
+            return PARSE_ERROR_INVALID_FLAG;
 
-            if (0 != grab_one_artifact_flag(a_ptr, s))
-                return 5;
+        a_ptr->act_idx = (IDX)n;
+    } else if (tokens[0] == "F") {
+        // F:flags
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-            s = t;
+        const auto &flags = str_split(tokens[1], '|', true, 10);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
+                continue;
+            if (!grab_one_artifact_flag(a_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
         }
-    } else {
-        return 6;
-    }
+    } else
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
-    return 0;
+    return PARSE_ERROR_NONE;
 }
index cbbe903..4197ff4 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
-#include "info-reader/info-reader-util.h"
 #include "system/angband.h"
+#include <string_view>
 
-errr parse_a_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_a_info(std::string_view buf, angband_header *head);
index c13390c..61ed5b6 100644 (file)
@@ -3,28 +3,28 @@
 #include "grid/feature.h"
 #include "info-reader/dungeon-info-tokens-table.h"
 #include "info-reader/feature-reader.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "info-reader/race-info-tokens-table.h"
 #include "io/tokenizer.h"
 #include "main/angband-headers.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-#include <string>
 
 /*!
  * @brief テキストトークンを走査してフラグを一つ得る(ダンジョン用) /
  * Grab one flag for a dungeon type from a textual string
  * @param d_ptr 保管先のダンジョン構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_dungeon_flag(dungeon_type *d_ptr, concptr what)
+static bool grab_one_dungeon_flag(dungeon_type *d_ptr, std::string_view what)
 {
     if (EnumClassFlagGroup<DF>::grab_one_flag(d_ptr->flags, d_info_flags, what))
-        return 0;
+        return true;
 
-    msg_format(_("未知のダンジョン・フラグ '%s'。", "Unknown dungeon type flag '%s'."), what);
-    return 1;
+    msg_format(_("未知のダンジョン・フラグ '%s'。", "Unknown dungeon type flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -32,33 +32,33 @@ static errr grab_one_dungeon_flag(dungeon_type *d_ptr, concptr what)
  * Grab one (basic) flag in a monster_race from a textual string
  * @param d_ptr 保管先のダンジョン構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_basic_monster_flag(dungeon_type *d_ptr, concptr what)
+static bool grab_one_basic_monster_flag(dungeon_type *d_ptr, std::string_view what)
 {
-    if (grab_one_flag(&d_ptr->mflags1, r_info_flags1, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflags1, r_info_flags1, what))
+        return true;
 
-    if (grab_one_flag(&d_ptr->mflags2, r_info_flags2, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflags2, r_info_flags2, what))
+        return true;
 
-    if (grab_one_flag(&d_ptr->mflags3, r_info_flags3, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflags3, r_info_flags3, what))
+        return true;
 
-    if (grab_one_flag(&d_ptr->mflags7, r_info_flags7, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflags7, r_info_flags7, what))
+        return true;
 
-    if (grab_one_flag(&d_ptr->mflags8, r_info_flags8, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflags8, r_info_flags8, what))
+        return true;
 
-    if (grab_one_flag(&d_ptr->mflags9, r_info_flags9, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflags9, r_info_flags9, what))
+        return true;
 
-    if (grab_one_flag(&d_ptr->mflagsr, r_info_flagsr, what) == 0)
-        return 0;
+    if (info_grab_one_flag(d_ptr->mflagsr, r_info_flagsr, what))
+        return true;
 
-    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
-    return 1;
+    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -66,15 +66,15 @@ static errr grab_one_basic_monster_flag(dungeon_type *d_ptr, concptr what)
  * Grab one (spell) flag in a monster_race from a textual string
  * @param d_ptr 保管先のダンジョン構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_spell_monster_flag(dungeon_type *d_ptr, concptr what)
+static bool grab_one_spell_monster_flag(dungeon_type *d_ptr, std::string_view what)
 {
     if (EnumClassFlagGroup<RF_ABILITY>::grab_one_flag(d_ptr->m_ability_flags, r_info_ability_flags, what))
-        return 0;
+        return true;
 
-    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
-    return 1;
+    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -84,220 +84,203 @@ static errr grab_one_spell_monster_flag(dungeon_type *d_ptr, concptr what)
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_d_info(char *buf, angband_header *head)
+errr parse_d_info(std::string_view buf, angband_header *head)
 {
     static dungeon_type *d_ptr = NULL;
-    char *s, *t;
-    if (buf[0] == 'N') {
-        s = angband_strchr(buf + 2, ':');
-        if (!s)
-            return 1;
+    const auto &tokens = str_split(buf, ':', false);
 
-        *s++ = '\0';
-#ifdef JP
-        if (!*s)
-            return 1;
-#endif
+    if (tokens[0] == "N") {
+        // N:index:name_ja
+        if (tokens.size() < 3 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        int i = atoi(buf + 2);
+        auto i = std::stoi(tokens[1]);
         if (i < error_idx)
-            return 4;
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         d_ptr = &d_info[i];
 #ifdef JP
-        d_ptr->name = std::string(s);
+        d_ptr->name = tokens[2];
 #endif
-    }
-#ifdef JP
-    else if (buf[0] == 'E')
-        return 0;
-#else
-    else if (buf[0] == 'E') {
-        /* Acquire the Text */
-        s = buf + 2;
-
-        /* Store the name */
-        d_ptr->name = std::string(s);
-    }
+    } else if (!d_ptr)
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if (tokens[0] == "E") {
+        // E:name_en
+#ifndef JP
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        d_ptr->name = tokens[1];
 #endif
-    else if (buf[0] == 'D') {
+    } else if (tokens[0] == "D") {
+        // D:text_ja
+        // D:$text_en
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 #ifdef JP
-        if (buf[2] == '$')
-            return 0;
-        s = buf + 2;
+        if (tokens[1][0] == '$')
+            return PARSE_ERROR_NONE;
+        d_ptr->text.append(buf.substr(2));
 #else
-        if (buf[2] != '$')
-            return 0;
-        s = buf + 3;
+        if (tokens[1][0] != '$')
+            return PARSE_ERROR_NONE;
+        d_ptr->text.append(buf.substr(3));
 #endif
-        d_ptr->text.append(s);
-    } else if (buf[0] == 'W') {
-        int min_lev, max_lev;
-        int min_plev, mode;
-        int min_alloc, max_chance;
-        int obj_good, obj_great;
-        int pit, nest;
-
-        if (10
-            != sscanf(buf + 2, "%d:%d:%d:%d:%d:%d:%d:%d:%x:%x", &min_lev, &max_lev, &min_plev, &mode, &min_alloc, &max_chance, &obj_good, &obj_great,
-                (unsigned int *)&pit, (unsigned int *)&nest))
-            return 1;
-
-        d_ptr->mindepth = (DEPTH)min_lev;
-        d_ptr->maxdepth = (DEPTH)max_lev;
-        d_ptr->min_plev = (PLAYER_LEVEL)min_plev;
-        d_ptr->mode = (BIT_FLAGS8)mode;
-        d_ptr->min_m_alloc_level = min_alloc;
-        d_ptr->max_m_alloc_chance = max_chance;
-        d_ptr->obj_good = obj_good;
-        d_ptr->obj_great = obj_great;
-        d_ptr->pit = (BIT_FLAGS16)pit;
-        d_ptr->nest = (BIT_FLAGS16)nest;
-    } else if (buf[0] == 'P') {
-        int dy, dx;
-        if (2 != sscanf(buf + 2, "%d:%d", &dy, &dx))
-            return 1;
-
-        d_ptr->dy = dy;
-        d_ptr->dx = dx;
-    } else if (buf[0] == 'L') {
-        char *zz[16];
-        if (tokenize(buf + 2, DUNGEON_FEAT_PROB_NUM * 2 + 1, zz, 0) != (DUNGEON_FEAT_PROB_NUM * 2 + 1))
-            return 1;
-
-        for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) {
-            d_ptr->floor[i].feat = f_tag_to_index(zz[i * 2]);
+    } else if (tokens[0] == "W") {
+        // W:min_level:max_level:(1):mode:(2):(3):(4):(5):prob_pit:prob_nest
+        // (1)minimum player level (unused)
+        // (2)minimum level of allocating monster
+        // (3)maximum probability of level boost of allocation monster
+        // (4)maximum probability of dropping good objects
+        // (5)maximum probability of dropping great objects
+        if (tokens.size() < 11)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(d_ptr->mindepth, tokens[1]);
+        info_set_value(d_ptr->maxdepth, tokens[2]);
+        info_set_value(d_ptr->min_plev, tokens[3]);
+        info_set_value(d_ptr->mode, tokens[4]);
+        info_set_value(d_ptr->min_m_alloc_level, tokens[5]);
+        info_set_value(d_ptr->max_m_alloc_chance, tokens[6]);
+        info_set_value(d_ptr->obj_good, tokens[7]);
+        info_set_value(d_ptr->obj_great, tokens[8]);
+        info_set_value(d_ptr->pit, tokens[9]);
+        info_set_value(d_ptr->nest, tokens[10]);
+    } else if (tokens[0] == "P") {
+        // P:wild_y:wild_x
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(d_ptr->dy, tokens[1]);
+        info_set_value(d_ptr->dx, tokens[2]);
+    } else if (tokens[0] == "L") {
+        // L:floor_1:prob_1:floor_2:prob_2:floor_3:prob_3:tunnel_prob
+        if (tokens.size() < DUNGEON_FEAT_PROB_NUM * 2 + 2)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        for (size_t i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) {
+            auto feat_idx = i * 2 + 1;
+            auto per_idx = feat_idx + 1;
+            d_ptr->floor[i].feat = f_tag_to_index(tokens[feat_idx]);
             if (d_ptr->floor[i].feat < 0)
                 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
 
-            d_ptr->floor[i].percent = (PERCENTAGE)atoi(zz[i * 2 + 1]);
+            info_set_value(d_ptr->floor[i].percent, tokens[per_idx]);
         }
 
-        d_ptr->tunnel_percent = atoi(zz[DUNGEON_FEAT_PROB_NUM * 2]);
-    } else if (buf[0] == 'A') {
-        char *zz[16];
-        if (tokenize(buf + 2, DUNGEON_FEAT_PROB_NUM * 2 + 4, zz, 0) != (DUNGEON_FEAT_PROB_NUM * 2 + 4))
-            return 1;
+        auto tunnel_idx = DUNGEON_FEAT_PROB_NUM * 2 + 1;
+        info_set_value(d_ptr->tunnel_percent, tokens[tunnel_idx]);
+    } else if (tokens[0] == "A") {
+        // A:wall_1:prob_1:wall_2:prob_2:wall_3:prob_3:outer_wall:inner_wall:stream_1:stream_2
+        if (tokens.size() < DUNGEON_FEAT_PROB_NUM * 2 + 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
         for (int i = 0; i < DUNGEON_FEAT_PROB_NUM; i++) {
-            d_ptr->fill[i].feat = f_tag_to_index(zz[i * 2]);
+            auto feat_idx = i * 2 + 1;
+            auto prob_idx = feat_idx + 1;
+            d_ptr->fill[i].feat = f_tag_to_index(tokens[feat_idx]);
             if (d_ptr->fill[i].feat < 0)
                 return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
 
-            d_ptr->fill[i].percent = (PERCENTAGE)atoi(zz[i * 2 + 1]);
+            info_set_value(d_ptr->fill[i].percent, tokens[prob_idx]);
         }
 
-        d_ptr->outer_wall = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2]);
+        auto idx = DUNGEON_FEAT_PROB_NUM * 2 + 1;
+        d_ptr->outer_wall = f_tag_to_index(tokens[idx++]);
         if (d_ptr->outer_wall < 0)
             return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
 
-        d_ptr->inner_wall = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 1]);
+        d_ptr->inner_wall = f_tag_to_index(tokens[idx++]);
         if (d_ptr->inner_wall < 0)
             return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
 
-        d_ptr->stream1 = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 2]);
+        d_ptr->stream1 = f_tag_to_index(tokens[idx++]);
         if (d_ptr->stream1 < 0)
             return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
 
-        d_ptr->stream2 = f_tag_to_index(zz[DUNGEON_FEAT_PROB_NUM * 2 + 3]);
+        d_ptr->stream2 = f_tag_to_index(tokens[idx]);
         if (d_ptr->stream2 < 0)
             return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
-    } else if (buf[0] == 'F') {
-        int artif = 0, monst = 0;
-
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while (*t == ' ' || *t == '|')
-                    t++;
-            }
-
-            if (1 == sscanf(s, "FINAL_ARTIFACT_%d", &artif)) {
-                d_ptr->final_artifact = (ARTIFACT_IDX)artif;
-                s = t;
+    } else if (tokens[0] == "F") {
+        // F:flags
+        if (tokens.size() < 2)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
                 continue;
-            }
 
-            if (1 == sscanf(s, "FINAL_OBJECT_%d", &artif)) {
-                d_ptr->final_object = (KIND_OBJECT_IDX)artif;
-                s = t;
-                continue;
-            }
-
-            if (1 == sscanf(s, "FINAL_GUARDIAN_%d", &monst)) {
-                d_ptr->final_guardian = (MONRACE_IDX)monst;
-                s = t;
-                continue;
+            const auto &f_tokens = str_split(f, '_');
+            if (f_tokens.size() == 3) {
+                if (f_tokens[0] == "FINAL" && f_tokens[1] == "ARTIFACT") {
+                    info_set_value(d_ptr->final_artifact, f_tokens[2]);
+                    continue;
+                }
+                if (f_tokens[0] == "FINAL" && f_tokens[1] == "OBJECT") {
+                    info_set_value(d_ptr->final_object, f_tokens[2]);
+                    continue;
+                }
+                if (f_tokens[0] == "FINAL" && f_tokens[1] == "GUARDIAN") {
+                    info_set_value(d_ptr->final_guardian, f_tokens[2]);
+                    continue;
+                }
+                if (f_tokens[0] == "MONSTER" && f_tokens[1] == "DIV") {
+                    info_set_value(d_ptr->special_div, f_tokens[2]);
+                    continue;
+                }
             }
 
-            if (1 == sscanf(s, "MONSTER_DIV_%d", &monst)) {
-                d_ptr->special_div = (PROB)monst;
-                s = t;
+            if (!grab_one_dungeon_flag(d_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
+        }
+    } else if (tokens[0] == "M") {
+        // M:monsterflags
+        if (tokens.size() < 2)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
                 continue;
-            }
-
-            if (0 != grab_one_dungeon_flag(d_ptr, s))
-                return 5;
 
-            s = t;
-        }
-    } else if (buf[0] == 'M') {
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while (*t == ' ' || *t == '|')
-                    t++;
-            }
+            const auto &m_tokens = str_split(f, '_');
+            if (m_tokens[0] == "R" && m_tokens[1] == "CHAR") {
+                if (m_tokens[2].size() > 4)
+                    return PARSE_ERROR_GENERIC;
 
-            if (!strncmp(s, "R_CHAR_", 7)) {
-                s += 7;
-                angband_strcpy(d_ptr->r_char, s, sizeof(d_ptr->r_char));
-                s = t;
+                strcpy(d_ptr->r_char, m_tokens[2].c_str());
                 continue;
             }
 
-            if (0 != grab_one_basic_monster_flag(d_ptr, s))
-                return 5;
-
-            s = t;
+            if (!grab_one_basic_monster_flag(d_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
         }
-    } else if (buf[0] == 'S') {
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while ((*t == ' ') || (*t == '|'))
-                    t++;
-            }
-
-            int i;
-            if (1 == sscanf(s, "1_IN_%d", &i)) {
-                s = t;
+    } else if (tokens[0] == "S") {
+        // S: flags
+        if (tokens.size() < 2)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
                 continue;
-            }
 
-            if (0 != grab_one_spell_monster_flag(d_ptr, s))
-                return 5;
+            const auto &s_tokens = str_split(f, '_');
+            if (s_tokens.size() == 3 && s_tokens[1] == "IN") {
+                if (s_tokens[0] != "1")
+                    return PARSE_ERROR_GENERIC;
+                continue; //!< r_info.txtからのコピペ対策
+            }
 
-            s = t;
+            if (!grab_one_spell_monster_flag(d_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
         }
-    } else {
-        return 6;
     }
+    else
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
     return 0;
 }
index 42c692b..4bd9988 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "system/angband.h"
-#include "info-reader/info-reader-util.h"
+#include <string_view>
 
-errr parse_d_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_d_info(std::string_view buf, angband_header *head);
index 95a6559..1eec870 100644 (file)
@@ -1,53 +1,55 @@
 #include "info-reader/ego-reader.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/kind-info-tokens-table.h"
+#include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
 #include "object-enchant/object-ego.h"
 #include "object-enchant/tr-types.h"
-#include "parse-error-types.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-#include <string>
-#include <utility>
 
 /*!
  * @brief テキストトークンを走査してフラグを一つ得る(エゴ用) /
  * Grab one flag in a ego-item_type from a textual string
  * @param e_ptr 保管先のエゴ構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーがあった場合1、エラーがない場合0を返す
+ * @return 見つけたらtrue
  */
 static bool grab_one_ego_item_flag(ego_item_type *e_ptr, std::string_view what)
 {
-    if (k_info_flags.find(what) != k_info_flags.end()) {
-        add_flag(e_ptr->flags, k_info_flags[what]);
-        return 0;
-    }
+    if (info_grab_one_flag(e_ptr->flags, k_info_flags, what))
+        return true;
 
     if (EnumClassFlagGroup<TRG>::grab_one_flag(e_ptr->gen_flags, k_info_gen_flags, what))
-        return 0;
+        return true;
 
-    msg_format(_("未知の名のあるアイテム・フラグ '%s'。", "Unknown ego-item flag '%s'."), what);
-    return 1;
+    msg_format(_("未知の名のあるアイテム・フラグ '%s'。", "Unknown ego-item flag '%s'."), what.data());
+    return false;
 }
 
+/*!
+ * @brief テキストトークンを走査して生成フラグを一つ得る(エゴ用) /
+ * Grab one genetation flag in a ego-item_type from a textual string
+ * @param e_ptr 保管先のエゴ構造体参照ポインタ
+ * @param what 参照元の文字列ポインタ
+ * @return 見つけたらtrue
+ */
 static bool grab_ego_generate_flags(ego_generate_type &xtra, std::string_view what)
 {
-    if (k_info_flags.find(what) != k_info_flags.end()) {
-        xtra.tr_flags.push_back(k_info_flags[what]);
-        return 0;
+    if (auto it = k_info_flags.find(what); it != k_info_flags.end()) {
+        xtra.tr_flags.push_back(it->second);
+        return true;
     }
 
-    auto it = k_info_gen_flags.find(what);
-    if (it != k_info_gen_flags.end()) {
+    if (auto it = k_info_gen_flags.find(what); it != k_info_gen_flags.end()) {
         xtra.trg_flags.push_back(it->second);
-        return false;
+        return true;
     }
 
-    return true;
+    return false;
 }
 
-
 /*!
  * @brief アイテムエゴ情報(e_info)のパース関数 /
  * Initialize the "e_info" array, by parsing an ascii "template" file
@@ -55,20 +57,19 @@ static bool grab_ego_generate_flags(ego_generate_type &xtra, std::string_view wh
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_e_info(char *buf, angband_header *head)
+errr parse_e_info(std::string_view buf, angband_header *head)
 {
     static ego_item_type *e_ptr = NULL;
-    auto line = std::string(buf);
-    auto tok = str_split(line, ':', false);
+    const auto &tokens = str_split(buf, ':', false, 10);
 
-    error_idx = 0;
+    error_idx = 0; //!< @note 順不同で登録しているため
 
-    if (tok[0] == "N") {
+    if (tokens[0] == "N") {
         // N:index:name_ja
-        if (tok[1].size() == 0)
+        if (tokens.size() < 3 || tokens[1].size() == 0)
             return PARSE_ERROR_GENERIC;
 
-        auto i = std::stoi(tok[1]);
+        auto i = std::stoi(tokens[1]);
         if (i < error_idx)
             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
@@ -77,87 +78,92 @@ errr parse_e_info(char *buf, angband_header *head)
         error_idx = i;
         e_ptr = &e_info[i];
 #ifdef JP
-        e_ptr->name = tok[2];
+        e_ptr->name = tokens[2];
 #endif
     } else if (!e_ptr)
         return PARSE_ERROR_MISSING_RECORD_HEADER;
-    else if (tok[0] == "E") {
+    else if (tokens[0] == "E") {
         // E:name_en
 #ifndef JP
-        if (tok[1].size() == 0)
-            return 1;
-        e_ptr->name = tok[1];
+        if (tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        e_ptr->name = tokens[1];
 #endif
-    }
-    else if (tok[0] == "X") {
+    } else if (tokens[0] == "X") {
         // X:slot:rating
-        if (tok.size() < 3)
+        if (tokens.size() < 3)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
-        e_ptr->slot = (INVENTORY_IDX)std::stoi(tok[1]);
-        e_ptr->rating = (PRICE)std::stoi(tok[2]);
-    } else if (tok[0] == "W") {
+
+        info_set_value(e_ptr->slot, tokens[1]);
+        info_set_value(e_ptr->rating, tokens[2]);
+    } else if (tokens[0] == "W") {
         // W:level:ratiry:xtra:cost
         // xtra is not used
-        if (tok.size() < 5)
+        if (tokens.size() < 5)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
-        e_ptr->level = (DEPTH)std::stoi(tok[1]);
-        e_ptr->rarity = (RARITY)std::stoi(tok[2]);
-        e_ptr->cost = (PRICE)std::stoi(tok[4]);
-    } else if (tok[0] == "B") {
+
+        info_set_value(e_ptr->level, tokens[1]);
+        info_set_value(e_ptr->rarity, tokens[2]);
+        info_set_value(e_ptr->cost, tokens[4]);
+    } else if (tokens[0] == "B") {
         // Base bonuses
         // B:to_hit:to_dam:to_ac
-        if (tok.size() < 4)
-            return 1;
-        e_ptr->base_to_h = (HIT_PROB)std::stoi(tok[1]);
-        e_ptr->base_to_d = (HIT_POINT)std::stoi(tok[2]);
-        e_ptr->base_to_a = (ARMOUR_CLASS)std::stoi(tok[3]);
-    } else if (tok[0] == "C") {
+        if (tokens.size() < 4)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(e_ptr->base_to_h, tokens[1]);
+        info_set_value(e_ptr->base_to_d, tokens[2]);
+        info_set_value(e_ptr->base_to_a, tokens[3]);
+    } else if (tokens[0] == "C") {
         // Creation bonuses (random plus)
         // C:to_hit:to_dam:to_ac:pval
-        if (tok.size() < 5)
+        if (tokens.size() < 5)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
-        e_ptr->max_to_h = (HIT_PROB)std::stoi(tok[1]);
-        e_ptr->max_to_d = (HIT_POINT)std::stoi(tok[2]);
-        e_ptr->max_to_a = (ARMOUR_CLASS)std::stoi(tok[3]);
-        e_ptr->max_pval = (PARAMETER_VALUE)std::stoi(tok[4]);
-    } else if (tok[0] == "U") {
+
+        info_set_value(e_ptr->max_to_h, tokens[1]);
+        info_set_value(e_ptr->max_to_d, tokens[2]);
+        info_set_value(e_ptr->max_to_a, tokens[3]);
+        info_set_value(e_ptr->max_pval, tokens[4]);
+    } else if (tokens[0] == "U") {
         // U:activation_flag
-        if (tok.size() < 2 || tok[1].size() == 0)
+        if (tokens.size() < 2 || tokens[1].size() == 0)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
-        auto n = grab_one_activation_flag(tok[1].c_str());
+
+        auto n = grab_one_activation_flag(tokens[1].c_str());
         if (n <= 0)
             return PARSE_ERROR_INVALID_FLAG;
+
         e_ptr->act_idx = (IDX)n;
-    } else if (tok[0] == "F") {
+    } else if (tokens[0] == "F") {
         // F:flags
-        if (tok.size() < 2 || tok[1].size() == 0)
-            return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        const auto& flags = str_split(tok[1], '|', true);
+        const auto& flags = str_split(tokens[1], '|', true, 10);
         for (const auto& f : flags) {
             if (f.size() == 0)
                 continue;
-            if (0 != grab_one_ego_item_flag(e_ptr, f))
+            if (!grab_one_ego_item_flag(e_ptr, f))
                 return PARSE_ERROR_INVALID_FLAG;
         }
-    } else if (tok[0] == "G") {
+    } else if (tokens[0] == "G") {
         // G:mul/dev:flags
-        if (tok.size() < 3)
-            return PARSE_ERROR_UNDEFINED_TERRAIN_TAG;
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        auto prob = str_split(tok[1], '/');
-        if (prob.size() != 2 || tok[1].size() == 0 || tok[2].size() == 0)
+        const auto &prob = str_split(tokens[1], '/', false, 2);
+        if (prob.size() != 2 || tokens[1].size() == 0 || tokens[2].size() == 0)
             return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
         ego_generate_type xtra;
         xtra.mul = std::stoi(prob[0]);
         xtra.dev = std::stoi(prob[1]);
 
-        const auto& flags = str_split(tok[2], '|', true);
+        const auto& flags = str_split(tokens[2], '|', true, 10);
         for (const auto& f : flags) {
             if (f.size() == 0)
                 continue;
-            if (grab_ego_generate_flags(xtra, f))
+            if (!grab_ego_generate_flags(xtra, f))
                 return PARSE_ERROR_INVALID_FLAG;
         }
 
index 9d33353..e3a46c7 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "system/angband.h"
-#include "parse-error-types.h"
-#include "info-reader/info-reader-util.h"
+#include <string_view>
 
-errr parse_e_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_e_info(std::string_view buf, angband_header *head);
index da0c85b..c33bf5e 100644 (file)
 #include "info-reader/feature-info-tokens-table.h"
 
 /*!
- * 地形属性トークンの定義 /
- * Feature info flags
+ * @brief 地形属性トークンの定義 / Feature info flags
  */
-concptr f_info_flags[NUM_F_FLAGS] = {
-    "LOS",
-    "PROJECT",
-    "MOVE",
-    "PLACE",
-    "DROP",
-    "SECRET",
-    "NOTICE",
-    "REMEMBER",
-    "OPEN",
-    "CLOSE",
-    "BASH",
-    "SPIKE",
-    "DISARM",
-    "STORE",
-    "TUNNEL",
-    "MAY_HAVE_GOLD",
-    "HAS_GOLD",
-    "HAS_ITEM",
-    "DOOR",
-    "TRAP",
-    "STAIRS",
-    "RUNE_PROTECTION",
-    "LESS",
-    "MORE",
-    "AVOID_RUN",
-    "FLOOR",
-    "WALL",
-    "PERMANENT",
-    "XXX00",
-    "XXX01",
-    "XXX02",
-    "HIT_TRAP",
+const std::unordered_map<std::string_view, feature_flag_type> f_info_flags = {
+    { "LOS", FF_LOS },
+    { "PROJECT", FF_PROJECT },
+    { "MOVE", FF_MOVE },
+    { "PLACE", FF_PLACE },
+    { "DROP", FF_DROP },
+    { "SECRET", FF_SECRET },
+    { "NOTICE", FF_NOTICE },
+    { "REMEMBER", FF_REMEMBER },
+    { "OPEN", FF_OPEN },
+    { "CLOSE", FF_CLOSE },
+    { "BASH", FF_BASH },
+    { "SPIKE", FF_SPIKE },
+    { "DISARM", FF_DISARM },
+    { "STORE", FF_STORE },
+    { "TUNNEL", FF_TUNNEL },
+    { "MAY_HAVE_GOLD", FF_MAY_HAVE_GOLD },
+    { "HAS_GOLD", FF_HAS_GOLD },
+    { "HAS_ITEM", FF_HAS_ITEM },
+    { "DOOR", FF_DOOR },
+    { "TRAP", FF_TRAP },
+    { "STAIRS", FF_STAIRS },
+    { "RUNE_PROTECTION", FF_RUNE_PROTECTION },
+    { "LESS", FF_LESS },
+    { "MORE", FF_MORE },
+    { "AVOID_RUN", FF_AVOID_RUN },
+    { "FLOOR", FF_FLOOR },
+    { "WALL", FF_WALL },
+    { "PERMANENT", FF_PERMANENT },
+    // { "XXX00", FF_XXX00 },
+    // { "XXX01", FF_XXX01 },
+    // { "XXX02", FF_XXX02 },
+    { "HIT_TRAP", FF_HIT_TRAP },
 
-    "BRIDGE",
-    "RIVER",
-    "LAKE",
-    "BRIDGED",
-    "COVERED",
-    "GLOW",
-    "ENSECRET",
-    "WATER",
-    "LAVA",
-    "SHALLOW",
-    "DEEP",
-    "POISON_PUDDLE",
-    "HURT_ROCK",
-    "HURT_FIRE",
-    "HURT_COLD",
-    "HURT_ACID",
-    "COLD_PUDDLE",
-    "ACID_PUDDLE",
-    "OIL",
-    "ELEC_PUDDLE",
-    "CAN_CLIMB",
-    "CAN_FLY",
-    "CAN_SWIM",
-    "CAN_PASS",
-    "CAN_OOZE",
-    "CAN_DIG",
-    "HIDE_ITEM",
-    "HIDE_SNEAK",
-    "HIDE_SWIM",
-    "HIDE_DIG",
-    "KILL_HUGE",
-    "KILL_MOVE",
+    // { "BRIDGE", FF_BRIDGE },
+    // { "RIVER", FF_RIVER },
+    // { "LAKE", FF_LAKE },
+    // { "BRIDGED", FF_BRIDGED },
+    // { "COVERED", FF_COVERED },
+    { "GLOW", FF_GLOW },
+    { "ENSECRET", FF_ENSECRET },
+    { "WATER", FF_WATER },
+    { "LAVA", FF_LAVA },
+    { "SHALLOW", FF_SHALLOW },
+    { "DEEP", FF_DEEP },
+    { "POISON_PUDDLE", FF_POISON_PUDDLE },
+    { "HURT_ROCK", FF_HURT_ROCK },
+    // { "HURT_FIRE", FF_HURT_FIRE },
+    // { "HURT_COLD", FF_HURT_COLD },
+    // { "HURT_ACID", FF_HURT_ACID },
+    { "COLD_PUDDLE", FF_COLD_PUDDLE },
+    { "ACID_PUDDLE", FF_ACID_PUDDLE },
+    // { "OIL", FF_OIL },
+    { "ELEC_PUDDLE", FF_ELEC_PUDDLE },
+    // { "CAN_CLIMB", FF_CAN_CLIMB },
+    { "CAN_FLY", FF_CAN_FLY },
+    { "CAN_SWIM", FF_CAN_SWIM },
+    { "CAN_PASS", FF_CAN_PASS },
+    // { "CAN_OOZE", FF_CAN_OOZE },
+    { "CAN_DIG", FF_CAN_DIG },
+    // { "HIDE_ITEM", FF_HIDE_ITEM },
+    // { "HIDE_SNEAK", FF_HIDE_SNEAK },
+    // { "HIDE_SWIM", FF_HIDE_SWIM },
+    // { "HIDE_DIG", FF_HIDE_DIG },
+    // { "KILL_HUGE", FF_KILL_HUGE },
+    // { "KILL_MOVE", FF_KILL_MOVE },
 
-    "PICK_TRAP",
-    "PICK_DOOR",
-    "ALLOC",
-    "CHEST",
-    "DROP_1D2",
-    "DROP_2D2",
-    "DROP_GOOD",
-    "DROP_GREAT",
-    "HURT_POIS",
-    "HURT_ELEC",
-    "HURT_WATER",
-    "HURT_BWATER",
-    "USE_FEAT",
-    "GET_FEAT",
-    "GROUND",
-    "OUTSIDE",
-    "EASY_HIDE",
-    "EASY_CLIMB",
-    "MUST_CLIMB",
-    "TREE",
-    "NEED_TREE",
-    "BLOOD",
-    "DUST",
-    "SLIME",
-    "PLANT",
-    "XXX2",
-    "INSTANT",
-    "EXPLODE",
-    "TIMED",
-    "ERUPT",
-    "STRIKE",
-    "SPREAD",
+    // { "PICK_TRAP", FF_PICK_TRAP },
+    // { "PICK_DOOR", FF_PICK_DOOR },
+    // { "ALLOC", FF_ALLOC },
+    // { "CHEST", FF_CHEST },
+    // { "DROP_1D2", FF_DROP_1D2 },
+    // { "DROP_2D2", FF_DROP_2D2 },
+    // { "DROP_GOOD", FF_DROP_GOOD },
+    // { "DROP_GREAT", FF_DROP_GREAT },
+    // { "HURT_POIS", FF_HURT_POIS },
+    // { "HURT_ELEC", FF_HURT_ELEC },
+    // { "HURT_WATER", FF_HURT_WATER },
+    // { "HURT_BWATER", FF_HURT_BWATER },
+    // { "USE_FEAT", FF_USE_FEAT },
+    // { "GET_FEAT", FF_GET_FEAT },
+    // { "GROUND", FF_GROUND },
+    // { "OUTSIDE", FF_OUTSIDE },
+    // { "EASY_HIDE", FF_EASY_HIDE },
+    // { "EASY_CLIMB", FF_EASY_CLIMB },
+    // { "MUST_CLIMB", FF_MUST_CLIMB },
+    { "TREE", FF_TREE },
+    // { "NEED_TREE", FF_NEED_TREE },
+    // { "BLOOD", FF_BLOOD },
+    // { "DUST", FF_DUST },
+    // { "SLIME", FF_SLIME },
+    { "PLANT", FF_PLANT },
+    // { "XXX2", FF_XXX2 },
+    // { "INSTANT", FF_INSTANT },
+    // { "EXPLODE", FF_EXPLODE },
+    // { "TIMED", FF_TIMED },
+    // { "ERUPT", FF_ERUPT },
+    // { "STRIKE", FF_STRIKE },
+    // { "SPREAD", FF_SPREAD },
 
-    "SPECIAL",
-    "HURT_DISI",
-    "QUEST_ENTER",
-    "QUEST_EXIT",
-    "QUEST",
-    "SHAFT",
-    "MOUNTAIN",
-    "BLDG",
-    "RUNE_EXPLOSION",
-    "PATTERN",
-    "TOWN",
-    "ENTRANCE",
-    "MIRROR",
-    "UNPERM",
-    "TELEPORTABLE",
-    "CONVERT",
-    "GLASS",
+    { "SPECIAL", FF_SPECIAL },
+    { "HURT_DISI", FF_HURT_DISI },
+    { "QUEST_ENTER", FF_QUEST_ENTER },
+    { "QUEST_EXIT", FF_QUEST_EXIT },
+    { "QUEST", FF_QUEST },
+    { "SHAFT", FF_SHAFT },
+    { "MOUNTAIN", FF_MOUNTAIN },
+    { "BLDG", FF_BLDG },
+    { "RUNE_EXPLOSION", FF_RUNE_EXPLOSION },
+    { "PATTERN", FF_PATTERN },
+    { "TOWN", FF_TOWN },
+    { "ENTRANCE", FF_ENTRANCE },
+    { "MIRROR", FF_MIRROR },
+    { "UNPERM", FF_UNPERM },
+    { "TELEPORTABLE", FF_TELEPORTABLE },
+    { "CONVERT", FF_CONVERT },
+    { "GLASS", FF_GLASS },
 };
index ac95d3c..ec0ae4d 100644 (file)
@@ -1,6 +1,8 @@
 #pragma once
 
 #include "system/angband.h"
+#include "grid/feature-flag-types.h"
+#include <string_view>
+#include <unordered_map>
 
-#define NUM_F_FLAGS 113
-extern concptr f_info_flags[NUM_F_FLAGS];
+extern const std::unordered_map<std::string_view, feature_flag_type> f_info_flags;
index 73a8a5c..877d422 100644 (file)
@@ -4,6 +4,7 @@
 #include "grid/grid.h"
 #include "grid/trap.h"
 #include "info-reader/feature-info-tokens-table.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
 #include "room/door-definition.h"
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-#include <string>
-#include <string_view>
 
-/*! 地形タグ情報から地形IDを得られなかった場合にTRUEを返す */
-static bool feat_tag_is_not_found = FALSE;
+/*! 地形タグ情報から地形IDを得られなかった場合にtrueを返す */
+static bool feat_tag_is_not_found = false;
 
 /*!
  * @brief テキストトークンを走査してフラグを一つ得る(地形情報向け) /
  * Grab one flag in an feature_type from a textual string
  * @param f_ptr 地形情報を保管する先の構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_feat_flag(feature_type *f_ptr, concptr what)
+static bool grab_one_feat_flag(feature_type *f_ptr, std::string_view what)
 {
-    for (int i = 0; i < FF_FLAG_MAX; i++) {
-        if (streq(what, f_info_flags[i])) {
-            add_flag(f_ptr->flags, i);
-            return 0;
-        }
-    }
+    if (info_grab_one_flag(f_ptr->flags, f_info_flags, what))
+        return true;
 
-    msg_format(_("未知の地形フラグ '%s'。", "Unknown feature flag '%s'."), what);
-    return PARSE_ERROR_GENERIC;
+    msg_format(_("未知の地形フラグ '%s'。", "Unknown feature flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -43,19 +38,17 @@ static errr grab_one_feat_flag(feature_type *f_ptr, concptr what)
  * @param f_ptr 地形情報を保管する先の構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
  * @param count ステートの保存先ID
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_feat_action(feature_type *f_ptr, concptr what, int count)
+static bool grab_one_feat_action(feature_type *f_ptr, std::string_view what, int count)
 {
-    for (FF_FLAGS_IDX i = 0; i < FF_FLAG_MAX; i++) {
-        if (streq(what, f_info_flags[i])) {
-            f_ptr->state[count].action = i;
-            return 0;
-        }
+    if (auto it = f_info_flags.find(what); it != f_info_flags.end()) {
+        f_ptr->state[count].action = static_cast<FF_FLAGS_IDX>(it->second);
+        return true;
     }
 
-    msg_format(_("未知の地形アクション '%s'。", "Unknown feature action '%s'."), what);
-    return PARSE_ERROR_GENERIC;
+    msg_format(_("未知の地形アクション '%s'。", "Unknown feature action '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -65,172 +58,162 @@ static errr grab_one_feat_action(feature_type *f_ptr, concptr what, int count)
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_f_info(char *buf, angband_header *head)
+errr parse_f_info(std::string_view buf, angband_header *head)
 {
     static feature_type *f_ptr = NULL;
-    int i;
-    char *s, *t;
-    if (buf[0] == 'N') {
-        s = angband_strchr(buf + 2, ':');
+    const auto &tokens = str_split(buf, ':', false, 10);
 
-        if (s) {
-            *s++ = '\0';
-        }
+    if (tokens[0] == "N") {
+        // N:index:tag
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        if (tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_GENERIC;
 
-        i = atoi(buf + 2);
-        if (i <= error_idx)
-            return 4;
+        auto i = std::stoi(tokens[1]);
+        if (i < error_idx)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         f_ptr = &f_info[i];
-        if (s) {
-            f_ptr->tag = std::string(s);
-        }
+        f_ptr->tag = tokens[2];
 
         f_ptr->mimic = (FEAT_IDX)i;
         f_ptr->destroyed = (FEAT_IDX)i;
         for (i = 0; i < MAX_FEAT_STATES; i++)
             f_ptr->state[i].action = FF_FLAG_MAX;
-    } else if (!f_ptr) {
-        return 3;
-    }
-#ifdef JP
-    else if (buf[0] == 'J') {
-        f_ptr->name = std::string(buf + 2);
-    } else if (buf[0] == 'E') {
-    }
-#else
-    else if (buf[0] == 'J') {
-    } else if (buf[0] == 'E') {
-        f_ptr->name = std::string(buf + 2);
-    }
-#endif
-    else if (buf[0] == 'M') {
-        f_ptr->mimic_tag = std::string(buf + 2);
-    } else if (buf[0] == 'G') {
-        int j;
-        byte s_attr;
-        char char_tmp[F_LIT_MAX];
-        if (buf[1] != ':')
-            return 1;
-        if (!buf[2])
-            return 1;
-        if (buf[3] != ':')
-            return 1;
-        if (!buf[4])
-            return 1;
-
-        char_tmp[F_LIT_STANDARD] = buf[2];
-        s_attr = color_char_to_attr(buf[4]);
+
+    } else if (!f_ptr)
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if (tokens[0] == _("J", "E")) {
+        // J:name_ja
+        // E:name_en
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        f_ptr->name = tokens[1];
+    } else if (tokens[0] == _("E", "J")) {
+        //pass
+    } else if (tokens[0] == "M") {
+        // M:mimic_tag
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        f_ptr->mimic_tag = tokens[1];
+    } else if (tokens[0] == "G") {
+        // G:symbol:color:lite:lite_symbol:lite_color:dark_symbol:dark_color
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        size_t n;
+        char s_char;
+        if (tokens[1].size() == 1) {
+            s_char = tokens[1][0];
+            n = 2;
+        } else if (tokens[1].size() == 0 && tokens[2].size() == 0) {
+            if (tokens.size() < 4)
+                return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+            s_char = ':';
+            n = 3;
+        } else
+            return PARSE_ERROR_GENERIC;
+
+        auto s_attr = color_char_to_attr(tokens[n++][0]);
         if (s_attr > 127)
-            return 1;
+            return PARSE_ERROR_GENERIC;
 
+        f_ptr->d_char[F_LIT_STANDARD] = s_char;
         f_ptr->d_attr[F_LIT_STANDARD] = s_attr;
-        f_ptr->d_char[F_LIT_STANDARD] = char_tmp[F_LIT_STANDARD];
-        if (buf[5] == ':') {
+        if (tokens.size() == n) {
+            for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
+                f_ptr->d_char[j] = s_char;
+                f_ptr->d_attr[j] = s_attr;
+            }
+        } else if (tokens[n++] == "LIT") {
             apply_default_feat_lighting(f_ptr->d_attr, f_ptr->d_char);
-            if (!streq(buf + 6, "LIT")) {
-                char attr_lite_tmp[F_LIT_MAX - F_LIT_NS_BEGIN];
-
-                if ((F_LIT_MAX - F_LIT_NS_BEGIN) * 2
-                    != sscanf(buf + 6, "%c:%c:%c:%c", &char_tmp[F_LIT_LITE], &attr_lite_tmp[F_LIT_LITE - F_LIT_NS_BEGIN], &char_tmp[F_LIT_DARK],
-                        &attr_lite_tmp[F_LIT_DARK - F_LIT_NS_BEGIN]))
-                    return 1;
-                if (buf[F_LIT_MAX * 4 + 1])
-                    return 1;
-
-                for (j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
-                    switch (attr_lite_tmp[j - F_LIT_NS_BEGIN]) {
-                    case '*':
-                        /* Use default lighting */
-                        break;
-                    case '-':
-                        /* No lighting support */
-                        f_ptr->d_attr[j] = f_ptr->d_attr[F_LIT_STANDARD];
-                        break;
-                    default:
-                        /* Extract the color */
-                        f_ptr->d_attr[j] = color_char_to_attr(attr_lite_tmp[j - F_LIT_NS_BEGIN]);
-                        if (f_ptr->d_attr[j] > 127)
-                            return 1;
-                        break;
-                    }
-                    f_ptr->d_char[j] = char_tmp[j];
+
+            for (int j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
+                auto c_idx = n + (j - F_LIT_NS_BEGIN) * 2;
+                auto a_idx = c_idx + 1;
+                if (tokens.size() <= (size_t)a_idx)
+                    continue;
+                if (tokens[c_idx].size() != 1 || tokens[a_idx].size() != 1)
+                    continue;
+
+                f_ptr->d_char[j] = tokens[c_idx][0];
+
+                if (tokens[a_idx] == "*") {
+                    // pass
+                } else if (tokens[a_idx] == "-") {
+                    f_ptr->d_attr[j] = s_attr;
+                } else {
+                    f_ptr->d_attr[j] = color_char_to_attr(tokens[a_idx][0]);
+                    if (f_ptr->d_attr[j] > 127)
+                        return PARSE_ERROR_GENERIC;
                 }
             }
-        } else if (!buf[5]) {
-            for (j = F_LIT_NS_BEGIN; j < F_LIT_MAX; j++) {
-                f_ptr->d_attr[j] = s_attr;
-                f_ptr->d_char[j] = char_tmp[F_LIT_STANDARD];
-            }
         } else
-            return 1;
-    } else if (buf[0] == 'F') {
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while (*t == ' ' || *t == '|')
-                    t++;
-            }
-
-            if (1 == sscanf(s, "SUBTYPE_%d", &i)) {
-                f_ptr->subtype = (FEAT_SUBTYPE)i;
-                s = t;
-
+            return PARSE_ERROR_GENERIC;
+    } else if (tokens[0] == "F") {
+        // F:flags
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true, 10);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
                 continue;
-            }
 
-            if (1 == sscanf(s, "POWER_%d", &i)) {
-                f_ptr->power = (FEAT_POWER)i;
-                s = t;
-                continue;
+            const auto &f_tokens = str_split(f, '_', false, 2);
+            if (f_tokens.size() == 2) {
+                if (f_tokens[0] == "SUBTYPE") {
+                    info_set_value(f_ptr->subtype, f_tokens[1]);
+                    continue;
+                } else if (f_tokens[0] == "POWER") {
+                    info_set_value(f_ptr->power, f_tokens[1]);
+                    continue;
+                }
             }
 
-            if (0 != grab_one_feat_flag(f_ptr, s))
-                return (PARSE_ERROR_INVALID_FLAG);
-
-            s = t;
+            if (!grab_one_feat_flag(f_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
         }
-    } else if (buf[0] == 'W') {
-        int priority;
-        if (1 != sscanf(buf + 2, "%d", &priority))
-            return (PARSE_ERROR_GENERIC);
-        f_ptr->priority = (FEAT_PRIORITY)priority;
-    } else if (buf[0] == 'K') {
-        for (i = 0; i < MAX_FEAT_STATES; i++)
+    } else if (tokens[0] == "W") {
+        // W:priority
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        info_set_value(f_ptr->priority, tokens[1]);
+    } else if (tokens[0] == "K") {
+        // K:state:feat
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        if (tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        int i = 0;
+        for (; i < MAX_FEAT_STATES; i++) {
             if (f_ptr->state[i].action == FF_FLAG_MAX)
                 break;
+        }
 
         if (i == MAX_FEAT_STATES)
             return PARSE_ERROR_GENERIC;
 
-        /* loop */
-        for (s = t = buf + 2; *t && (*t != ':'); t++)
-            ;
-
-        if (*t == ':')
-            *t++ = '\0';
-
-        if (streq(s, "DESTROYED")) {
-            f_ptr->destroyed_tag = std::string(t);
-        } else {
+        if (tokens[1] == "DESTROYED")
+            f_ptr->destroyed_tag = tokens[2];
+        else {
             f_ptr->state[i].action = 0;
-            if (0 != grab_one_feat_action(f_ptr, s, i))
+            if (!grab_one_feat_action(f_ptr, tokens[1], i))
                 return PARSE_ERROR_INVALID_FLAG;
 
-            f_ptr->state[i].result_tag = std::string(t);
+            f_ptr->state[i].result_tag = tokens[2];
         }
-    } else {
-        return 6;
-    }
+    } else
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
-    return 0;
+    return PARSE_ERROR_NONE;
 }
 
 /*!
@@ -393,12 +376,11 @@ errr init_feat_variables(void)
  * @param str タグ文字列
  * @return 地形ID
  */
-s16b f_tag_to_index(concptr str)
+FEAT_IDX f_tag_to_index(std::string_view str)
 {
-    for (u16b i = 0; i < f_head.info_num; i++) {
-        if (streq(f_info[i].tag.c_str(), str)) {
-            return (s16b)i;
-        }
+    for (size_t i = 0; i < f_head.info_num; i++) {
+        if (f_info[i].tag == str)
+            return (FEAT_IDX)i;
     }
 
     return -1;
index b79952e..c944eb8 100644 (file)
@@ -1,10 +1,11 @@
 #pragma once
 
 #include "system/angband.h"
-#include "info-reader/info-reader-util.h"
+#include <string_view>
 
-errr parse_f_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_f_info(std::string_view buf, angband_header *head);
 errr init_feat_variables(void);
-s16b f_tag_to_index(concptr str);
+FEAT_IDX f_tag_to_index(std::string_view str);
 s16b f_tag_to_index_in_init(concptr str);
 void retouch_f_info(angband_header *head);
index 6521193..ef6eaea 100644 (file)
@@ -2,6 +2,7 @@
 #include "dungeon/quest.h"
 #include "grid/feature.h"
 #include "info-reader/feature-reader.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "info-reader/random-grid-effect-types.h"
 #include "io/tokenizer.h"
@@ -15,6 +16,7 @@
 #include "system/system-variables.h"
 #include "util/angband-files.h"
 #include "util/string-processor.h"
+#include <string>
 
 dungeon_grid letter[255];
 
@@ -27,7 +29,7 @@ dungeon_grid letter[255];
  * @param parse_info_txt_line パース関数
  * @return エラーコード
  */
-errr init_info_txt(FILE *fp, char *buf, angband_header *head, parse_info_txt_func parse_info_txt_line)
+errr init_info_txt(FILE *fp, char *buf, angband_header *head, std::function<errr(std::string_view, angband_header *)> parse_info_txt_line)
 {
     error_idx = -1;
     error_line = 0;
@@ -53,7 +55,7 @@ errr init_info_txt(FILE *fp, char *buf, angband_header *head, parse_info_txt_fun
             }
         }
 
-        if ((err = (*parse_info_txt_line)(buf, head)) != 0)
+        if ((err = parse_info_txt_line(buf, head)) != 0)
             return (err);
     }
 
index f4aefa5..7de2fe3 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "system/angband.h"
+#include <string_view>
 
 enum parse_error_type : int;
 
@@ -18,9 +19,9 @@ typedef struct dungeon_grid {
 
 extern dungeon_grid letter[255];
 
-typedef struct angband_header angband_header;
-typedef struct floor_type floor_type;
-typedef errr (*parse_info_txt_func)(char *buf, angband_header *head);
-errr init_info_txt(FILE *fp, char *buf, angband_header *head, parse_info_txt_func parse_info_txt_line);
+struct angband_header;
+struct floor_type;
+
+errr init_info_txt(FILE *fp, char *buf, angband_header *head, std::function<errr(std::string_view, angband_header *)> parse_info_txt_line);
 parse_error_type parse_line_feature(floor_type *floor_ptr, char *buf);
 parse_error_type parse_line_building(char *buf);
index 1248278..845a0c4 100644 (file)
@@ -8,26 +8,6 @@ int error_idx; /*!< データ読み込み/初期化時に汎用的にエラー
 int error_line; /*!< データ読み込み/初期化時に汎用的にエラー行数を保存するグローバル変数 */
 
 /*!
- * @brief テキストトークンを走査してフラグを一つ得る(汎用) /
- * Grab one flag from a textual string
- * @param flags ビットフラグを追加する先の参照ポインタ
- * @param names トークン定義配列
- * @param what 参照元の文字列ポインタ
- * @return エラーコード
- */
-errr grab_one_flag(u32b *flags, concptr names[], concptr what)
-{
-    for (int i = 0; i < 32; i++) {
-        if (streq(what, names[i])) {
-            *flags |= (1UL << i);
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
-/*!
  * @brief テキストトークンを走査してフラグを一つ得る(発動能力用) /
  * Grab one activation index flag
  * @param what 参照元の文字列ポインタ
index 08ade59..7f2a282 100644 (file)
@@ -1,13 +1,62 @@
 #pragma once
 
 #include "system/angband.h"
+#include "util/bit-flags-calculator.h"
+#include <string>
+#include <string_view>
+#include <unordered_map>
 
 /*
  * Size of memory reserved for initialization of some arrays
  */
-extern int error_idx;
-extern int error_line;
+extern int error_idx; //!< エラーが発生したinfo ID
+extern int error_line; //!< エラーが発生した行
 
-typedef struct angband_header angband_header;
-errr grab_one_flag(u32b *flags, concptr names[], concptr what);
 byte grab_one_activation_flag(concptr what);
+
+using sview = std::string_view;
+
+/*!
+ * @brief infoフラグ文字列をフラグビットに変換する
+ * @param flags ビットフラグ変数
+ * @param names フラグ文字列変換表
+ * @param what フラグ文字列
+ * @return 見つけたらtrue
+ */
+template <typename T>
+bool info_grab_one_flag(u32b &flags, const std::unordered_map<sview, T> &names, sview what)
+{
+    if (auto it = names.find(what); it != names.end()) {
+        set_bits(flags, it->second);
+        return true;
+    }
+    return false;
+}
+
+/*!
+ * @brief infoフラグ文字列をフラグビットに変換する
+ * @param flags ビットフラグ配列
+ * @param names フラグ文字列変換表
+ * @param what フラグ文字列
+ * @return 見つけたらtrue
+ */
+template <typename T>
+bool info_grab_one_flag(u32b *flags, const std::unordered_map<sview, T> &names, sview what)
+{
+    if (auto it = names.find(what); it != names.end()) {
+        add_flag(flags, it->second);
+        return true;
+    }
+    return false;
+}
+
+/*!
+ * @brief infoパラメータに値をセットする
+ * @param パラメータ変数
+ * @val 値
+ */
+template <typename T>
+void info_set_value(T &arg, const std::string &val)
+{
+    arg = static_cast<T>(std::stoi(val));
+}
index 2d059e0..44ff2b9 100644 (file)
@@ -5,7 +5,7 @@
  * オブジェクト基本特性トークンの定義 /
  * Object flags
  */
-std::unordered_map<std::string_view, tr_type> k_info_flags = {
+const std::unordered_map<std::string_view, tr_type> k_info_flags = {
     { "STR", TR_STR },
     { "INT", TR_INT },
     { "WIS", TR_WIS },
@@ -176,7 +176,7 @@ std::unordered_map<std::string_view, tr_type> k_info_flags = {
  * オブジェクト生成特性トークンの定義 /
  * Object flags
  */
-std::unordered_map<std::string_view, TRG> k_info_gen_flags = {
+const std::unordered_map<std::string_view, TRG> k_info_gen_flags = {
     { "INSTA_ART", TRG::INSTA_ART },
     { "QUESTITEM", TRG::QUESTITEM },
     { "XTRA_POWER", TRG::XTRA_POWER },
index aa79c3a..ec3f521 100644 (file)
@@ -3,8 +3,8 @@
 #include "system/angband.h"
 #include "object-enchant/tr-types.h"
 #include "object-enchant/trg-types.h"
-#include <string>
+#include <string_view>
 #include <unordered_map>
 
-extern std::unordered_map<std::string_view, tr_type> k_info_flags;
-extern std::unordered_map<std::string_view, TRG> k_info_gen_flags;
+extern const std::unordered_map<std::string_view, tr_type> k_info_flags;
+extern const std::unordered_map<std::string_view, TRG> k_info_gen_flags;
index ac4d822..fbfcaf8 100644 (file)
@@ -1,5 +1,7 @@
 #include "info-reader/kind-reader.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/kind-info-tokens-table.h"
+#include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
 #include "object-enchant/tr-types.h"
 #include "object/object-kind.h"
@@ -7,27 +9,24 @@
 #include "util/bit-flags-calculator.h"
 #include "util/string-processor.h"
 #include "view/display-messages.h"
-#include <string>
 
 /*!
  * @brief テキストトークンを走査してフラグを一つ得る(ベースアイテム用) /
  * Grab one flag in an object_kind from a textual string
  * @param k_ptr 保管先のベースアイテム構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_kind_flag(object_kind *k_ptr, concptr what)
+static bool grab_one_kind_flag(object_kind *k_ptr, std::string_view what)
 {
-    if (k_info_flags.find(what) != k_info_flags.end()) {
-        add_flag(k_ptr->flags, k_info_flags[what]);
-        return 0;
-    }
+    if (info_grab_one_flag(k_ptr->flags, k_info_flags, what))
+        return true;
 
     if (EnumClassFlagGroup<TRG>::grab_one_flag(k_ptr->gen_flags, k_info_gen_flags, what))
-        return 0;
+        return true;
 
-    msg_format(_("未知のアイテム・フラグ '%s'。", "Unknown object flag '%s'."), what);
-    return 1;
+    msg_format(_("未知のアイテム・フラグ '%s'。", "Unknown object flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -37,163 +36,136 @@ static errr grab_one_kind_flag(object_kind *k_ptr, concptr what)
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_k_info(char *buf, angband_header *head)
+errr parse_k_info(std::string_view buf, angband_header *head)
 {
     static object_kind *k_ptr = NULL;
+    const auto &tokens = str_split(buf, ':', false, 10);
 
-    char *s, *t;
-    if (buf[0] == 'N') {
-#ifdef JP
-        char *flavor;
-#endif
-        s = angband_strchr(buf + 2, ':');
-        if (!s)
-            return 1;
-
-        *s++ = '\0';
-        int i = atoi(buf + 2);
+    if (tokens[0] == "N") {
+        // N:index:name_ja
+        if (tokens.size() < 3 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        if (i <= error_idx)
-            return 4;
+        auto i = std::stoi(tokens[1]);
+        if (i < error_idx)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         k_ptr = &k_info[i];
-
 #ifdef JP
-        if (!*s)
-            return 1;
-
-        flavor = angband_strchr(s, ':');
-        if (flavor) {
-            *flavor++ = '\0';
-            k_ptr->flavor_name = std::string(flavor);
-        }
-
-        k_ptr->name = std::string(s);
+        k_ptr->name = tokens[2];
 #endif
-    } else if (!k_ptr) {
-        return 3;
-    }
-#ifdef JP
-    /* 英語名を読むルーチンを追加 */
-    /* 'E' から始まる行は英語名としている */
-    else if (buf[0] == 'E') {
-        /* nothing to do */
-    }
-#else
-    else if (buf[0] == 'E') {
-        char *flavor;
-        s = buf + 2;
-        flavor = angband_strchr(s, ':');
-        if (flavor) {
-            *flavor++ = '\0';
-            k_ptr->flavor_name = std::string(flavor);
-        }
-
-        k_ptr->name = std::string(s);
-    }
+        if (tokens.size() > 3)
+            k_ptr->flavor_name = tokens[3];
+
+    } else if (!k_ptr)
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if (tokens[0] == "E") {
+        // E:name_en
+#ifndef JP
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        k_ptr->name = tokens[1];
+
+        if (tokens.size() > 2)
+            k_ptr->flavor_name = tokens[2];
 #endif
-    else if (buf[0] == 'D') {
+    } else if (tokens[0] == "D") {
+        // D:text_ja
+        // D:$text_en
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 #ifdef JP
-        if (buf[2] == '$')
-            return 0;
-        s = buf + 2;
+        if (tokens[1][0] == '$')
+            return PARSE_ERROR_NONE;
+        k_ptr->text.append(buf.substr(2));
 #else
-        if (buf[2] != '$')
-            return 0;
-        s = buf + 3;
+        if (tokens[1][0] != '$')
+            return PARSE_ERROR_NONE;
+        k_ptr->text.append(buf.substr(3));
 #endif
-        k_ptr->text.append(s);
-    } else if (buf[0] == 'G') {
-        char sym;
-        byte tmp;
-        if (buf[1] != ':')
-            return 1;
-        if (!buf[2])
-            return 1;
-        if (buf[3] != ':')
-            return 1;
-        if (!buf[4])
-            return 1;
-
-        sym = buf[2];
-        tmp = color_char_to_attr(buf[4]);
-        if (tmp > 127)
-            return 1;
-
-        k_ptr->d_attr = tmp;
-        k_ptr->d_char = sym;
-    } else if (buf[0] == 'I') {
-        int tval, sval, pval;
-        if (3 != sscanf(buf + 2, "%d:%d:%d", &tval, &sval, &pval))
-            return 1;
-
-        k_ptr->tval = (tval_type)tval;
-        k_ptr->sval = (OBJECT_SUBTYPE_VALUE)sval;
-        k_ptr->pval = (PARAMETER_VALUE)pval;
-    } else if (buf[0] == 'W') {
-        int level, extra, wgt;
-        long cost;
-        if (4 != sscanf(buf + 2, "%d:%d:%d:%ld", &level, &extra, &wgt, &cost))
-            return 1;
-
-        k_ptr->level = (DEPTH)level;
-        k_ptr->extra = (BIT_FLAGS8)extra;
-        k_ptr->weight = (WEIGHT)wgt;
-        k_ptr->cost = (PRICE)cost;
-    } else if (buf[0] == 'A') {
-        int i = 0;
-        for (s = buf + 1; s && (s[0] == ':') && s[1]; ++i) {
-            k_ptr->chance[i] = 1;
-            k_ptr->locale[i] = atoi(s + 1);
-            t = angband_strchr(s + 1, '/');
-            s = angband_strchr(s + 1, ':');
-            if (t && (!s || t < s)) {
-                int chance = atoi(t + 1);
-                if (chance > 0)
-                    k_ptr->chance[i] = (PROB)chance;
-            }
-        }
-    } else if (buf[0] == 'P') {
-        int ac, hd1, hd2, th, td, ta;
-        if (6 != sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &ac, &hd1, &hd2, &th, &td, &ta))
-            return 1;
-
-        k_ptr->ac = (ARMOUR_CLASS)ac;
-        k_ptr->dd = (DICE_NUMBER)hd1;
-        k_ptr->ds = (DICE_SID)hd2;
-        k_ptr->to_h = (HIT_PROB)th;
-        k_ptr->to_d = (HIT_POINT)td;
-        k_ptr->to_a = (ARMOUR_CLASS)ta;
-    } else if (buf[0] == 'U') {
-        byte n;
-        n = grab_one_activation_flag(buf + 2);
-        if (n > 0) {
-            k_ptr->act_idx = n;
-        } else {
-            return 5;
+    } else if (tokens[0] == "G") {
+        // G:color:symbol
+        if (tokens.size() < 3 || tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        auto a = color_char_to_attr(tokens[2][0]);
+        if (a > 127)
+            return PARSE_ERROR_GENERIC;
+
+        k_ptr->d_attr = a;
+        k_ptr->d_char = tokens[1][0];
+    } else if (tokens[0] == "I") {
+        // I:tval:sval:pval
+        if (tokens.size() < 4)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(k_ptr->tval, tokens[1]);
+        info_set_value(k_ptr->sval, tokens[2]);
+        info_set_value(k_ptr->pval, tokens[3]);
+    } else if (tokens[0] == "W") {
+        // W:level:extra:weight:cost
+        if (tokens.size() < 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(k_ptr->level, tokens[1]);
+        info_set_value(k_ptr->extra, tokens[2]);
+        info_set_value(k_ptr->weight, tokens[3]);
+        info_set_value(k_ptr->cost, tokens[4]);
+    } else if (tokens[0] == "A") {
+        // A:level/chance(:level/chance:level/chance:level/chance)
+        if (tokens.size() < 2 || tokens.size() > 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        auto i = 0;
+        for (auto t = tokens.begin() + 1; t != tokens.end(); t++) {
+            const auto &rarity = str_split(*t, '/', false, 2);
+            if (rarity.size() != 2 || rarity[0].size() == 0 || rarity[1].size() == 0)
+                return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
+            info_set_value(k_ptr->locale[i], rarity[0]);
+            info_set_value(k_ptr->chance[i], rarity[1]);
+            i++;
         }
-    } else if (buf[0] == 'F') {
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while (*t == ' ' || *t == '|')
-                    t++;
-            }
-
-            if (0 != grab_one_kind_flag(k_ptr, s))
-                return 5;
-            s = t;
+    } else if (tokens[0] == "P") {
+        // P:ac:dd:ds:to_h:to_d:to_a
+        if (tokens.size() < 6)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &dice = str_split(tokens[2], 'd', false, 2);
+        if (dice.size() != 2)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
+
+        info_set_value(k_ptr->ac, tokens[1]);
+        info_set_value(k_ptr->dd, dice[0]);
+        info_set_value(k_ptr->ds, dice[1]);
+        info_set_value(k_ptr->to_h, tokens[3]);
+        info_set_value(k_ptr->to_d, tokens[4]);
+        info_set_value(k_ptr->to_a, tokens[5]);
+    } else if (tokens[0] == "U") {
+        // U:activation_flag
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        auto n = grab_one_activation_flag(tokens[1].c_str());
+        if (n <= 0)
+            return PARSE_ERROR_INVALID_FLAG;
+
+        k_ptr->act_idx = (IDX)n;
+    } else if (tokens[0] == "F") {
+        // F:flags
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true, 10);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
+                continue;
+            if (!grab_one_kind_flag(k_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
         }
-    } else {
-        return 6;
-    }
+    } else
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
-    return 0;
+    return PARSE_ERROR_NONE;
 }
index 774cd61..e960099 100644 (file)
@@ -1,6 +1,7 @@
-#pragma once
+#pragma once
 
 #include "system/angband.h"
-#include "info-reader/info-reader-util.h"
+#include <string_view>
 
-errr parse_k_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_k_info(std::string_view buf, angband_header *head);
index a09189b..a8d7d76 100644 (file)
@@ -1,9 +1,36 @@
 #include "info-reader/magic-reader.h"
+#include "info-reader/info-reader-util.h"
+#include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
 #include "player-ability/player-ability-types.h"
 #include "player/player-class.h"
 #include "util/string-processor.h"
 
+namespace {
+/*!
+ * @brief 魔法タイプ名とtvalの対応表
+ */
+const std::unordered_map<std::string_view, tval_type> name_to_tval = {
+    { "SORCERY", TV_SORCERY_BOOK },
+    { "LIFE", TV_LIFE_BOOK },
+    { "MUSIC", TV_MUSIC_BOOK },
+    { "HISSATSU", TV_HISSATSU_BOOK },
+    { "NONE", TV_NONE },
+};
+
+/*!
+ * @brief 魔法必須能力とenumの対応表
+ */
+const std::unordered_map<std::string_view, int> name_to_stat = {
+    { "STR", A_STR },
+    { "INT", A_INT },
+    { "WIS", A_WIS },
+    { "DEX", A_DEX },
+    { "CON", A_CON },
+    { "CHR", A_CHR },
+};
+}
+
 /*!
  * @brief 職業魔法情報(m_info)のパース関数 /
  * Initialize the "m_info" array, by parsing an ascii "template" file
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_m_info(char *buf, angband_header *head)
+errr parse_m_info(std::string_view buf, angband_header *head)
 {
     static player_magic *m_ptr = NULL;
     static int realm, magic_idx = 0, readable = 0;
+    const auto &tokens = str_split(buf, ':', false, 7);
 
-    if (buf[0] == 'N') {
-        int i = atoi(buf + 2);
+    if (tokens[0] == "N") {
+        // N:class-index
+        if (tokens.size() < 2 && tokens[1].size() == 0)
+            return PARSE_ERROR_GENERIC;
 
-        if (i <= error_idx)
-            return 4;
+        auto i = std::stoi(tokens[1]);
+        if (i < error_idx)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         m_ptr = &m_info[i];
-    } else if (!m_ptr) {
-        return 3;
-    } else if (buf[0] == 'I') {
-        char *book, *stat;
-        int xtra, type, first, weight;
-        char *s;
-        s = angband_strchr(buf + 2, ':');
-
-        /* Verify that colon */
-        if (!s)
-            return 1;
-
-        /* Nuke the colon, advance to the name */
-        *s++ = '\0';
-
-        book = buf + 2;
-
-        if (streq(book, "SORCERY"))
-            m_ptr->spell_book = TV_SORCERY_BOOK;
-        else if (streq(book, "LIFE"))
-            m_ptr->spell_book = TV_LIFE_BOOK;
-        else if (streq(book, "MUSIC"))
-            m_ptr->spell_book = TV_MUSIC_BOOK;
-        else if (streq(book, "HISSATSU"))
-            m_ptr->spell_book = TV_HISSATSU_BOOK;
-        else if (streq(book, "NONE"))
-            m_ptr->spell_book = TV_NONE;
-        else
-            return 5;
-
-        stat = s;
-        s = angband_strchr(s, ':');
-        if (!s)
-            return 1;
-        *s++ = '\0';
-
-        if (streq(stat, "STR"))
-            m_ptr->spell_stat = A_STR;
-        else if (streq(stat, "INT"))
-            m_ptr->spell_stat = A_INT;
-        else if (streq(stat, "WIS"))
-            m_ptr->spell_stat = A_WIS;
-        else if (streq(stat, "DEX"))
-            m_ptr->spell_stat = A_DEX;
-        else if (streq(stat, "CON"))
-            m_ptr->spell_stat = A_CON;
-        else if (streq(stat, "CHR"))
-            m_ptr->spell_stat = A_CHR;
-        else
-            return 5;
-
-        if (4 != sscanf(s, "%x:%d:%d:%d", (uint *)&xtra, &type, &first, &weight))
-            return 1;
-
-        m_ptr->spell_xtra = xtra;
-        m_ptr->spell_type = type;
-        m_ptr->spell_first = first;
-        m_ptr->spell_weight = weight;
-    } else if (buf[0] == 'R') {
-        if (2 != sscanf(buf + 2, "%d:%d", &realm, &readable))
-            return 1;
-
+    } else if (!m_ptr)
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if (tokens[0] == "I") {
+        if (tokens.size() < 7 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto tval = name_to_tval.find(tokens[1]);
+        if (tval == name_to_tval.end())
+            return PARSE_ERROR_INVALID_FLAG;
+
+        m_ptr->spell_book = tval->second;
+
+        const auto stat = name_to_stat.find(tokens[2]);
+        if (stat == name_to_stat.end())
+            return PARSE_ERROR_INVALID_FLAG;
+
+        m_ptr->spell_stat = stat->second;
+
+        info_set_value(m_ptr->spell_xtra, tokens[3]);
+        info_set_value(m_ptr->spell_type, tokens[4]);
+        info_set_value(m_ptr->spell_first, tokens[5]);
+        info_set_value(m_ptr->spell_weight, tokens[6]);
+    } else if (tokens[0] == "R") {
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(realm, tokens[1]);
+        info_set_value(readable, tokens[2]);
         magic_idx = 0;
-    } else if (buf[0] == 'T') {
-        int level, mana, fail, exp;
-
+    } else if (tokens[0] == "T") {
         if (!readable)
-            return 1;
-        if (4 != sscanf(buf + 2, "%d:%d:%d:%d", &level, &mana, &fail, &exp))
-            return 1;
+            return PARSE_ERROR_GENERIC;
+
+        if (tokens.size() < 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        m_ptr->info[realm][magic_idx].slevel = (PLAYER_LEVEL)level;
-        m_ptr->info[realm][magic_idx].smana = (MANA_POINT)mana;
-        m_ptr->info[realm][magic_idx].sfail = (PERCENTAGE)fail;
-        m_ptr->info[realm][magic_idx].sexp = (EXP)exp;
+        auto &magic = m_ptr->info[realm][magic_idx];
+        info_set_value(magic.slevel, tokens[1]);
+        info_set_value(magic.smana, tokens[2]);
+        info_set_value(magic.sfail, tokens[3]);
+        info_set_value(magic.sexp, tokens[4]);
         magic_idx++;
     } else
-        return 6;
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
-    return 0;
+    return PARSE_ERROR_NONE;
 }
index 622a93a..793ceb7 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
-#include "info-reader/info-reader-util.h"
 #include "system/angband.h"
+#include <string_view>
 
-errr parse_m_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_m_info(std::string_view buf, angband_header *head);
index 8c39365..b20cee3 100644 (file)
   * モンスターの打撃手段トークンの定義 /
   * Monster Blow Methods
   */
-concptr r_info_blow_method[NB_RBM_TYPE + 1] = {
-       "",
-       "HIT",
-       "TOUCH",
-       "PUNCH",
-       "KICK",
-       "CLAW",
-       "BITE",
-       "STING",
-       "SLASH",
-       "BUTT",
-       "CRUSH",
-       "ENGULF",
-       "CHARGE",
-       "CRAWL",
-       "DROOL",
-       "SPIT",
-       "EXPLODE",
-       "GAZE",
-       "WAIL",
-       "SPORE",
-       "XXX4",
-       "BEG",
-       "INSULT",
-       "MOAN",
-       "SHOW",
-       "SHOOT",
-       NULL
+const std::unordered_map<std::string_view, rbm_type> r_info_blow_method = {
+       { "HIT", RBM_HIT },
+       { "TOUCH", RBM_TOUCH },
+       { "PUNCH", RBM_PUNCH },
+       { "KICK", RBM_KICK },
+       { "CLAW", RBM_CLAW },
+       { "BITE", RBM_BITE },
+       { "STING", RBM_STING },
+       { "SLASH", RBM_SLASH },
+       { "BUTT", RBM_BUTT },
+       { "CRUSH", RBM_CRUSH },
+       { "ENGULF", RBM_ENGULF },
+       { "CHARGE", RBM_CHARGE },
+       { "CRAWL", RBM_CRAWL },
+       { "DROOL", RBM_DROOL },
+       { "SPIT", RBM_SPIT },
+       { "EXPLODE", RBM_EXPLODE },
+       { "GAZE", RBM_GAZE },
+       { "WAIL", RBM_WAIL },
+       { "SPORE", RBM_SPORE },
+       { "XXX4", RBM_XXX4 },
+       { "BEG", RBM_BEG },
+       { "INSULT", RBM_INSULT },
+       { "MOAN", RBM_MOAN },
+       { "SHOW", RBM_SHOW },
+       { "SHOOT", RBM_SHOOT },
 };
 
 /*!
  * モンスターの打撃属性トークンの定義 /
  * Monster Blow Effects
  */
-concptr r_info_blow_effect[NB_RBE_TYPE + 1] = {
-       "",
-       "HURT",
-       "POISON",
-       "UN_BONUS",
-       "UN_POWER",
-       "EAT_GOLD",
-       "EAT_ITEM",
-       "EAT_FOOD",
-       "EAT_LITE",
-       "ACID",
-       "ELEC",
-       "FIRE",
-       "COLD",
-       "BLIND",
-       "CONFUSE",
-       "TERRIFY",
-       "PARALYZE",
-       "LOSE_STR",
-       "LOSE_INT",
-       "LOSE_WIS",
-       "LOSE_DEX",
-       "LOSE_CON",
-       "LOSE_CHR",
-       "LOSE_ALL",
-       "SHATTER",
-       "EXP_10",
-       "EXP_20",
-       "EXP_40",
-       "EXP_80",
-       "DISEASE",
-       "TIME",
-       "EXP_VAMP",
-       "DR_MANA",
-       "SUPERHURT",
-       "INERTIA",
-       "STUN",
-       "FLAVOR",
-       NULL
+const std::unordered_map<std::string_view, rbe_type> r_info_blow_effect = {
+       { "HURT", RBE_HURT },
+       { "POISON", RBE_POISON },
+       { "UN_BONUS", RBE_UN_BONUS },
+       { "UN_POWER", RBE_UN_POWER },
+       { "EAT_GOLD", RBE_EAT_GOLD },
+       { "EAT_ITEM", RBE_EAT_ITEM },
+       { "EAT_FOOD", RBE_EAT_FOOD },
+       { "EAT_LITE", RBE_EAT_LITE },
+       { "ACID", RBE_ACID },
+       { "ELEC", RBE_ELEC },
+       { "FIRE", RBE_FIRE },
+       { "COLD", RBE_COLD },
+       { "BLIND", RBE_BLIND },
+       { "CONFUSE", RBE_CONFUSE },
+       { "TERRIFY", RBE_TERRIFY },
+       { "PARALYZE", RBE_PARALYZE },
+       { "LOSE_STR", RBE_LOSE_STR },
+       { "LOSE_INT", RBE_LOSE_INT },
+       { "LOSE_WIS", RBE_LOSE_WIS },
+       { "LOSE_DEX", RBE_LOSE_DEX },
+       { "LOSE_CON", RBE_LOSE_CON },
+       { "LOSE_CHR", RBE_LOSE_CHR },
+       { "LOSE_ALL", RBE_LOSE_ALL },
+       { "SHATTER", RBE_SHATTER },
+       { "EXP_10", RBE_EXP_10 },
+       { "EXP_20", RBE_EXP_20 },
+       { "EXP_40", RBE_EXP_40 },
+       { "EXP_80", RBE_EXP_80 },
+       { "DISEASE", RBE_DISEASE },
+       { "TIME", RBE_TIME },
+       { "EXP_VAMP", RBE_DR_LIFE },
+       { "DR_MANA", RBE_DR_MANA },
+       { "SUPERHURT", RBE_SUPERHURT },
+       { "INERTIA", RBE_INERTIA },
+       { "STUN", RBE_STUN },
+       { "FLAVOR", RBE_FLAVOR },
 };
 
 /*!
  * モンスター特性トークンの定義1 /
  * Monster race flags
  */
-concptr r_info_flags1[NUM_R_FLAGS_1] = {
-       "UNIQUE",
-       "QUESTOR",
-       "MALE",
-       "FEMALE",
-       "CHAR_CLEAR",
-       "SHAPECHANGER",
-       "ATTR_CLEAR",
-       "ATTR_MULTI",
-       "FORCE_DEPTH",
-       "FORCE_MAXHP",
-       "PREVENT_SUDDEN_MAGIC",
-       "FORCE_EXTRA",
-       "ATTR_SEMIRAND",
-       "FRIENDS",
-       "ESCORT",
-       "ESCORTS",
-       "NEVER_BLOW",
-       "NEVER_MOVE",
-       "RAND_25",
-       "RAND_50",
-       "ONLY_GOLD",
-       "ONLY_ITEM",
-       "DROP_60",
-       "DROP_90",
-       "DROP_1D2",
-       "DROP_2D2",
-       "DROP_3D2",
-       "DROP_4D2",
-       "DROP_GOOD",
-       "DROP_GREAT",
-       "XXX2",
-       "XXX3"
+const std::unordered_map<std::string_view, race_flags1> r_info_flags1 = {
+       { "UNIQUE", RF1_UNIQUE },
+       { "QUESTOR", RF1_QUESTOR },
+       { "MALE", RF1_MALE },
+       { "FEMALE", RF1_FEMALE },
+       { "CHAR_CLEAR", RF1_CHAR_CLEAR },
+       { "SHAPECHANGER", RF1_SHAPECHANGER },
+       { "ATTR_CLEAR", RF1_ATTR_CLEAR },
+       { "ATTR_MULTI", RF1_ATTR_MULTI },
+       { "FORCE_DEPTH", RF1_FORCE_DEPTH },
+       { "FORCE_MAXHP", RF1_FORCE_MAXHP },
+       { "PREVENT_SUDDEN_MAGIC", RF1_PREVENT_SUDDEN_MAGIC },
+       { "FORCE_EXTRA", RF1_FORCE_EXTRA },
+       { "ATTR_SEMIRAND", RF1_ATTR_SEMIRAND },
+       { "FRIENDS", RF1_FRIENDS },
+       { "ESCORT", RF1_ESCORT },
+       { "ESCORTS", RF1_ESCORTS },
+       { "NEVER_BLOW", RF1_NEVER_BLOW },
+       { "NEVER_MOVE", RF1_NEVER_MOVE },
+       { "RAND_25", RF1_RAND_25 },
+       { "RAND_50", RF1_RAND_50 },
+       { "ONLY_GOLD", RF1_ONLY_GOLD },
+       { "ONLY_ITEM", RF1_ONLY_ITEM },
+       { "DROP_60", RF1_DROP_60 },
+       { "DROP_90", RF1_DROP_90 },
+       { "DROP_1D2", RF1_DROP_1D2 },
+       { "DROP_2D2", RF1_DROP_2D2 },
+       { "DROP_3D2", RF1_DROP_3D2 },
+       { "DROP_4D2", RF1_DROP_4D2 },
+       { "DROP_GOOD", RF1_DROP_GOOD },
+       { "DROP_GREAT", RF1_DROP_GREAT },
 };
 
 /*!
  * モンスター特性トークンの定義2 /
  * Monster race flags
  */
-concptr r_info_flags2[NUM_R_FLAGS_2] = {
-       "STUPID",
-       "SMART",
-       "CAN_SPEAK",
-       "REFLECTING",
-       "INVISIBLE",
-       "COLD_BLOOD",
-       "EMPTY_MIND",
-       "WEIRD_MIND",
-       "MULTIPLY",
-       "REGENERATE",
-       "CHAR_MULTI",
-       "ATTR_ANY",
-       "POWERFUL",
-       "ELDRITCH_HORROR",
-       "AURA_FIRE",
-       "AURA_ELEC",
-       "OPEN_DOOR",
-       "BASH_DOOR",
-       "PASS_WALL",
-       "KILL_WALL",
-       "MOVE_BODY",
-       "KILL_BODY",
-       "TAKE_ITEM",
-       "KILL_ITEM",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "HUMAN",
-       "QUANTUM"
+const std::unordered_map<std::string_view, race_flags2> r_info_flags2 = {
+       { "STUPID", RF2_STUPID },
+       { "SMART", RF2_SMART },
+       { "CAN_SPEAK", RF2_CAN_SPEAK },
+       { "REFLECTING", RF2_REFLECTING },
+       { "INVISIBLE", RF2_INVISIBLE },
+       { "COLD_BLOOD", RF2_COLD_BLOOD },
+       { "EMPTY_MIND", RF2_EMPTY_MIND },
+       { "WEIRD_MIND", RF2_WEIRD_MIND },
+       { "MULTIPLY", RF2_MULTIPLY },
+       { "REGENERATE", RF2_REGENERATE },
+       { "CHAR_MULTI", RF2_CHAR_MULTI },
+       { "ATTR_ANY", RF2_ATTR_ANY },
+       { "POWERFUL", RF2_POWERFUL },
+       { "ELDRITCH_HORROR", RF2_ELDRITCH_HORROR },
+       { "AURA_FIRE", RF2_AURA_FIRE },
+       { "AURA_ELEC", RF2_AURA_ELEC },
+       { "OPEN_DOOR", RF2_OPEN_DOOR },
+       { "BASH_DOOR", RF2_BASH_DOOR },
+       { "PASS_WALL", RF2_PASS_WALL },
+       { "KILL_WALL", RF2_KILL_WALL },
+       { "MOVE_BODY", RF2_MOVE_BODY },
+       { "KILL_BODY", RF2_KILL_BODY },
+       { "TAKE_ITEM", RF2_TAKE_ITEM },
+       { "KILL_ITEM", RF2_KILL_ITEM },
+       { "HUMAN", RF2_HUMAN },
+       { "QUANTUM", RF2_QUANTUM }
 };
 
 /*!
  * モンスター特性トークンの定義3 /
  * Monster race flags
  */
-concptr r_info_flags3[NUM_R_FLAGS_3] = {
-       "ORC",
-       "TROLL",
-       "GIANT",
-       "DRAGON",
-       "DEMON",
-       "UNDEAD",
-       "EVIL",
-       "ANIMAL",
-       "AMBERITE",
-       "GOOD",
-       "AURA_COLD",
-       "NONLIVING",
-       "HURT_LITE",
-       "HURT_ROCK",
-       "HURT_FIRE",
-       "HURT_COLD",
-       "ANGEL",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "NO_FEAR",
-       "NO_STUN",
-       "NO_CONF",
-       "NO_SLEEP"
+const std::unordered_map<std::string_view, race_flags3> r_info_flags3 = {
+       { "ORC", RF3_ORC },
+       { "TROLL", RF3_TROLL },
+       { "GIANT", RF3_GIANT },
+       { "DRAGON", RF3_DRAGON },
+       { "DEMON", RF3_DEMON },
+       { "UNDEAD", RF3_UNDEAD },
+       { "EVIL", RF3_EVIL },
+       { "ANIMAL", RF3_ANIMAL },
+       { "AMBERITE", RF3_AMBERITE },
+       { "GOOD", RF3_GOOD },
+       { "AURA_COLD", RF3_AURA_COLD },
+       { "NONLIVING", RF3_NONLIVING },
+       { "HURT_LITE", RF3_HURT_LITE },
+       { "HURT_ROCK", RF3_HURT_ROCK },
+       { "HURT_FIRE", RF3_HURT_FIRE },
+       { "HURT_COLD", RF3_HURT_COLD },
+       { "ANGEL", RF3_ANGEL },
+       { "NO_FEAR", RF3_NO_FEAR },
+       { "NO_STUN", RF3_NO_STUN },
+       { "NO_CONF", RF3_NO_CONF },
+       { "NO_SLEEP", RF3_NO_SLEEP }
 };
 
 /*!
@@ -311,155 +288,109 @@ const std::unordered_map<std::string_view, RF_ABILITY> r_info_ability_flags = {
  * Monster race flags
  * "GUARDIAN" ... init.c d_infoの FINAL_GUARDIAN_* にて自動指定
  */
-concptr r_info_flags7[NUM_R_FLAGS_7] = {
-       "AQUATIC",
-       "CAN_SWIM",
-       "CAN_FLY",
-       "FRIENDLY",
-       "NAZGUL",
-       "UNIQUE2",
-       "RIDING",
-       "KAGE",
-       "HAS_LITE_1",
-       "SELF_LITE_1",
-       "HAS_LITE_2",
-       "SELF_LITE_2",
-       "XXX7X12",
-       "CHAMELEON",
-       "XXXX4XXX",
-       "TANUKI",
-       "HAS_DARK_1",
-       "SELF_DARK_1",
-       "HAS_DARK_2",
-       "SELF_DARK_2",
-       "XXX7X20",
-       "XXX7X21",
-       "XXX7X22",
-       "XXX7X23",
-       "XXX7X24",
-       "XXX7X25",
-       "XXX7X26",
-       "XXX7X27",
-       "XXX7X28",
-       "XXX7X29",
-       "XXX7X30",
-       "XXX7X31",
+const std::unordered_map<std::string_view, race_flags7> r_info_flags7 = {
+       { "AQUATIC", RF7_AQUATIC },
+       { "CAN_SWIM", RF7_CAN_SWIM },
+       { "CAN_FLY", RF7_CAN_FLY },
+       { "FRIENDLY", RF7_FRIENDLY },
+       { "NAZGUL", RF7_NAZGUL },
+       { "UNIQUE2", RF7_UNIQUE2 },
+       { "RIDING", RF7_RIDING },
+       { "KAGE", RF7_KAGE },
+       { "HAS_LITE_1", RF7_HAS_LITE_1 },
+       { "SELF_LITE_1", RF7_SELF_LITE_1 },
+       { "HAS_LITE_2", RF7_HAS_LITE_2 },
+       { "SELF_LITE_2", RF7_SELF_LITE_2 },
+       { "CHAMELEON", RF7_CHAMELEON },
+       { "TANUKI", RF7_TANUKI },
+       { "HAS_DARK_1", RF7_HAS_DARK_1 },
+       { "SELF_DARK_1", RF7_SELF_DARK_1 },
+       { "HAS_DARK_2", RF7_HAS_DARK_2 },
+       { "SELF_DARK_2", RF7_SELF_DARK_2 },
 };
 
 /*!
  * モンスター特性トークンの定義8 /
  * Monster race flags
  */
-concptr r_info_flags8[NUM_R_FLAGS_8] = {
-       "WILD_ONLY",
-       "WILD_TOWN",
-       "XXX8X02",
-       "WILD_SHORE",
-       "WILD_OCEAN",
-       "WILD_WASTE",
-       "WILD_WOOD",
-       "WILD_VOLCANO",
-       "XXX8X08",
-       "WILD_MOUNTAIN",
-       "WILD_GRASS",
-       "XXX8X11",
-       "XXX8X12",
-       "XXX8X13",
-       "XXX8X14",
-       "XXX8X15",
-       "XXX8X16",
-       "XXX8X17",
-       "XXX8X18",
-       "XXX8X19",
-       "XXX8X20",
-       "XXX8X21",
-       "XXX8X22",
-       "XXX8X23",
-       "XXX8X24",
-       "XXX8X25",
-       "XXX8X26",
-       "XXX8X27",
-       "XXX8X28",
-       "XXX8X29",
-       "WILD_SWAMP",   /* ToDo: Implement Swamp */
-       "WILD_ALL",
+const std::unordered_map<std::string_view, race_flags8> r_info_flags8 = {
+       { "WILD_ONLY", RF8_WILD_ONLY },
+       { "WILD_TOWN", RF8_WILD_TOWN },
+       { "WILD_SHORE", RF8_WILD_SHORE },
+       { "WILD_OCEAN", RF8_WILD_OCEAN },
+       { "WILD_WASTE", RF8_WILD_WASTE },
+       { "WILD_WOOD", RF8_WILD_WOOD },
+       { "WILD_VOLCANO", RF8_WILD_VOLCANO },
+       { "WILD_MOUNTAIN", RF8_WILD_MOUNTAIN },
+       { "WILD_GRASS", RF8_WILD_GRASS },
+       { "WILD_SWAMP", RF8_WILD_SWAMP },
+       { "WILD_ALL", RF8_WILD_ALL },
 };
 
 /*!
  * モンスター特性トークンの定義9 /
  * Monster race flags
  */
-concptr r_info_flags9[NUM_R_FLAGS_9] = {
-       "DROP_CORPSE",
-       "DROP_SKELETON",
-       "EAT_BLIND",
-       "EAT_CONF",
-       "EAT_MANA",
-       "EAT_NEXUS",
-       "EAT_BLINK",
-       "EAT_SLEEP",
-       "EAT_BERSERKER",
-       "EAT_ACIDIC",
-       "EAT_SPEED",
-       "EAT_CURE",
-       "EAT_FIRE_RES",
-       "EAT_COLD_RES",
-       "EAT_ACID_RES",
-       "EAT_ELEC_RES",
-       "EAT_POIS_RES",
-       "EAT_INSANITY",
-       "EAT_DRAIN_EXP",
-       "EAT_POISONOUS",
-       "EAT_GIVE_STR",
-       "EAT_GIVE_INT",
-       "EAT_GIVE_WIS",
-       "EAT_GIVE_DEX",
-       "EAT_GIVE_CON",
-       "EAT_GIVE_CHR",
-       "EAT_LOSE_STR",
-       "EAT_LOSE_INT",
-       "EAT_LOSE_WIS",
-       "EAT_LOSE_DEX",
-       "EAT_LOSE_CON",
-       "EAT_LOSE_CHR",
-       "EAT_DRAIN_MANA",
+const std::unordered_map<std::string_view, race_flags9> r_info_flags9 = {
+       { "DROP_CORPSE", RF9_DROP_CORPSE },
+       { "DROP_SKELETON", RF9_DROP_SKELETON },
+       { "EAT_BLIND", RF9_EAT_BLIND },
+       { "EAT_CONF", RF9_EAT_CONF },
+       { "EAT_MANA", RF9_EAT_MANA },
+       { "EAT_NEXUS", RF9_EAT_NEXUS },
+       // { "EAT_BLINK", RF9_EAT_BLINK }, //<! @note フラグ未定義
+       { "EAT_SLEEP", RF9_EAT_SLEEP },
+       { "EAT_BERSERKER", RF9_EAT_BERSERKER },
+       { "EAT_ACIDIC", RF9_EAT_ACIDIC },
+       { "EAT_SPEED", RF9_EAT_SPEED },
+       { "EAT_CURE", RF9_EAT_CURE },
+       { "EAT_FIRE_RES", RF9_EAT_FIRE_RES },
+       { "EAT_COLD_RES", RF9_EAT_COLD_RES },
+       { "EAT_ACID_RES", RF9_EAT_ACID_RES },
+       { "EAT_ELEC_RES", RF9_EAT_ELEC_RES },
+       { "EAT_POIS_RES", RF9_EAT_POIS_RES },
+       { "EAT_INSANITY", RF9_EAT_INSANITY },
+       { "EAT_DRAIN_EXP", RF9_EAT_DRAIN_EXP },
+       { "EAT_POISONOUS", RF9_EAT_POISONOUS },
+       { "EAT_GIVE_STR", RF9_EAT_GIVE_STR },
+       { "EAT_GIVE_INT", RF9_EAT_GIVE_INT },
+       { "EAT_GIVE_WIS", RF9_EAT_GIVE_WIS },
+       { "EAT_GIVE_DEX", RF9_EAT_GIVE_DEX },
+       { "EAT_GIVE_CON", RF9_EAT_GIVE_CON },
+       { "EAT_GIVE_CHR", RF9_EAT_GIVE_CHR },
+       { "EAT_LOSE_STR", RF9_EAT_LOSE_STR },
+       { "EAT_LOSE_INT", RF9_EAT_LOSE_INT },
+       { "EAT_LOSE_WIS", RF9_EAT_LOSE_WIS },
+       { "EAT_LOSE_DEX", RF9_EAT_LOSE_DEX },
+       { "EAT_LOSE_CON", RF9_EAT_LOSE_CON },
+       { "EAT_LOSE_CHR", RF9_EAT_LOSE_CHR },
+       { "EAT_DRAIN_MANA", RF9_EAT_DRAIN_MANA },
 };
 
 /*!
  * モンスター特性トークンの定義R(耐性) /
  * Monster race flags
  */
-concptr r_info_flagsr[NUM_R_FLAGS_R] = {
-       "IM_ACID",
-       "IM_ELEC",
-       "IM_FIRE",
-       "IM_COLD",
-       "IM_POIS",
-       "RES_LITE",
-       "RES_DARK",
-       "RES_NETH",
-       "RES_WATE",
-       "RES_PLAS",
-       "RES_SHAR",
-       "RES_SOUN",
-       "RES_CHAO",
-       "RES_NEXU",
-       "RES_DISE",
-       "RES_WALL",
-       "RES_INER",
-       "RES_TIME",
-       "RES_GRAV",
-       "RES_ALL",
-       "RES_TELE",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
-       "XXX",
+const std::unordered_map<std::string_view, race_flags_resistance> r_info_flagsr = {
+       { "IM_ACID", RFR_IM_ACID },
+       { "IM_ELEC", RFR_IM_ELEC },
+       { "IM_FIRE", RFR_IM_FIRE },
+       { "IM_COLD", RFR_IM_COLD },
+       { "IM_POIS", RFR_IM_POIS },
+       { "RES_LITE", RFR_RES_LITE },
+       { "RES_DARK", RFR_RES_DARK },
+       { "RES_NETH", RFR_RES_NETH },
+       { "RES_WATE", RFR_RES_WATE },
+       { "RES_PLAS", RFR_RES_PLAS },
+       { "RES_SHAR", RFR_RES_SHAR },
+       { "RES_SOUN", RFR_RES_SOUN },
+       { "RES_CHAO", RFR_RES_CHAO },
+       { "RES_NEXU", RFR_RES_NEXU },
+       { "RES_DISE", RFR_RES_DISE },
+       { "RES_WALL", RFR_RES_WALL },
+       { "RES_INER", RFR_RES_INER },
+       { "RES_TIME", RFR_RES_TIME },
+       { "RES_GRAV", RFR_RES_GRAV },
+       { "RES_ALL", RFR_RES_ALL },
+       { "RES_TELE", RFR_RES_TELE },
 };
index a5c35e6..4e0cc78 100644 (file)
@@ -2,31 +2,28 @@
 
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-types.h"
+#include "monster-race/race-ability-flags.h"
+#include "monster-race/race-flags1.h"
+#include "monster-race/race-flags2.h"
+#include "monster-race/race-flags3.h"
+#include "monster-race/race-flags7.h"
+#include "monster-race/race-flags8.h"
+#include "monster-race/race-flags9.h"
+#include "monster-race/race-flags-resistance.h"
 #include "system/angband.h"
 
 #include <string_view>
 #include <unordered_map>
 
-#define NUM_R_FLAGS_1 32
-#define NUM_R_FLAGS_2 32
-#define NUM_R_FLAGS_3 32
-#define NUM_R_FLAGS_4 32
-#define NUM_R_ABILITY_FLAGS_1 32
-#define NUM_R_ABILITY_FLAGS_2 32
-#define NUM_R_FLAGS_7 32
-#define NUM_R_FLAGS_8 32
-#define NUM_R_FLAGS_9 33
-#define NUM_R_FLAGS_R 32
-
 enum class RF_ABILITY;
 
-extern concptr r_info_blow_method[NB_RBM_TYPE + 1];
-extern concptr r_info_blow_effect[NB_RBE_TYPE + 1];
-extern concptr r_info_flags1[NUM_R_FLAGS_1];
-extern concptr r_info_flags2[NUM_R_FLAGS_2];
-extern concptr r_info_flags3[NUM_R_FLAGS_3];
+extern const std::unordered_map<std::string_view, rbm_type> r_info_blow_method;
+extern const std::unordered_map<std::string_view, rbe_type> r_info_blow_effect;
+extern const std::unordered_map<std::string_view, race_flags1> r_info_flags1;
+extern const std::unordered_map<std::string_view, race_flags2> r_info_flags2;
+extern const std::unordered_map<std::string_view, race_flags3> r_info_flags3;
 extern const std::unordered_map<std::string_view, RF_ABILITY> r_info_ability_flags;
-extern concptr r_info_flags7[NUM_R_FLAGS_7];
-extern concptr r_info_flags8[NUM_R_FLAGS_8];
-extern concptr r_info_flags9[NUM_R_FLAGS_9];
-extern concptr r_info_flagsr[NUM_R_FLAGS_R];
+extern const std::unordered_map<std::string_view, race_flags7> r_info_flags7;
+extern const std::unordered_map<std::string_view, race_flags8> r_info_flags8;
+extern const std::unordered_map<std::string_view, race_flags9> r_info_flags9;
+extern const std::unordered_map<std::string_view, race_flags_resistance> r_info_flagsr;
index 865a0c0..3cbab56 100644 (file)
@@ -1,4 +1,5 @@
 #include "info-reader/race-reader.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/parse-error-types.h"
 #include "info-reader/race-info-tokens-table.h"
 #include "main/angband-headers.h"
  * Grab one (basic) flag in a monster_race from a textual string
  * @param r_ptr 保管先のモンスター種族構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_basic_flag(monster_race *r_ptr, concptr what)
+static bool grab_one_basic_flag(monster_race *r_ptr, std::string_view what)
 {
-    if (grab_one_flag(&r_ptr->flags1, r_info_flags1, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flags1, r_info_flags1, what))
+        return true;
 
-    if (grab_one_flag(&r_ptr->flags2, r_info_flags2, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flags2, r_info_flags2, what))
+        return true;
 
-    if (grab_one_flag(&r_ptr->flags3, r_info_flags3, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flags3, r_info_flags3, what))
+        return true;
 
-    if (grab_one_flag(&r_ptr->flags7, r_info_flags7, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flags7, r_info_flags7, what))
+        return true;
 
-    if (grab_one_flag(&r_ptr->flags8, r_info_flags8, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flags8, r_info_flags8, what))
+        return true;
 
-    if (grab_one_flag(&r_ptr->flags9, r_info_flags9, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flags9, r_info_flags9, what))
+        return true;
 
-    if (grab_one_flag(&r_ptr->flagsr, r_info_flagsr, what) == 0)
-        return PARSE_ERROR_NONE;
+    if (info_grab_one_flag(r_ptr->flagsr, r_info_flagsr, what))
+        return true;
 
-    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
-    return PARSE_ERROR_GENERIC;
+    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -48,15 +49,15 @@ static errr grab_one_basic_flag(monster_race *r_ptr, concptr what)
  * Grab one (spell) flag in a monster_race from a textual string
  * @param r_ptr 保管先のモンスター種族構造体参照ポインタ
  * @param what 参照元の文字列ポインタ
- * @return エラーコード
+ * @return 見つけたらtrue
  */
-static errr grab_one_spell_flag(monster_race *r_ptr, concptr what)
+static bool grab_one_spell_flag(monster_race *r_ptr, std::string_view what)
 {
     if (EnumClassFlagGroup<RF_ABILITY>::grab_one_flag(r_ptr->ability_flags, r_info_ability_flags, what))
-        return PARSE_ERROR_NONE;
+        return true;
 
-    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what);
-    return PARSE_ERROR_GENERIC;
+    msg_format(_("未知のモンスター・フラグ '%s'。", "Unknown monster flag '%s'."), what.data());
+    return false;
 }
 
 /*!
@@ -66,223 +67,205 @@ static errr grab_one_spell_flag(monster_race *r_ptr, concptr what)
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_r_info(char *buf, angband_header *head)
+errr parse_r_info(std::string_view buf, angband_header *head)
 {
     static monster_race *r_ptr = NULL;
-    char *s, *t;
-    if (buf[0] == 'N') {
-        s = angband_strchr(buf + 2, ':');
-        if (!s)
-            return PARSE_ERROR_GENERIC;
+    const auto &tokens = str_split(buf, ':', true, 10);
 
-        *s++ = '\0';
-#ifdef JP
-        if (!*s)
-            return PARSE_ERROR_GENERIC;
-#endif
+    if (tokens[0] == "N") {
+        // N:index:name_ja
+        if (tokens.size() < 3 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        int i = atoi(buf + 2);
+        auto i = std::stoi(tokens[1]);
         if (i < error_idx)
             return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
-
         if (i >= head->info_num)
-            return PARSE_ERROR_OBSOLETE_FILE;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         r_ptr = &r_info[i];
 #ifdef JP
-        r_ptr->name = std::string(s);
+        r_ptr->name = tokens[2];
 #endif
-    } else if (!r_ptr) {
+    } else if (!r_ptr)
         return PARSE_ERROR_MISSING_RECORD_HEADER;
-    }
-#ifdef JP
-    /* 英語名を読むルーチンを追加 */
-    /* 'E' から始まる行は英語名 */
-    else if (buf[0] == 'E') {
-        r_ptr->E_name = std::string(buf + 2);
-    }
-#else
-    else if (buf[0] == 'E') {
-        r_ptr->name = std::string(buf + 2);
-    }
+    else if (tokens[0] == "E") {
+        // E:name_en
+#ifndef JP
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        r_ptr->name = tokens[1];
 #endif
-    else if (buf[0] == 'D') {
+    } else if (tokens[0] == "D") {
+        // D:text_ja
+        // D:$text_en
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 #ifdef JP
-        if (buf[2] == '$')
+        if (tokens[1][0] == '$')
             return PARSE_ERROR_NONE;
-
-        s = buf + 2;
+        r_ptr->text.append(buf.substr(2));
 #else
-        if (buf[2] != '$')
+        if (tokens[1][0] != '$')
             return PARSE_ERROR_NONE;
-        s = buf + 3;
+        r_ptr->text.append(buf.substr(3));
 #endif
-        r_ptr->text.append(s);
-    } else if (buf[0] == 'G') {
-        if ((buf[1] != ':') || !buf[2] || (buf[3] != ':') || !buf[4])
-            return PARSE_ERROR_GENERIC;
+    } else if (tokens[0] == "G") {
+        // G:color:symbol
+        if (tokens.size() < 3 || tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        char sym = buf[2];
-        byte tmp = color_char_to_attr(buf[4]);
-        if (tmp > 127)
+        auto a = color_char_to_attr(tokens[2][0]);
+        if (a > 127)
             return PARSE_ERROR_GENERIC;
 
-        r_ptr->d_char = sym;
-        r_ptr->d_attr = tmp;
-    } else if (buf[0] == 'I') {
-        int spd, hp1, hp2, aaf, ac, slp;
-        if (sscanf(buf + 2, "%d:%dd%d:%d:%d:%d", &spd, &hp1, &hp2, &aaf, &ac, &slp) != 6)
-            return PARSE_ERROR_GENERIC;
+        r_ptr->d_attr = a;
+        r_ptr->d_char = tokens[1][0];
+    } else if (tokens[0] == "I") {
+        // G:speed:hp_dice:affect_range:ac:sleep_degree
+        if (tokens.size() < 6)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        r_ptr->speed = (SPEED)spd;
-        r_ptr->hdice = (DICE_NUMBER)MAX(hp1, 1);
-        r_ptr->hside = (DICE_SID)MAX(hp2, 1);
-        r_ptr->aaf = (POSITION)aaf;
-        r_ptr->ac = (ARMOUR_CLASS)ac;
-        r_ptr->sleep = (SLEEP_DEGREE)slp;
-    } else if (buf[0] == 'W') {
-        int lev, rar, pad;
-        long exp;
-        long nextexp;
-        int nextmon;
-        if (sscanf(buf + 2, "%d:%d:%d:%ld:%ld:%d", &lev, &rar, &pad, &exp, &nextexp, &nextmon) != 6)
+        const auto &dice = str_split(tokens[2], 'd', false, 2);
+        if (dice.size() < 2)
             return PARSE_ERROR_GENERIC;
 
-        r_ptr->level = (DEPTH)lev;
-        r_ptr->rarity = (RARITY)rar;
-        r_ptr->extra = (BIT_FLAGS16)pad;
-        r_ptr->mexp = (EXP)exp;
-        r_ptr->next_exp = (EXP)nextexp;
-        r_ptr->next_r_idx = (MONRACE_IDX)nextmon;
-    } else if (buf[0] == 'R') {
-        int id, ds, dd;
-        int i = 0;
-        for (; i < A_MAX; i++)
+        info_set_value(r_ptr->speed, tokens[1]);
+        info_set_value(r_ptr->hdice, dice[0]);
+        info_set_value(r_ptr->hside, dice.size() == 1 ? "1" : dice[1]);
+        info_set_value(r_ptr->aaf, tokens[3]);
+        info_set_value(r_ptr->ac, tokens[4]);
+        info_set_value(r_ptr->sleep, tokens[5]);
+    } else if (tokens[0] == "W") {
+        // W:level:ratity:extra:exp:next_exp:next_id
+        if (tokens.size() < 5 || tokens.size() == 6)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(r_ptr->level, tokens[1]);
+        info_set_value(r_ptr->rarity, tokens[2]);
+        info_set_value(r_ptr->extra, tokens[3]);
+        info_set_value(r_ptr->mexp, tokens[4]);
+
+        if (tokens.size() < 6)
+            return PARSE_ERROR_NONE;
+
+        info_set_value(r_ptr->next_exp, tokens[5]);
+        info_set_value(r_ptr->next_r_idx, tokens[6]);
+    } else if (tokens[0] == "R") {
+        // R:reinforcer_idx:number_dice
+        size_t i = 0;
+        for (; i < A_MAX; i++) {
             if (r_ptr->reinforce_id[i] == 0)
                 break;
+        }
 
-        if ((i == 6) || (sscanf(buf + 2, "%d:%dd%d", &id, &dd, &ds) != 3))
+        if (i >= 6)
             return PARSE_ERROR_GENERIC;
 
-        r_ptr->reinforce_id[i] = (MONRACE_IDX)id;
-        r_ptr->reinforce_dd[i] = (DICE_NUMBER)dd;
-        r_ptr->reinforce_ds[i] = (DICE_SID)ds;
-    } else if (buf[0] == 'B') {
-        int n1, n2;
-        int i = 0;
-        for (i = 0; i < 4; i++)
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        if (tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &dice = str_split(tokens[2], 'd', false, 2);
+        info_set_value(r_ptr->reinforce_id[i], tokens[1]);
+        info_set_value(r_ptr->reinforce_dd[i], dice[0]);
+        info_set_value(r_ptr->reinforce_ds[i], dice[1]);
+    } else if (tokens[0] == "B") {
+        // B:blow_type:blow_effect:dice
+        size_t i = 0;
+        for (; i < 4; i++) {
             if (!r_ptr->blow[i].method)
                 break;
-
-        if (i == 4)
-            return PARSE_ERROR_GENERIC;
-
-        /* loop */
-        for (s = t = buf + 2; *t && (*t != ':'); t++)
-            ;
-
-        if (*t == ':')
-            *t++ = '\0';
-
-        for (n1 = 0; r_info_blow_method[n1]; n1++) {
-            if (streq(s, r_info_blow_method[n1]))
-                break;
         }
 
-        if (!r_info_blow_method[n1])
+        if (i >= 4)
             return PARSE_ERROR_GENERIC;
 
-        /* loop */
-        for (s = t; *t && (*t != ':'); t++)
-            ;
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        if (tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        if (*t == ':')
-            *t++ = '\0';
+        auto rbm = r_info_blow_method.find(tokens[1]);
+        if (rbm == r_info_blow_method.end())
+            return PARSE_ERROR_INVALID_FLAG;
 
-        for (n2 = 0; r_info_blow_effect[n2]; n2++) {
-            if (streq(s, r_info_blow_effect[n2]))
-                break;
-        }
+        auto rbe = r_info_blow_effect.find(tokens[2]);
+        if (rbe == r_info_blow_effect.end())
+            return PARSE_ERROR_INVALID_FLAG;
 
-        if (!r_info_blow_effect[n2])
-            return PARSE_ERROR_GENERIC;
+        r_ptr->blow[i].method = rbm->second;
+        r_ptr->blow[i].effect = rbe->second;
 
-        /* loop */
-        for (s = t; *t && (*t != 'd'); t++)
-            ;
-
-        if (*t == 'd')
-            *t++ = '\0';
-
-        r_ptr->blow[i].method = (rbm_type)n1;
-        r_ptr->blow[i].effect = (rbe_type)n2;
-        r_ptr->blow[i].d_dice = atoi(s);
-        r_ptr->blow[i].d_side = atoi(t);
-    } else if (buf[0] == 'F') {
-        for (s = buf + 2; *s;) {
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while (*t == ' ' || *t == '|')
-                    t++;
-            }
+        if (tokens.size() < 4)
+            return PARSE_ERROR_NONE;
 
-            if (0 != grab_one_basic_flag(r_ptr, s))
-                return PARSE_ERROR_INVALID_FLAG;
+        const auto &dice = str_split(tokens[3], 'd', false, 2);
+        info_set_value(r_ptr->blow[i].d_dice, dice[0]);
+        info_set_value(r_ptr->blow[i].d_side, dice[1]);
+    } else if (tokens[0] == "F") {
+        // F:flags
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true, 10);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
+                continue;
 
-            s = t;
+            if (!grab_one_basic_flag(r_ptr, f))
+                return PARSE_ERROR_INVALID_FLAG;
         }
-    } else if (buf[0] == 'S') {
-        for (s = buf + 2; *s;) {
-
-            /* loop */
-            for (t = s; *t && (*t != ' ') && (*t != '|'); ++t)
-                ;
-
-            if (*t) {
-                *t++ = '\0';
-                while ((*t == ' ') || (*t == '|'))
-                    t++;
-            }
+    } else if (tokens[0] == "S") {
+        // S:flags
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        const auto &flags = str_split(tokens[1], '|', true, 10);
+        for (const auto &f : flags) {
+            if (f.size() == 0)
+                continue;
 
-            int i;
-            if (1 == sscanf(s, "1_IN_%d", &i)) {
+            const auto &s_tokens = str_split(f, '_', false, 3);
+            if (s_tokens.size() == 3 && s_tokens[1] == "IN") {
+                if (s_tokens[0] != "1")
+                    return PARSE_ERROR_GENERIC;
+                RARITY i;
+                info_set_value(i, s_tokens[2]);
                 r_ptr->freq_spell = 100 / i;
-                s = t;
-                continue;
+                return PARSE_ERROR_NONE;
             }
 
-            if (grab_one_spell_flag(r_ptr, s) != PARSE_ERROR_NONE)
+            if (!grab_one_spell_flag(r_ptr, f))
                 return PARSE_ERROR_INVALID_FLAG;
-
-            s = t;
         }
-    } else if (buf[0] == 'A') {
-        int id, per, rarity;
-        int i = 0;
-        for (i = 0; i < 4; i++)
+
+    } else if (tokens[0] == "A") {
+        // A:artifact_idx:rarity:percent
+        size_t i = 0;
+        for (; i < 4; i++) {
             if (!r_ptr->artifact_id[i])
                 break;
-
-        if ((i == 4) || (sscanf(buf + 2, "%d:%d:%d", &id, &rarity, &per) != 3))
+        }
+        if (i >= 4)
             return PARSE_ERROR_GENERIC;
 
-        r_ptr->artifact_id[i] = (ARTIFACT_IDX)id;
-        r_ptr->artifact_rarity[i] = (RARITY)rarity;
-        r_ptr->artifact_percent[i] = (PERCENTAGE)per;
-    } else if (buf[0] == 'V') {
-        int val;
-        if (sscanf(buf + 2, "%d", &val) != 3)
-            return 1;
+        if (tokens.size() < 4)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        info_set_value(r_ptr->artifact_id[i], tokens[1]);
+        info_set_value(r_ptr->artifact_rarity[i], tokens[2]);
+        info_set_value(r_ptr->artifact_percent[i], tokens[3]);
+    } else if (tokens[0] == "V") {
+        // V:arena_odds
+        if (tokens.size() < 2)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        r_ptr->arena_ratio = (PERCENTAGE)val;
-    } else {
+        info_set_value(r_ptr->arena_ratio, tokens[1]);
+    } else
         return PARSE_ERROR_UNDEFINED_DIRECTIVE;
-    }
 
     return PARSE_ERROR_NONE;
 }
index 35b8f01..cc79c3d 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
-#include "info-reader/info-reader-util.h"
 #include "system/angband.h"
+#include <string_view>
 
-errr parse_r_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_r_info(std::string_view buf, angband_header *head);
index d4d5c19..10ab87e 100644 (file)
@@ -1,6 +1,20 @@
 #include "info-reader/skill-reader.h"
+#include "info-reader/info-reader-util.h"
+#include "info-reader/parse-error-types.h"
 #include "main/angband-headers.h"
+#include "object/tval-types.h"
 #include "player/player-skill.h"
+#include "util/string-processor.h"
+
+namespace {
+const std::unordered_map<int, int> level_to_exp = {
+    { EXP_LEVEL_UNSKILLED, WEAPON_EXP_UNSKILLED },
+    { EXP_LEVEL_BEGINNER, WEAPON_EXP_BEGINNER },
+    { EXP_LEVEL_SKILLED, WEAPON_EXP_SKILLED },
+    { EXP_LEVEL_EXPERT, WEAPON_EXP_EXPERT },
+    { EXP_LEVEL_MASTER, WEAPON_EXP_MASTER },
+};
+}
 
 /*!
  * @brief 職業技能情報(s_info)のパース関数 /
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_s_info(char *buf, angband_header *head)
+errr parse_s_info(std::string_view buf, angband_header *head)
 {
     static skill_table *s_ptr = NULL;
-    if (buf[0] == 'N') {
-        int i = atoi(buf + 2);
-        if (i <= error_idx)
-            return 4;
+    const auto &tokens = str_split(buf, ':', false, 5);
+
+    if (tokens[0] == "N") {
+        // N:class-index
+        if (tokens.size() < 2 && tokens[1].size() == 0)
+            return PARSE_ERROR_GENERIC;
+
+        auto i = std::stoi(tokens[1]);
+        if (i < error_idx)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         s_ptr = &s_info[i];
-    } else if (!s_ptr) {
-        return 3;
-    } else if (buf[0] == 'W') {
+    } else if (!s_ptr)
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if(tokens[0] == "W") {
+        if (tokens.size() < 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
         int tval, sval, start, max;
-        const s16b exp_conv_table[] = { WEAPON_EXP_UNSKILLED, WEAPON_EXP_BEGINNER, WEAPON_EXP_SKILLED, WEAPON_EXP_EXPERT, WEAPON_EXP_MASTER };
+        info_set_value(tval, tokens[1]);
+        info_set_value(sval, tokens[2]);
+        info_set_value(start, tokens[3]);
+        info_set_value(max, tokens[4]);
+
+        auto start_exp = level_to_exp.find(start);
+        if (start_exp == level_to_exp.end())
+            return PARSE_ERROR_INVALID_FLAG;
 
-        if (4 != sscanf(buf + 2, "%d:%d:%d:%d", &tval, &sval, &start, &max))
-            return 1;
+        auto max_exp = level_to_exp.find(max);
+        if (max_exp == level_to_exp.end())
+            return PARSE_ERROR_INVALID_FLAG;
 
-        if (start < EXP_LEVEL_UNSKILLED || start > EXP_LEVEL_MASTER || max < EXP_LEVEL_UNSKILLED || max > EXP_LEVEL_MASTER)
-            return 8;
+        s_ptr->w_start[tval][sval] = (SUB_EXP)start_exp->second;
+        s_ptr->w_max[tval][sval] = (SUB_EXP)max_exp->second;
+    } else if (tokens[0] == "S") {
+        if (tokens.size() < 4)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        s_ptr->w_start[tval][sval] = exp_conv_table[start];
-        s_ptr->w_max[tval][sval] = exp_conv_table[max];
-    } else if (buf[0] == 'S') {
         int num, start, max;
-        if (3 != sscanf(buf + 2, "%d:%d:%d", &num, &start, &max))
-            return 1;
+        info_set_value(num, tokens[1]);
+        info_set_value(start, tokens[2]);
+        info_set_value(max, tokens[3]);
 
-        if (start < WEAPON_EXP_UNSKILLED || start > WEAPON_EXP_MASTER || max < WEAPON_EXP_UNSKILLED || max > WEAPON_EXP_MASTER)
-            return 8;
+        if (start < WEAPON_EXP_UNSKILLED || start > WEAPON_EXP_MASTER || max < WEAPON_EXP_UNSKILLED || max > WEAPON_EXP_MASTER || start > max)
+            return PARSE_ERROR_INVALID_FLAG;
 
         s_ptr->s_start[num] = (SUB_EXP)start;
         s_ptr->s_max[num] = (SUB_EXP)max;
     } else
-        return 6;
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
-    return 0;
+    return PARSE_ERROR_NONE;
 }
index 8cff63a..5602f8f 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "system/angband.h"
-#include "info-reader/info-reader-util.h"
+#include <string_view>
 
-errr parse_s_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_s_info(std::string_view buf, angband_header *head);
index 39aad67..119ce49 100644 (file)
@@ -1,8 +1,9 @@
 #include "info-reader/vault-reader.h"
 #include "main/angband-headers.h"
+#include "info-reader/info-reader-util.h"
+#include "info-reader/parse-error-types.h"
 #include "room/rooms-vault.h"
 #include "util/string-processor.h"
-#include <string>
 
 /*!
  * @brief Vault情報(v_info)のパース関数 /
  * @param head ヘッダ構造体
  * @return エラーコード
  */
-errr parse_v_info(char *buf, angband_header *head)
+errr parse_v_info(std::string_view buf, angband_header *head)
 {
-    char *s;
     static vault_type *v_ptr = NULL;
+    const auto &tokens = str_split(buf, ':', false, 5);
 
-    if (buf[0] == 'N') {
-        s = angband_strchr(buf + 2, ':');
-        if (!s)
-            return 1;
+    if (tokens[0] == "N") {
+        // N:index:name
+        if (tokens.size() < 3)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+        if (tokens[1].size() == 0 || tokens[2].size() == 0)
+            return PARSE_ERROR_GENERIC;
 
-        *s++ = '\0';
-        if (!*s)
-            return 1;
-
-        int i = atoi(buf + 2);
-        if (i <= error_idx)
-            return 4;
+        auto i = std::stoi(tokens[1]);
+        if (i < error_idx)
+            return PARSE_ERROR_NON_SEQUENTIAL_RECORDS;
         if (i >= head->info_num)
-            return 2;
+            return PARSE_ERROR_OUT_OF_BOUNDS;
 
         error_idx = i;
         v_ptr = &v_info[i];
-        v_ptr->name = std::string(s);
+        v_ptr->name = std::string(tokens[2]);
     } else if (!v_ptr)
-        return 3;
-    else if (buf[0] == 'D') {
-        v_ptr->text.append(buf + 2);
-    } else if (buf[0] == 'X') {
-        EFFECT_ID typ, rat, hgt, wid;
-        if (4 != sscanf(buf + 2, "%d:%d:%d:%d", &typ, &rat, &hgt, &wid))
-            return 1;
+        return PARSE_ERROR_MISSING_RECORD_HEADER;
+    else if (tokens[0] == "D") {
+        // D:MapText
+        if (tokens.size() < 2 || tokens[1].size() == 0)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
+
+        v_ptr->text.append(buf.substr(2));
+    } else if (tokens[0] == "X") {
+        // X:type:rate:height:width
+        if (tokens.size() < 5)
+            return PARSE_ERROR_TOO_FEW_ARGUMENTS;
 
-        v_ptr->typ = (ROOM_IDX)typ;
-        v_ptr->rat = (PROB)rat;
-        v_ptr->hgt = (POSITION)hgt;
-        v_ptr->wid = (POSITION)wid;
+        info_set_value(v_ptr->typ, tokens[1]);
+        info_set_value(v_ptr->rat, tokens[2]);
+        info_set_value(v_ptr->hgt, tokens[3]);
+        info_set_value(v_ptr->wid, tokens[4]);
     } else
-        return 6;
+        return PARSE_ERROR_UNDEFINED_DIRECTIVE;
 
-    return 0;
+    return PARSE_ERROR_NONE;
 }
index ba055bb..a0ee4ab 100644 (file)
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "system/angband.h"
-#include "info-reader/info-reader-util.h"
+#include <string_view>
 
-errr parse_v_info(char *buf, angband_header *head);
+struct angband_header;
+errr parse_v_info(std::string_view buf, angband_header *head);
index 5c07c21..d4cd462 100644 (file)
@@ -9,9 +9,6 @@
 /*!
  * @brief 各初期データ用ヘッダ構造体 / Template file header information (see "init.c").
  */
-typedef struct angband_header angband_header;
-typedef errr (*parse_info_txt_func)(char *buf, angband_header *head);
-
 struct angband_header {
     byte checksum; //!< Checksum of "info" records
     u16b info_num; //!< このinfoのデータ数
index 1712b72..47cf20a 100644 (file)
@@ -12,6 +12,7 @@
 #include "info-reader/feature-reader.h"
 #include "info-reader/fixed-map-parser.h"
 #include "info-reader/general-parser.h"
+#include "info-reader/info-reader-util.h"
 #include "info-reader/kind-reader.h"
 #include "info-reader/magic-reader.h"
 #include "info-reader/race-reader.h"
@@ -38,6 +39,7 @@
 #ifndef WINDOWS
 #include <sys/types.h>
 #endif
+#include <string_view>
 
 /*!
  * @brief 基本情報読み込みのメインルーチン /
@@ -73,7 +75,8 @@ static void init_header(angband_header *head, IDX num)
  * even if the string happens to be empty (everyone has a unique '\0').
  */
 template <typename InfoType>
-static errr init_info(concptr filename, angband_header &head, std::vector<InfoType> &info, parse_info_txt_func parser, void (*retouch)(angband_header *head))
+static errr init_info(concptr filename, angband_header &head, std::vector<InfoType> &info, std::function<errr(std::string_view, angband_header *)> parser,
+    void (*retouch)(angband_header *head))
 {
     char buf[1024];
     path_build(buf, sizeof(buf), ANGBAND_DIR_EDIT, format("%s.txt", filename));
index 7735fe0..bd8d45b 100644 (file)
@@ -12,5 +12,6 @@ enum race_flags8 : uint32_t {
     RF8_XXX8X08 = 0x00000100,
     RF8_WILD_MOUNTAIN = 0x00000200,
     RF8_WILD_GRASS = 0x00000400,
+    RF8_WILD_SWAMP = 0x00000800, //!< 沼地に生息(未使用)
     RF8_WILD_ALL = 0x80000000,
 };