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

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

unix.superglobalmegacorp.com

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