Annotation of nono/lib/config.cpp, revision 1.1.1.13

1.1       root        1: //
                      2: // nono
1.1.1.2   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.10  root        7: //
                      8: // 設定
                      9: //
                     10: 
1.1       root       11: #include "config.h"
1.1.1.11  root       12: #include "fdc.h"
1.1       root       13: #include "mystring.h"
                     14: 
1.1.1.10  root       15: // グローバル参照用
                     16: Config *gConfig;
1.1       root       17: 
                     18: // コンストラクタ
                     19: Config::Config()
                     20: {
                     21:        // 設定項目はすべてここで用意すること。
                     22:        // ここで追加した順に表示されるので基本的にはアルファベット順に並べる
                     23:        // (先頭のドットは考慮しなくていい)。
                     24:        // ただし vmtype だけは特別なので最初に表示されたほうがいいだろう。
                     25: 
                     26:        Add("vmtype", "");
                     27: 
                     28:        // 以下概ねアルファベット順に並べる
                     29: 
1.1.1.11  root       30:        // X68030 CGROM ファイルパス。なければ内蔵 CGROM。
                     31:        Add("cgrom-image", "", VMCap::X68030);
                     32: 
1.1.1.7   root       33:        // VM 内の時計を同期する時間軸。
                     34:        // [ real, virtual ]
                     35:        Add("clock-sync", "real");
                     36: 
1.1.1.10  root       37:        // デバッガコンソール
                     38:        Add("debugger-driver", "none");
                     39:        Add("debugger-tcp-port", 0);
                     40:        // デバッガコンソールの fallback は常に不可とする。hostcom.cpp 参照。
                     41:        //  "debugger-fallback"
1.1.1.7   root       42: 
1.1.1.12  root       43:        // DIPSW エイリアス
                     44:        Add("dipsw-autoboot", "", VMCap::LUNA | VMCap::NEWS);
                     45:        Add("dipsw-serial", "", VMCap::LUNA | VMCap::NEWS);
                     46: 
1.1.1.7   root       47:        // MAC アドレス
1.1.1.13! root       48:        Add("ethernet0-macaddr", "auto");
        !            49:        Add("ethernet1-macaddr", "auto");
        !            50:        AddAlias("ethernet-macaddr", "ethernet0-macaddr");
1.1.1.12  root       51: 
                     52:        // X68030 の拡張メモリサイズ
                     53:        Add("extram-size", "0", VMCap::X68030);
1.1.1.7   root       54: 
1.1.1.11  root       55:        // フロッピーディスク
                     56:        Add("fd-drive", 2, VMCap::X68030);
                     57:        for (int id = 0; id < FDCDevice::MAX_DRIVE; id++) {
                     58:                // 種別とイメージパス
                     59:                Add(string_format("fd%d-image", id), VMCap::X68030);
                     60:                // エミュレータ的に書き込みを禁止するか
                     61:                Add(string_format("fd%d-writeignore", id), 0, VMCap::X68030);
                     62:        }
                     63: 
                     64:        // X68030 時の FPU の有無。
                     65:        Add("fpu-type", "68881", VMCap::X68030);
1.1.1.9   root       66: 
1.1.1.12  root       67:        // 高速モード。
                     68:        Add("fast-mode", "0");
                     69: 
1.1.1.10  root       70:        // シリアルポートのホスト側設定
                     71:        Add("hostcom-driver", "none");
                     72:        Add("hostcom-fallback", 0);
                     73:        Add("hostcom-tcp-port", 9998);
                     74: 
1.1.1.11  root       75:        // キーボードの入力モード
                     76:        Add("hostkbd-input", "char");
                     77: 
1.1.1.7   root       78:        // ネットワークのホスト側設定。
1.1.1.13! root       79:        for (int i = 0; i < 2; i++) {
        !            80:                // 2枚目はデフォルトで none のほうがいいだろう。
        !            81:                // --show-config での表示順のためループ内におく。
        !            82:                if (i == 0) {
        !            83:                        Add("hostnet0-driver", "auto");
        !            84:                } else {
        !            85:                        Add("hostnet1-driver", "none");
        !            86:                }
        !            87:                Add(string_format("hostnet%d-fallback", i), 0);
        !            88:                Add(string_format("hostnet%d-afpacket-ifname", i), "auto");
        !            89:                Add(string_format("hostnet%d-bpf-ifname", i), "auto");
        !            90:                Add(string_format("hostnet%d-tap-devpath", i), "auto");
        !            91:        }
        !            92:        AddAlias("hostnet-driver",                      "hostnet0-driver");
        !            93:        AddAlias("hostnet-fallback",            "hostnet0-fallback");
        !            94:        AddAlias("hostnet-afpacket-ifname",     "hostnet0-afpacket-ifname");
        !            95:        AddAlias("hostnet-bpf-ifname",          "hostnet0-bpf-ifname");
        !            96:        AddAlias("hostnet-tap-devpath",         "hostnet0-tap-devpath");
1.1.1.7   root       97: 
1.1.1.11  root       98:        // IPLROM1/2 ファイルパス。なければ内蔵 ROM。
                     99:        Add("iplrom1-image", "", VMCap::X68030);
                    100:        Add("iplrom2-image", "", VMCap::X68030);
                    101: 
1.1.1.10  root      102:        // キーボードの接続
                    103:        Add("keyboard-connect", 1);
                    104: 
1.1.1.8   root      105:        // LUNA の RTC(MK48T02) がうるう年でない 1970 をエポックとして
                    106:        // 設定しているので、そちらに合わせてうるう年を補正する
1.1.1.11  root      107:        Add("luna-adjust-misused-epoch", 1, VMCap::LUNA);
                    108: 
                    109:        // LUNA の DIPSW (1 が UP、0 が DOWN)。
                    110:        // 初期値は機種によって異なるため pio.cpp で設定している。
                    111:        Add("luna-dipsw1", VMCap::LUNA);
                    112:        Add("luna-dipsw2", VMCap::LUNA);
1.1.1.8   root      113: 
1.1.1.10  root      114:        // LUNA ビデオボードプレーン数
1.1.1.12  root      115:        Add("luna-video-plane", 4, VMCap::LUNA);
1.1.1.10  root      116: 
1.1.1.8   root      117:        // m88100 の別名ニーモニックを併記する。
1.1.1.11  root      118:        Add(".m88k-altname", 0, VMCap::M88K);
1.1.1.8   root      119: 
1.1.1.12  root      120:        // 画面サイズ。
                    121:        Add("mainview-scale", "1");
                    122: 
                    123:        // モニタウィンドウ(等)のフォントサイズ
                    124:        Add("monitor-fontsize", 12);
                    125: 
1.1.1.7   root      126:        // モニタウィンドウの更新頻度 [Hz]
1.1.1.3   root      127:        Add("monitor-rate", 20);
1.1.1.7   root      128: 
                    129:        // MPU クロック (MHz 単位の実数、小数点以下は3桁まで)。
                    130:        // 初期値は各 VM クラスで設定している。
1.1       root      131:        Add("mpu-clock");
1.1.1.7   root      132: 
                    133:        // M88100 で疑似 STOP 状態をサポートする
1.1.1.11  root      134:        Add("mpu-pseudo-stop", 1, VMCap::M88K);
1.1.1.7   root      135: 
1.1.1.13! root      136:        // Nereid
        !           137:        Add("nereid0-enable", 0, VMCap::X68030);
        !           138:        Add("nereid1-enable", 0, VMCap::X68030);
        !           139: 
        !           140:        // Nereid イーサネット
        !           141:        Add("nereid0-net", 1, VMCap::X68030);
        !           142:        Add("nereid1-net", 1, VMCap::X68030);
        !           143: 
        !           144:        // Nereid バンクメモリ容量 (0, 4, 16 もしくは -4, -16)
        !           145:        Add("nereid0-ram-size", 16, VMCap::X68030);
        !           146:        Add("nereid1-ram-size", 16, VMCap::X68030);
        !           147: 
1.1.1.12  root      148:        // NEWS の DIPSW (1 がオン、0 がオフ)。
                    149:        Add("news-dipsw", "00001000", VMCap::NEWS);
                    150: 
                    151:        // NEWS の SIC を無視する。(暫定)
1.1.1.13! root      152:        // これは新旧で処置が変わるのでエイリアスにしていない。
1.1.1.12  root      153:        Add("xxx-news-sic-ignore", "0", VMCap::NEWS);
                    154:        Add("xxx-news-sci-ignore", "", VMCap::NEWS);
                    155: 
1.1.1.7   root      156:        // PROM ファイルパス。なければ内蔵 ROM 起動。
1.1.1.11  root      157:        Add("prom-image", "", VMCap::LUNA);
1.1.1.7   root      158: 
                    159:        // PROM のデバッグオプション。
                    160:        // PROM 中の SCSI デバッグビットを立てる。
1.1.1.11  root      161:        Add(".prom-scsi-debug", 0, VMCap::LUNA1);
1.1.1.7   root      162: 
                    163:        // RAM サイズ (MB 単位の整数)。
                    164:        // 初期値は機種ごとの VM クラスで設定している。
1.1.1.2   root      165:        Add("ram-size", 0);
1.1.1.7   root      166: 
                    167:        // RTC のデバッグ用オプション。
1.1       root      168:        Add(".rtc-force-fixed", 0);
1.1.1.8   root      169:        Add(".rtc-date");
                    170:        Add(".rtc-time");
1.1.1.7   root      171: 
1.1.1.10  root      172:        // RTC の epoch。初期値は各 VM クラスで設定している。
1.1.1.12  root      173:        Add("rtc-epoch-year", VMCap::LUNA | VMCap::NEWS);
1.1.1.10  root      174: 
1.1.1.7   root      175:        // ステータスパネルを表示する。
1.1.1.6   root      176:        Add("show-statuspanel", 1);
1.1.1.7   root      177: 
                    178:        // SCSI 設定。
1.1       root      179:        for (int id = 0; id < 8; id++) {
1.1.1.7   root      180:                // 種別とイメージパス
1.1       root      181:                Add(string_format("spc0-id%d-image", id));
1.1.1.7   root      182:                // エミュレータ的に書き込みを禁止するか
1.1.1.8   root      183:                Add(string_format("spc0-id%d-writeignore", id), 0);
                    184:                // エミュレータ的に書き込みを禁止するか
                    185:                // (後方互換、十分不要になった頃に削除する)
1.1       root      186:                Add(string_format("spc0-id%d-writeprotect", id), 0);
1.1.1.7   root      187:                // シークタイム [msec]
1.1.1.4   root      188:                Add(string_format("spc0-id%d-seektime", id), 0);
1.1       root      189:        }
1.1.1.11  root      190: 
                    191:        // SRAM の RAM 容量を同期するか。
                    192:        Add("sram-sync-ramsize", 1, VMCap::X68030);
1.1       root      193: }
                    194: 
                    195: // デストラクタ
                    196: Config::~Config()
                    197: {
1.1.1.10  root      198:        gConfig = NULL;
1.1       root      199: }
                    200: 
                    201: // 項目を追加 (初期状態用)。値は空文字列。
                    202: bool
