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

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

unix.superglobalmegacorp.com

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