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

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: 
                      7: #include "config.h"
                      8: #include "mystring.h"
                      9: 
                     10: std::unique_ptr<Config> gConfig;
                     11: 
                     12: //
                     13: // 設定クラス
                     14: //
                     15: 
                     16: // コンストラクタ
                     17: Config::Config()
                     18: {
                     19:        // 設定項目はすべてここで用意すること。
                     20:        // ここで追加した順に表示されるので基本的にはアルファベット順に並べる
                     21:        // (先頭のドットは考慮しなくていい)。
                     22:        // ただし vmtype だけは特別なので最初に表示されたほうがいいだろう。
                     23: 
                     24:        Add("vmtype", "");
                     25: 
                     26:        // 以下概ねアルファベット順に並べる
                     27: 
                     28:                                        // デバッガの TCP 待ち受けポート
1.1.1.4   root       29:        Add("debugger-port", 0);
1.1.1.5   root       30:        Add("ethernet-hostdevice", "auto");
1.1       root       31:        Add("ethernet-hostdriver", "none");
                     32:        Add("ethernet-macaddr", "auto");
                     33:                                        // LUNA の DIPSW (1 が UP、0 が DOWN)
1.1.1.3   root       34:                                        // 機種によって初期値を変えるため pio.cpp で設定。
                     35:        Add("luna-dipsw1");
                     36:        Add("luna-dipsw2");
                     37:                                        // モニタウィンドウの更新頻度。(Hz)
                     38:        Add("monitor-rate", 20);
1.1       root       39:                                        // MPU クロック (MHz 単位の実数、小数点以下は3桁まで)。
1.1.1.2   root       40:                                        // 各 VM クラスで初期値を設定している。
1.1       root       41:        Add("mpu-clock");
                     42:        Add("mpu-has-fpu", 0);
1.1.1.2   root       43:                                        // PROM ファイルパス。なければ内蔵 ROM 起動。
                     44:        Add("prom-image", "");
1.1       root       45:        Add(".prom-scsi-debug", 0);
1.1.1.2   root       46:                                        // RAM サイズ (MB 単位の整数)。
                     47:                                        // 各 VM クラスで初期値を設定している。
                     48:        Add("ram-size", 0);
1.1       root       49:        Add(".rtc-force-fixed", 0);
1.1.1.6 ! root       50:        Add("show-statuspanel", 1);
1.1       root       51:        for (int id = 0; id < 8; id++) {
                     52:                Add(string_format("spc0-id%d-image", id));
                     53:                Add(string_format("spc0-id%d-writeprotect", id), 0);
1.1.1.4   root       54:                                        // シークタイム [msec]
                     55:                Add(string_format("spc0-id%d-seektime", id), 0);
1.1       root       56:        }
                     57: }
                     58: 
                     59: // デストラクタ
                     60: Config::~Config()
                     61: {
                     62: }
                     63: 
                     64: // 項目を追加 (初期状態用)。値は空文字列。
                     65: bool
                     66: Config::Add(const std::string& key)
                     67: {
                     68:        return Add(key, "");
                     69: }
                     70: 
                     71: // 項目を追加 (初期状態用)。値は整数値を文字列にしたもの。
                     72: bool
                     73: Config::Add(const std::string& key, int value)
                     74: {
                     75:        return Add(key, std::to_string(value));
                     76: }
                     77: 
                     78: // 項目を追加 (初期状態用)
                     79: bool
                     80: Config::Add(const std::string& key, const std::string& value)
                     81: {
                     82:        assert(FindItem(key) == NULL);
1.1.1.2   root       83:        assert(fixed == false);
1.1       root       84: 
                     85:        list.emplace_back(key, value, ConfigItem::FromInitial, "");
                     86:        return true;
                     87: }
                     88: 
1.1.1.4   root       89: // 項目を削除
                     90: // key が見付からなくても何もしない。key は複数登録されていることはないはず。
                     91: void
                     92: Config::Delete(const std::string& key)
                     93: {
                     94:        for (auto it = list.begin(); it != list.end(); ++it) {
                     95:                auto item = *it;
                     96:                if (key == item.key) {
                     97:                        list.erase(it);
                     98:                        return;
                     99:                }
                    100:        }
                    101:        assert(FindItem(key) == NULL);
                    102: }
                    103: 