1.1.1.11  root      203: Config::Add(const std::string& key, VMCap vmcap)
1.1       root      204: {
1.1.1.11  root      205:        return Add(key, "", vmcap);
1.1       root      206: }
                    207: 
                    208: // 項目を追加 (初期状態用)。値は整数値を文字列にしたもの。
                    209: bool
1.1.1.11  root      210: Config::Add(const std::string& key, int value, VMCap vmcap)
1.1       root      211: {
1.1.1.11  root      212:        return Add(key, std::to_string(value), vmcap);
1.1       root      213: }
                    214: 
                    215: // 項目を追加 (初期状態用)
                    216: bool
1.1.1.11  root      217: Config::Add(const std::string& key, const std::string& value, VMCap vmcap)
1.1       root      218: {
                    219:        assert(FindItem(key) == NULL);
1.1.1.2   root      220:        assert(fixed == false);
1.1       root      221: 
1.1.1.11  root      222:        list.emplace_back(key, value, vmcap, ConfigItem::FromInitial, "");
1.1       root      223:        return true;
                    224: }
                    225: 
1.1.1.13! root      226: // エイリアスを追加
        !           227: bool
        !           228: Config::AddAlias(const std::string& alias, const std::string& key)
        !           229: {
        !           230:        // すでに同名のエイリアスがあれば、プログラムミス
        !           231:        for (const auto& p : aliases) {
        !           232:                if (alias == p.first) {
        !           233:                        PANIC("aliases already has %s !", alias.c_str());
        !           234:                }
        !           235:        }
        !           236: 
        !           237:        aliases.emplace_back(alias, key);
        !           238:        return true;
        !           239: }
        !           240: 
1.1.1.4   root      241: // 項目を削除
                    242: // key が見付からなくても何もしない。key は複数登録されていることはないはず。
                    243: void
                    244: Config::Delete(const std::string& key)
                    245: {
                    246:        for (auto it = list.begin(); it != list.end(); ++it) {
                    247:                auto item = *it;
                    248:                if (key == item.key) {
                    249:                        list.erase(it);
                    250:                        return;
                    251:                }
                    252:        }
                    253:        assert(FindItem(key) == NULL);
                    254: }
                    255: 
1.1       root      256: // 設定ファイルの内容で上書きする
                    257: bool
                    258: Config::Update(const ConfigFile& file)
                    259: {
1.1.1.2   root      260:        assert(fixed == false);
                    261: 
1.1       root      262:        for (const auto& pair : file.lines) {
                    263:                const std::string& line = pair.first;
                    264:                int lineno = pair.second;
                    265: 
                    266:                auto where = string_format("%s:%d", file.filepath.c_str(), lineno);
                    267:                if (UpdateLine(line, ConfigItem::FromConfig, where) == false) {
                    268:                        return false;
                    269:                }
                    270:        }
                    271: 
                    272:        return true;
                    273: }
                    274: 
                    275: // コマンドラインオプションで更新
                    276: bool