1.1       root      104: // 設定ファイルの内容で上書きする
                    105: bool
                    106: Config::Update(const ConfigFile& file)
                    107: {
1.1.1.2   root      108:        assert(fixed == false);
                    109: 
1.1       root      110:        for (const auto& pair : file.lines) {
                    111:                const std::string& line = pair.first;
                    112:                int lineno = pair.second;
                    113: 
                    114:                auto where = string_format("%s:%d", file.filepath.c_str(), lineno);
                    115:                if (UpdateLine(line, ConfigItem::FromConfig, where) == false) {
                    116:                        return false;
                    117:                }
                    118:        }
                    119: 
                    120:        return true;
                    121: }
                    122: 
                    123: // コマンドラインオプションで更新
                    124: bool
                    125: Config::Update(const std::vector<std::string>& options)
                    126: {
1.1.1.2   root      127:        assert(fixed == false);
                    128: 
1.1       root      129:        for (const auto& line : options) {
                    130:                if (UpdateLine(line, ConfigItem::FromOption, "") == false) {
                    131:                        return false;
                    132:                }
                    133:        }
                    134: 
                    135:        return true;
                    136: }
                    137: 
                    138: // 更新1行分の共通処理。
                    139: // キーが見付からないのはエラーとはしない(?)。
                    140: // エラーが起きたらエラーメッセージを表示して false を返す。
                    141: bool
                    142: Config::UpdateLine(const std::string& line, ConfigItem::from_t from,
                    143:        const std::string& where)
                    144: {
                    145:        std::string key;
                    146:        std::string val;
                    147: 
                    148:        // キーと値に分解
                    149:        if (SplitKeyVal(&key, &val, line) == false) {
                    150:                std::string fromstr;
                    151:                if (from == ConfigItem::FromOption) {
                    152:                        fromstr = "-V " + line;
                    153:                } else {
                    154:                        fromstr = where;
                    155:                }
                    156:                warnx("%s: syntax error", fromstr.c_str());
                    157:                return false;
                    158:        }
                    159: 
                    160:        // キーで検索 (なければ無視?)
                    161:        ConfigItem *itemptr = FindItem(key);
                    162:        if (itemptr == NULL) {
                    163:                return true;
                    164:        }
                    165: 
                    166:        // 見付かったので更新
                    167:        ConfigItem& item = *itemptr;
                    168:        item.value = val;
                    169:        item.from  = from;
                    170:        item.where = where;
                    171: 
                    172:        return true;
                    173: }
                    174: 
                    175: // "key=val" 形式の行 line を分解するして *keyp, *valp に代入する。
                    176: // その際 key, val 前後の空白は取り除く。
                    177: // 失敗すれば false を返す。
                    178: /*static*/ bool
                    179: Config::SplitKeyVal(std::string *keyp, std::string *valp,
                    180:        const std::string& line)
                    181: {
                    182:        assert(keyp);
                    183:        assert(valp);
                    184: 
                    185:        // キーと値に分解
                    186:        auto pos = line.find('=');
                    187:        if (pos == std::string::npos) {
                    188:                return false;
                    189:        }
                    190:        auto key = line.substr(0, pos++);
                    191:        auto val = line.substr(pos, line.size() - pos);
                    192: 
                    193:        string_rtrim(key);
                    194:        string_rtrim(val);
                    195:        *keyp = string_ltrim(key);
                    196:        *valp = string_ltrim(val);
                    197: 
                    198:        return true;
                    199: }
                    200: 
1.1.1.2   root      201: // 内容を表示する。
                    202: // all なら隠し設定も含めて表示。
1.1       root      203: void
1.1.1.2   root      204: Config::Show(bool all) const
1.1       root      205: {
1.1.1.2   root      206:        assert(fixed);
                    207: 
1.1       root      208:        for (const auto& item : list) {
1.1.1.2   root      209:                // '!' から始まるのは内部用変数なので隠す
                    210:                if (!all && item.key[0] == '!') {
                    211:                        continue;
                    212:                }
1.1       root      213:                // ドットから始まるのは隠し設定で、初期値のままなら隠す
1.1.1.2   root      214:                if (!all &&
                    215:                    item.key[0] == '.' && item.from == ConfigItem::FromInitial) {
1.1       root      216:                        continue;
                    217:                }
                    218: 
                    219:                std::string buf = string_format("%s=\"%s\"",
                    220:                        item.key.c_str(), item.value.c_str());
                    221:                if (buf.size() < 40) {
                    222:                        int n = ((40 - buf.size()) + 7) / 8;
                    223:                        buf.append(n, '\t');
                    224:                } else {
                    225:                        buf.push_back('\t');
                    226:                }
                    227: 
                    228:                std::string fromstr;
                    229:                switch (item.from) {
                    230:                 case ConfigItem::FromInitial:
                    231:                        fromstr = "initial value";
                    232:                        break;
                    233:                 case ConfigItem::FromConfig:
                    234:                        fromstr = item.where;
                    235:                        break;
                    236:                 case ConfigItem::FromOption:
                    237:                        fromstr = "-V option";
                    238:                        break;
                    239:                 default:
                    240:                        __unreachable();
                    241:                }
                    242: 
                    243:                printf("%s(%s)\n", buf.c_str(), fromstr.c_str());
                    244:        }
                    245: }
                    246: 
                    247: // key から ConfigItem を取得する。見付からなければ assert する。
                    248: const ConfigItem&