1.1.1.12  root      277: Config::Update(const std::string& line, const std::string& optname)
1.1       root      278: {
1.1.1.2   root      279:        assert(fixed == false);
                    280: 
1.1.1.12  root      281:        return UpdateLine(line, ConfigItem::FromOption, optname);
1.1       root      282: }
                    283: 
                    284: // 更新1行分の共通処理。
1.1.1.10  root      285: // キーが見付からない場合、コマンドラインからならエラーとし、
                    286: // それ以外からの場合は警告のみで無視する。
1.1       root      287: // エラーが起きたらエラーメッセージを表示して false を返す。
                    288: bool
                    289: Config::UpdateLine(const std::string& line, ConfigItem::from_t from,
                    290:        const std::string& where)
                    291: {
                    292:        std::string key;
                    293:        std::string val;
                    294: 
                    295:        // キーと値に分解
                    296:        if (SplitKeyVal(&key, &val, line) == false) {
1.1.1.12  root      297:                ConfigItem::PrintErr(from, where, "", line, "Syntax error");
1.1       root      298:                return false;
                    299:        }
                    300: 
1.1.1.13! root      301:        // キーが別名なら正規名に置換
        !           302:        key = GetCanonKey(key);
        !           303: 
1.1.1.10  root      304:        // キーで検索
1.1       root      305:        ConfigItem *itemptr = FindItem(key);
                    306:        if (itemptr == NULL) {
1.1.1.10  root      307:                // コマンドラインからの場合はエラーにする
                    308:                if (from == ConfigItem::FromOption) {
1.1.1.12  root      309:                        ConfigItem::PrintErr(from, where, key, val, "Unknown key");
1.1.1.10  root      310:                        return false;
                    311:                }
                    312:                // コマンドライン以外の場合は警告のみで無視する
1.1.1.12  root      313:                ConfigItem::PrintErr(from, where, key, val, "Unknown key, ignored");
1.1       root      314:                return true;
                    315:        }
                    316: 
                    317:        // 見付かったので更新
                    318:        ConfigItem& item = *itemptr;
                    319:        item.value = val;
                    320:        item.from  = from;
                    321:        item.where = where;
                    322: 
                    323:        return true;
                    324: }
                    325: 
                    326: // "key=val" 形式の行 line を分解するして *keyp, *valp に代入する。
                    327: // その際 key, val 前後の空白は取り除く。
                    328: // 失敗すれば false を返す。
                    329: /*static*/ bool
                    330: Config::SplitKeyVal(std::string *keyp, std::string *valp,
                    331:        const std::string& line)
                    332: {
                    333:        assert(keyp);
                    334:        assert(valp);
                    335: 
                    336:        // キーと値に分解
                    337:        auto pos = line.find('=');
                    338:        if (pos == std::string::npos) {
                    339:                return false;
                    340:        }
                    341:        auto key = line.substr(0, pos++);
                    342:        auto val = line.substr(pos, line.size() - pos);
                    343: 
1.1.1.8   root      344:        *keyp = string_trim(key);
                    345:        *valp = string_trim(val);
1.1       root      346: 
                    347:        return true;
                    348: }
                    349: 
1.1.1.13! root      350: // キーがエイリアスなら正規名を返す。
        !           351: // エイリアスでなければキーをそのまま返す。
        !           352: const std::string&
        !           353: Config::GetCanonKey(const std::string& key) const
        !           354: {
        !           355:        for (const auto& p : aliases) {
        !           356:                const auto& alias = p.first;
        !           357:                const auto& canon = p.second;
        !           358: 
        !           359:                if (key == alias) {
        !           360:                        return canon;
        !           361:                }
        !           362:        }
        !           363: 
        !           364:        return key;
        !           365: }
        !           366: 
1.1.1.2   root      367: // 内容を表示する。
                    368: // all なら隠し設定も含めて表示。
1.1       root      369: void
1.1.1.2   root      370: Config::Show(bool all) const
1.1       root      371: {
1.1.1.2   root      372:        assert(fixed);
                    373: 
1.1       root      374:        for (const auto& item : list) {
1.1.1.2   root      375:                // '!' から始まるのは内部用変数なので隠す
                    376:                if (!all && item.key[0] == '!') {
                    377:                        continue;
                    378:                }
1.1       root      379:                // ドットから始まるのは隠し設定で、初期値のままなら隠す
1.1.1.2   root      380:                if (!all &&
                    381:                    item.key[0] == '.' && item.from == ConfigItem::FromInitial) {
1.1       root      382:                        continue;
                    383:                }
                    384: 
                    385:                std::string buf = string_format("%s=\"%s\"",
                    386:                        item.key.c_str(), item.value.c_str());
                    387:                if (buf.size() < 40) {
                    388:                        int n = ((40 - buf.size()) + 7) / 8;
                    389:                        buf.append(n, '\t');
                    390:                } else {
                    391:                        buf.push_back('\t');
                    392:                }
                    393: 
                    394:                std::string fromstr;
                    395:                switch (item.from) {
                    396:                 case ConfigItem::FromInitial:
                    397:                        fromstr = "initial value";
                    398:                        break;
                    399:                 case ConfigItem::FromConfig:
                    400:                        fromstr = item.where;
                    401:                        break;
                    402:                 case ConfigItem::FromOption:
1.1.1.12  root      403:                        fromstr = "option " + item.where;
1.1       root      404:                        break;
                    405:                 default:
1.1.1.12  root      406:                        fromstr = string_format("corrupted item.from=%d", (int)item.from);
                    407:                        break;
1.1       root      408:                }
                    409: 
                    410:                printf("%s(%s)\n", buf.c_str(), fromstr.c_str());
                    411:        }
                    412: }
                    413: 
                    414: // key から ConfigItem を取得する。見付からなければ assert する。
                    415: const ConfigItem&
1.1.1.2   root      416: Config::Find(const std::string& key) const
1.1       root      417: {
                    418:        for (const auto& item : list) {
                    419:                if (key == item.key) {
                    420:                        return item;
                    421:                }
                    422:        }
1.1.1.10  root      423:        PANIC("Config::Find() \"%s\" not found", key.c_str());
1.1.1.2   root      424: }
                    425: 
                    426: // key のデフォルト値を差し替える。key が見付からなければ assert する。
                    427: void
                    428: Config::SetDefault(const std::string& key, int val)
                    429: {
                    430:        std::string valstr = std::to_string(val);
                    431:        SetDefault(key, valstr);
1.1       root      432: }
                    433: 
1.1.1.2   root      434: // key のデフォルト値を差し替える。key が見付からなければ assert する。
                    435: void
                    436: Config::SetDefault(const std::string& key, const std::string& val)