1.1.1.2   root      249: Config::Find(const std::string& key) const
1.1       root      250: {
                    251:        for (const auto& item : list) {
                    252:                if (key == item.key) {
                    253:                        return item;
                    254:                }
                    255:        }
1.1.1.2   root      256:        assertmsg(0, "Config::Find() \"%s\" not found\n", key.c_str());
                    257: }
                    258: 
                    259: // key のデフォルト値を差し替える。key が見付からなければ assert する。
                    260: void
                    261: Config::SetDefault(const std::string& key, int val)
                    262: {
                    263:        std::string valstr = std::to_string(val);
                    264:        SetDefault(key, valstr);
1.1       root      265: }
                    266: 
1.1.1.2   root      267: // key のデフォルト値を差し替える。key が見付からなければ assert する。
                    268: void
                    269: Config::SetDefault(const std::string& key, const std::string& val)
1.1       root      270: {
1.1.1.2   root      271:        assert(fixed == false);
                    272: 
1.1       root      273:        for (auto& item : list) {
                    274:                if (key == item.key) {
1.1.1.2   root      275:                        item.SetDefault(val);
                    276:                        return;
1.1       root      277:                }
                    278:        }
1.1.1.2   root      279:        assertmsg(0, "Config::SetDefault() \"%s\" not found\n", key.c_str());
1.1       root      280: }
                    281: 
                    282: // key から ConfigItem を返す。見付からなければ NULL を返す。
                    283: // (こっちは内部で変更するために使う)
                    284: ConfigItem *
                    285: Config::FindItem(const std::string& key)
                    286: {
                    287:        for (auto& item : list) {
                    288:                if (key == item.key) {
                    289:                        return &item;
                    290:                }
                    291:        }
                    292:        return NULL;
                    293: }
                    294: 
1.1.1.2   root      295: // これ以降は書き込み禁止
                    296: void
                    297: Config::Fix()
                    298: {
                    299:        assert(fixed == false);
                    300: 
                    301:        fixed = true;
                    302: }
                    303: 
1.1       root      304: 
                    305: //
                    306: // 設定項目
                    307: //
                    308: 
                    309: // デフォルト値を差し替える
                    310: void
                    311: ConfigItem::SetDefault(const std::string& val)
                    312: {
                    313:        if (from == FromInitial) {
                    314:                value = val;
                    315:        }
                    316: }
                    317: 
                    318: void
                    319: ConfigItem::Err() const
                    320: {
                    321:        // 定型文
                    322:        Err("invalid argument");
                    323: }
                    324: 
                    325: void
                    326: ConfigItem::Err(const char *fmt, ...) const
                    327: {
                    328:        char buf[1024];
                    329:        va_list ap;
                    330: 
                    331:        va_start(ap, fmt);
                    332:        vsnprintf(buf, sizeof(buf), fmt, ap);
                    333:        va_end(ap);
                    334: 
                    335:        std::string msg(buf);
                    336:        Err(msg);
                    337: }
                    338: 
                    339: void
                    340: ConfigItem::Err(const std::string& msg) const
                    341: {
                    342:        std::string fromstr;
                    343: 
                    344:        switch (from) {
                    345:         case FromInitial:
                    346:                fromstr = "initial value:";
                    347:                break;
                    348:         case FromConfig:
                    349:                fromstr = where + ":";
                    350:                break;
                    351:         case FromOption:
                    352:                fromstr = "option -V";
                    353:                break;
                    354:         default:
                    355:                __unreachable();
                    356:        }
                    357:        warnx("%s %s=%s: %s",
                    358:                fromstr.c_str(), key.c_str(), value.c_str(), msg.c_str());
                    359: }
                    360: 
                    361: 
                    362: //
                    363: // 設定ファイル
                    364: //
                    365: 
                    366: // コンストラクタ
                    367: ConfigFile::ConfigFile(const std::string& filepath_)
                    368: {
                    369:        filepath = filepath_;
                    370: }
                    371: 
                    372: // デストラクタ
                    373: ConfigFile::~ConfigFile()
                    374: {
                    375: }
                    376: 
                    377: // ファイルの読み込み
                    378: bool
                    379: ConfigFile::Load()
                    380: {
                    381:        char buf[1024];
                    382:        FILE *fp;
                    383: 
                    384:        fp = fopen(filepath.c_str(), "r");
                    385:        if (fp == NULL) {
                    386:                warn("%s", filepath.c_str());
                    387:                return false;
                    388:        }
                    389: 
                    390:        for (int line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) {
                    391:                // 空行とコメント行を無視
                    392:                rtrim(buf);
                    393:                if (buf[0] == '#') {
                    394:                        buf[0] = '\0';
                    395:                }
                    396:                if (buf[0] == '\0') {
                    397:                        continue;
                    398:                }
                    399: 
                    400:                // ここでは記憶するだけ
                    401:                lines.emplace_back(buf, line);
                    402:        }
                    403: 
                    404:        fclose(fp);
                    405:        return true;
                    406: }

unix.superglobalmegacorp.com

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