1.1       root      437: {
1.1.1.2   root      438:        assert(fixed == false);
                    439: 
1.1       root      440:        for (auto& item : list) {
                    441:                if (key == item.key) {
1.1.1.2   root      442:                        item.SetDefault(val);
                    443:                        return;
1.1       root      444:                }
                    445:        }
1.1.1.2   root      446:        assertmsg(0, "Config::SetDefault() \"%s\" not found\n", key.c_str());
1.1       root      447: }
                    448: 
                    449: // key から ConfigItem を返す。見付からなければ NULL を返す。
                    450: // (こっちは内部で変更するために使う)
                    451: ConfigItem *
                    452: Config::FindItem(const std::string& key)
                    453: {
                    454:        for (auto& item : list) {
                    455:                if (key == item.key) {
                    456:                        return &item;
                    457:                }
                    458:        }
                    459:        return NULL;
                    460: }
                    461: 
1.1.1.12  root      462: // これ以降は書き込み禁止。
                    463: bool
1.1.1.2   root      464: Config::Fix()
                    465: {
                    466:        assert(fixed == false);
                    467: 
1.1.1.11  root      468:        // ここで、この機種に不要な変数を削除する。
1.1.1.12  root      469:        // が、その前にその変数がユーザから指定されていればエラーにする。
1.1.1.11  root      470:        for (auto it = list.begin(); it != list.end(); ) {
                    471:                ConfigItem& item = *it;
                    472:                VMCap vmcap = item.GetVMCap();
                    473:                if (gMainApp.Has(vmcap) == false) {
1.1.1.12  root      474:                        // この機種用ではない
                    475: 
                    476:                        if (item.from != ConfigItem::FromInitial) {
                    477:                                // 更新されていればエラー
                    478:                                item.Err("Not supported in this vmtype");
                    479:                                return false;
                    480:                        }
                    481: 
1.1.1.11  root      482:                        it = list.erase(it);
                    483:                } else {
                    484:                        ++it;
                    485:                }
                    486:        }
                    487: 
1.1.1.2   root      488:        fixed = true;
1.1.1.12  root      489:        return true;
1.1.1.2   root      490: }
                    491: 
1.1       root      492: 
                    493: //
                    494: // 設定項目
                    495: //
                    496: 
1.1.1.10  root      497: // 値を整数値として取得してみる。
                    498: bool
                    499: ConfigItem::TryInt(int *val) const
                    500: {
                    501:        char *endp;
                    502: 
                    503:        if (value.empty()) {
                    504:                return false;
                    505:        }
                    506: 
                    507:        errno = 0;
                    508:        int r = strtol(value.c_str(), &endp, 10);
                    509:        if (errno == ERANGE || *endp != '\0') {
                    510:                return false;
                    511:        }
                    512:        *val = r;
                    513:        return true;
                    514: }
                    515: 
1.1.1.12  root      516: // 値を double 値として取得してみる。
                    517: bool
                    518: ConfigItem::TryDouble(double *val) const
                    519: {
                    520:        char *endp;
                    521: 
                    522:        if (value.empty()) {
                    523:                return false;
                    524:        }
                    525: 
                    526:        errno = 0;
                    527:        double res = strtod(value.c_str(), &endp);
                    528:        if (errno) {
                    529:                return false;
                    530:        }
                    531:        *val = res;
                    532:        return true;
                    533: }
                    534: 
1.1       root      535: // デフォルト値を差し替える
                    536: void
                    537: ConfigItem::SetDefault(const std::string& val)
                    538: {
                    539:        if (from == FromInitial) {
                    540:                value = val;
                    541:        }
                    542: }
                    543: 
                    544: void
                    545: ConfigItem::Err() const
                    546: {
                    547:        // 定型文
1.1.1.12  root      548:        Err("Invalid argument");
1.1       root      549: }
                    550: 
                    551: void
                    552: ConfigItem::Err(const char *fmt, ...) const
                    553: {
                    554:        char buf[1024];
                    555:        va_list ap;
                    556: 
                    557:        va_start(ap, fmt);
                    558:        vsnprintf(buf, sizeof(buf), fmt, ap);
                    559:        va_end(ap);
                    560: 
                    561:        std::string msg(buf);
                    562:        Err(msg);
                    563: }
                    564: 
                    565: void
                    566: ConfigItem::Err(const std::string& msg) const
                    567: {
1.1.1.10  root      568:        PrintErr(from, where, key, value, msg);
                    569: }
                    570: 
1.1.1.12  root      571: // この item についてエラーを表示する。
                    572: // key=val の '=' がない場合のみ key を空、value を行全体として呼ぶ。
1.1.1.10  root      573: /*static*/ void
                    574: ConfigItem::PrintErr(ConfigItem::from_t from, const std::string& where,
                    575:        const std::string& key, const std::string& value, const std::string& msg)
                    576: {
1.1       root      577:        std::string fromstr;
                    578: 
                    579:        switch (from) {
                    580:         case FromInitial:
1.1.1.12  root      581:                // 初期値の場合 key が空なことは起きないはず。
                    582:                // というか初期値でエラーが起きることも普通はないはず。
                    583:                fromstr = "initial value: " + key + "=" + value;
1.1       root      584:                break;
1.1.1.12  root      585: 
1.1       root      586:         case FromConfig:
1.1.1.12  root      587:                // 設定ファイルでのエラー。where はファイル名と行番号。
                    588:                fromstr = where + ": ";
                    589:                if (key.empty() == false) {
                    590:                        fromstr += key;
1.1.1.13! root      591:                        fromstr += "=";
1.1.1.12  root      592:                }
                    593:                fromstr += value;
1.1       root      594:                break;
1.1.1.12  root      595: 
1.1       root      596:         case FromOption:
1.1.1.12  root      597:                // コマンドラインオプションの場合は where は
                    598:                // "--fontsize" とか "-V" なので、
                    599:                // "-V" なら (key =) value を追加し、
                    600:                // それ以外なら value のみ追加がいいか。
                    601:                fromstr = "option " + where + " ";
                    602:                if (where == "-V") {
                    603:                        if (key.empty() == false) {
                    604:                                fromstr += key;
                    605:                                fromstr += "=";
                    606:                        }
                    607:                }
                    608:                fromstr += value;
1.1       root      609:                break;
1.1.1.10  root      610: 
1.1.1.12  root      611:         default:
                    612:                fromstr = string_format("corrupted item.from=%d", (int)from);
                    613:                break;
1.1.1.10  root      614:        }
                    615: 
1.1.1.12  root      616:        warnx("%s: %s", fromstr.c_str(), msg.c_str());
1.1       root      617: }
                    618: 
                    619: 
                    620: //
                    621: // 設定ファイル
                    622: //
                    623: 
                    624: // コンストラクタ
                    625: ConfigFile::ConfigFile(const std::string& filepath_)
                    626: {
                    627:        filepath = filepath_;
                    628: }
                    629: 
                    630: // デストラクタ
                    631: ConfigFile::~ConfigFile()
                    632: {
                    633: }
                    634: 
1.1.1.12  root      635: // ファイルの読み込み。
                    636: // 成功すれば true を、失敗すればメッセージを出力して false を返す。
                    637: // ファイルがないのは正常とする (なければスルーするため)。
                    638: // ファイルがあって読めなければ失敗 (エラー終了したいので)。
1.1       root      639: bool
                    640: ConfigFile::Load()
                    641: {
                    642:        char buf[1024];
                    643:        FILE *fp;
                    644: 
                    645:        fp = fopen(filepath.c_str(), "r");
                    646:        if (fp == NULL) {
1.1.1.12  root      647:                if (errno == ENOENT) {
                    648:                        return true;
                    649:                }
1.1       root      650:                warn("%s", filepath.c_str());
                    651:                return false;
                    652:        }
                    653: 
                    654:        for (int line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) {
                    655:                // 空行とコメント行を無視
                    656:                rtrim(buf);
                    657:                if (buf[0] == '#') {
                    658:                        buf[0] = '\0';
                    659:                }
                    660:                if (buf[0] == '\0') {
                    661:                        continue;
                    662:                }
                    663: 
                    664:                // ここでは記憶するだけ
                    665:                lines.emplace_back(buf, line);
                    666:        }
                    667: 
                    668:        fclose(fp);
                    669:        return true;
                    670: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.