|
|
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");
1.1.1.14 root 49: Add("ethernet1-macaddr", "auto", VMCap::X68030);
1.1.1.13 root 50: AddAlias("ethernet-macaddr", "ethernet0-macaddr");
1.1.1.12 root 51:
1.1.1.14 root 52: // 実行ファイル(-X)
53: Add("exec-file");
54: Add("exec-arg", "", VMCap::LUNA | VMCap::X68030);
55: // RAMDISK (--initrd)
56: Add("exec-initrd", "", VMCap::VIRT68K);
57:
1.1.1.12 root 58: // X68030 の拡張メモリサイズ
59: Add("extram-size", "0", VMCap::X68030);
1.1.1.7 root 60:
1.1.1.11 root 61: // フロッピーディスク
62: Add("fd-drive", 2, VMCap::X68030);
63: for (int id = 0; id < FDCDevice::MAX_DRIVE; id++) {
64: // 種別とイメージパス
1.1.1.15! root 65: Add(string_format("fd%u-image", id), VMCap::X68030);
1.1.1.11 root 66: // エミュレータ的に書き込みを禁止するか
1.1.1.15! root 67: Add(string_format("fd%u-writeignore", id), 0, VMCap::X68030);
1.1.1.11 root 68: }
69:
70: // X68030 時の FPU の有無。
71: Add("fpu-type", "68881", VMCap::X68030);
1.1.1.9 root 72:
1.1.1.12 root 73: // 高速モード。
74: Add("fast-mode", "0");
75:
1.1.1.14 root 76: // ホスト CPU アクセラレーション。
77: Add("host-avx2", "auto");
1.1.1.15! root 78: Add("host-neon", "auto");
! 79:
! 80: // CPU アフィニティ (解釈が複雑すぎるので隠しオプション)。
! 81: // "" … 指定しない
! 82: // auto … 予約。現状は "" と同じ。
! 83: // low:<list> … Light スレッドを <list> の CPU に割り付ける。
! 84: // high:<list> … Heavy スレッドを <list> の CPU に割り付ける。
! 85: // perf:<list> … Heavy スレッドを <list> の CPU に、
! 86: // Light スレッドをその反集合の CPU に割り付ける。
! 87: Add(".host-cpu-affinity", "auto");
1.1.1.14 root 88:
1.1.1.10 root 89: // シリアルポートのホスト側設定
90: Add("hostcom-driver", "none");
91: Add("hostcom-fallback", 0);
92: Add("hostcom-tcp-port", 9998);
93:
1.1.1.11 root 94: // キーボードの入力モード
1.1.1.14 root 95: Add("hostkbd-input", "char", VMCap::LUNA | VMCap::X68030);
1.1.1.11 root 96:
1.1.1.7 root 97: // ネットワークのホスト側設定。
1.1.1.14 root 98: // (0 と 1 で -driver の初期値が違う)
99: Add("hostnet0-driver", "auto");
100: Add("hostnet0-fallback", 0);
101: Add("hostnet0-afpacket-ifname", "auto");
102: Add("hostnet0-bpf-ifname", "auto");
103: Add("hostnet0-tap-devpath", "auto");
104:
105: Add("hostnet1-driver", "none", VMCap::X68030);
106: Add("hostnet1-fallback", 0, VMCap::X68030);
107: Add("hostnet1-afpacket-ifname", "auto", VMCap::X68030);
108: Add("hostnet1-bpf-ifname", "auto", VMCap::X68030);
109: Add("hostnet1-tap-devpath", "auto", VMCap::X68030);
110:
1.1.1.13 root 111: AddAlias("hostnet-driver", "hostnet0-driver");
112: AddAlias("hostnet-fallback", "hostnet0-fallback");
113: AddAlias("hostnet-afpacket-ifname", "hostnet0-afpacket-ifname");
114: AddAlias("hostnet-bpf-ifname", "hostnet0-bpf-ifname");
115: AddAlias("hostnet-tap-devpath", "hostnet0-tap-devpath");
1.1.1.7 root 116:
1.1.1.11 root 117: // IPLROM1/2 ファイルパス。なければ内蔵 ROM。
118: Add("iplrom1-image", "", VMCap::X68030);
119: Add("iplrom2-image", "", VMCap::X68030);
120:
1.1.1.10 root 121: // キーボードの接続
1.1.1.14 root 122: Add("keyboard-connect", 1, VMCap::LUNA | VMCap::X68030);
1.1.1.10 root 123:
1.1.1.8 root 124: // LUNA の RTC(MK48T02) がうるう年でない 1970 をエポックとして
125: // 設定しているので、そちらに合わせてうるう年を補正する
1.1.1.11 root 126: Add("luna-adjust-misused-epoch", 1, VMCap::LUNA);
127:
128: // LUNA の DIPSW (1 が UP、0 が DOWN)。
129: // 初期値は機種によって異なるため pio.cpp で設定している。
130: Add("luna-dipsw1", VMCap::LUNA);
131: Add("luna-dipsw2", VMCap::LUNA);
1.1.1.8 root 132:
1.1.1.10 root 133: // LUNA ビデオボードプレーン数
1.1.1.12 root 134: Add("luna-video-plane", 4, VMCap::LUNA);
1.1.1.10 root 135:
1.1.1.8 root 136: // m88100 の別名ニーモニックを併記する。
1.1.1.11 root 137: Add(".m88k-altname", 0, VMCap::M88K);
1.1.1.8 root 138:
1.1.1.15! root 139: // m88100/88200 のバージョン。
! 140: // 初期値はコンストラクタ側で用意している。
! 141: Add("m88100-version", 0, VMCap::M88K);
! 142: Add("m88200-version", 0, VMCap::M88K);
! 143:
1.1.1.12 root 144: // 画面サイズ。
145: Add("mainview-scale", "1");
146:
147: // モニタウィンドウ(等)のフォントサイズ
148: Add("monitor-fontsize", 12);
149:
1.1.1.7 root 150: // モニタウィンドウの更新頻度 [Hz]
1.1.1.3 root 151: Add("monitor-rate", 20);
1.1.1.7 root 152:
153: // MPU クロック (MHz 単位の実数、小数点以下は3桁まで)。
154: // 初期値は各 VM クラスで設定している。
1.1 root 155: Add("mpu-clock");
1.1.1.7 root 156:
157: // M88100 で疑似 STOP 状態をサポートする
1.1.1.11 root 158: Add("mpu-pseudo-stop", 1, VMCap::M88K);
1.1.1.7 root 159:
1.1.1.13 root 160: // Nereid
161: Add("nereid0-enable", 0, VMCap::X68030);
162: Add("nereid1-enable", 0, VMCap::X68030);
163:
164: // Nereid イーサネット
165: Add("nereid0-net", 1, VMCap::X68030);
166: Add("nereid1-net", 1, VMCap::X68030);
167:
168: // Nereid バンクメモリ容量 (0, 4, 16 もしくは -4, -16)
169: Add("nereid0-ram-size", 16, VMCap::X68030);
170: Add("nereid1-ram-size", 16, VMCap::X68030);
171:
1.1.1.12 root 172: // NEWS の DIPSW (1 がオン、0 がオフ)。
173: Add("news-dipsw", "00001000", VMCap::NEWS);
174:
175: // NEWS の SIC を無視する。(暫定)
1.1.1.13 root 176: // これは新旧で処置が変わるのでエイリアスにしていない。
1.1.1.12 root 177: Add("xxx-news-sic-ignore", "0", VMCap::NEWS);
178: Add("xxx-news-sci-ignore", "", VMCap::NEWS);
179:
1.1.1.7 root 180: // PROM ファイルパス。なければ内蔵 ROM 起動。
1.1.1.11 root 181: Add("prom-image", "", VMCap::LUNA);
1.1.1.7 root 182:
183: // PROM のデバッグオプション。
184: // PROM 中の SCSI デバッグビットを立てる。
1.1.1.11 root 185: Add(".prom-scsi-debug", 0, VMCap::LUNA1);
1.1.1.7 root 186:
187: // RAM サイズ (MB 単位の整数)。
188: // 初期値は機種ごとの VM クラスで設定している。
1.1.1.2 root 189: Add("ram-size", 0);
1.1.1.7 root 190:
191: // RTC のデバッグ用オプション。
1.1 root 192: Add(".rtc-force-fixed", 0);
1.1.1.8 root 193: Add(".rtc-date");
194: Add(".rtc-time");
1.1.1.7 root 195:
1.1.1.10 root 196: // RTC の epoch。初期値は各 VM クラスで設定している。
1.1.1.12 root 197: Add("rtc-epoch-year", VMCap::LUNA | VMCap::NEWS);
1.1.1.10 root 198:
1.1.1.7 root 199: // ステータスパネルを表示する。
1.1.1.6 root 200: Add("show-statuspanel", 1);
1.1.1.7 root 201:
202: // SCSI 設定。
1.1 root 203: for (int id = 0; id < 8; id++) {
1.1.1.14 root 204: auto scsicap = VMCap::LUNA | VMCap::X68030;
1.1.1.7 root 205: // 種別とイメージパス
1.1.1.15! root 206: Add(string_format("spc0-id%u-image", id), scsicap);
1.1.1.7 root 207: // エミュレータ的に書き込みを禁止するか
1.1.1.15! root 208: Add(string_format("spc0-id%u-writeignore", id), 0, scsicap);
1.1.1.8 root 209: // エミュレータ的に書き込みを禁止するか
210: // (後方互換、十分不要になった頃に削除する)
1.1.1.15! root 211: Add(string_format("spc0-id%u-writeprotect", id), 0, scsicap);
1.1.1.7 root 212: // シークタイム [msec]
1.1.1.15! root 213: Add(string_format("spc0-id%u-seektime", id), 0, scsicap);
1.1 root 214: }
1.1.1.11 root 215:
216: // SRAM の RAM 容量を同期するか。
217: Add("sram-sync-ramsize", 1, VMCap::X68030);
1.1.1.14 root 218:
219: // virtio 設定。
220: for (int id = 0; id < 8; id++) {
221: auto viocap = VMCap::VIRT68K;
222: // イメージパス
1.1.1.15! root 223: Add(string_format("virtio-block%u-image", id), viocap);
1.1.1.14 root 224: // エミュレータ的に書き込みを禁止するか
1.1.1.15! root 225: Add(string_format("virtio-block%u-writeignore", id), 0, viocap);
1.1.1.14 root 226: }
227:
228: // Windrv パス。
229: Add("windrv-path", "", VMCap::X68030);
230:
231: // X68030 で FC2 ピンを切るか。
232: Add("x68k-cut-fc2", 1, VMCap::X68030);
1.1 root 233: }
234:
235: // デストラクタ
236: Config::~Config()
237: {
1.1.1.10 root 238: gConfig = NULL;
1.1 root 239: }
240:
241: // 項目を追加 (初期状態用)。値は空文字列。
242: bool
1.1.1.11 root 243: Config::Add(const std::string& key, VMCap vmcap)
1.1 root 244: {
1.1.1.11 root 245: return Add(key, "", vmcap);
1.1 root 246: }
247:
248: // 項目を追加 (初期状態用)。値は整数値を文字列にしたもの。
249: bool
1.1.1.11 root 250: Config::Add(const std::string& key, int value, VMCap vmcap)
1.1 root 251: {
1.1.1.11 root 252: return Add(key, std::to_string(value), vmcap);
1.1 root 253: }
254:
255: // 項目を追加 (初期状態用)
256: bool
1.1.1.11 root 257: Config::Add(const std::string& key, const std::string& value, VMCap vmcap)
1.1 root 258: {
259: assert(FindItem(key) == NULL);
1.1.1.2 root 260: assert(fixed == false);
1.1 root 261:
1.1.1.11 root 262: list.emplace_back(key, value, vmcap, ConfigItem::FromInitial, "");
1.1 root 263: return true;
264: }
265:
1.1.1.13 root 266: // エイリアスを追加
267: bool
268: Config::AddAlias(const std::string& alias, const std::string& key)
269: {
270: // すでに同名のエイリアスがあれば、プログラムミス
271: for (const auto& p : aliases) {
272: if (alias == p.first) {
273: PANIC("aliases already has %s !", alias.c_str());
274: }
275: }
276:
277: aliases.emplace_back(alias, key);
278: return true;
279: }
280:
1.1.1.4 root 281: // 項目を削除
282: // key が見付からなくても何もしない。key は複数登録されていることはないはず。
283: void
284: Config::Delete(const std::string& key)
285: {
286: for (auto it = list.begin(); it != list.end(); ++it) {
287: auto item = *it;
288: if (key == item.key) {
289: list.erase(it);
290: return;
291: }
292: }
293: assert(FindItem(key) == NULL);
294: }
295:
1.1 root 296: // 設定ファイルの内容で上書きする
297: bool
298: Config::Update(const ConfigFile& file)
299: {
1.1.1.2 root 300: assert(fixed == false);
301:
1.1 root 302: for (const auto& pair : file.lines) {
303: const std::string& line = pair.first;
1.1.1.15! root 304: uint lineno = pair.second;
1.1 root 305:
1.1.1.15! root 306: auto where = string_format("%s:%u", file.filepath.c_str(), lineno);
1.1.1.14 root 307: if (UpdateLine(line, file.from, where) == false) {
1.1 root 308: return false;
309: }
310: }
311:
312: return true;
313: }
314:
1.1.1.15! root 315: #define UpdateLinePerf(str) do { \
! 316: if (UpdateLine(str, ConfigItem::FromPerf, where) == false) \
! 317: return false; \
! 318: } while (0)
! 319:
1.1 root 320: // コマンドラインオプションで更新
321: bool
1.1.1.12 root 322: Config::Update(const std::string& line, const std::string& optname)
1.1 root 323: {
1.1.1.2 root 324: assert(fixed == false);
325:
1.1.1.15! root 326: // パフォーマンス測定用オプション --perf が指定されたら
! 327: // line="--perf" という非正規の書式で呼ばれるので、ここで展開する。
! 328: if (line == "--perf") {
! 329: // -V prom-image=PROM.DAT はパスの問題があるので、各自で追加指定
! 330: // する必要がある。
! 331: std::string where = "--perf -V";
! 332: UpdateLinePerf(".rtc-force-fixed=1");
! 333: UpdateLinePerf("clock-sync=virtual");
! 334: UpdateLinePerf("fast-mode=1");
! 335: UpdateLinePerf("fd0-writeignore=1");
! 336: UpdateLinePerf("fd1-writeignore=1");
! 337: UpdateLinePerf("fd2-writeignore=1");
! 338: UpdateLinePerf("fd3-writeignore=1");
! 339: UpdateLinePerf("ethernet-macaddr=02:00:00:00:00:01");
! 340: UpdateLinePerf("hostcom-driver=none");
! 341: UpdateLinePerf("hostnet-driver=none");
! 342: UpdateLinePerf("luna-dipsw1=11110111");
! 343: UpdateLinePerf("luna-video-plane=4");
! 344: UpdateLinePerf("spc0-id0-writeignore=1");
! 345: UpdateLinePerf("spc0-id1-writeignore=1");
! 346: UpdateLinePerf("spc0-id2-writeignore=1");
! 347: UpdateLinePerf("spc0-id3-writeignore=1");
! 348: UpdateLinePerf("spc0-id4-writeignore=1");
! 349: UpdateLinePerf("spc0-id5-writeignore=1");
! 350: UpdateLinePerf("spc0-id6-writeignore=1");
! 351: UpdateLinePerf("virtio-block0-writeignore=1");
! 352: UpdateLinePerf("virtio-block1-writeignore=1");
! 353: UpdateLinePerf("virtio-block2-writeignore=1");
! 354: UpdateLinePerf("virtio-block3-writeignore=1");
! 355: UpdateLinePerf("virtio-block4-writeignore=1");
! 356: UpdateLinePerf("virtio-block5-writeignore=1");
! 357: UpdateLinePerf("virtio-block6-writeignore=1");
! 358: return true;
! 359: } else {
! 360: return UpdateLine(line, ConfigItem::FromOption, optname);
! 361: }
1.1 root 362: }
363:
364: // 更新1行分の共通処理。
1.1.1.10 root 365: // キーが見付からない場合、コマンドラインからならエラーとし、
366: // それ以外からの場合は警告のみで無視する。
1.1 root 367: // エラーが起きたらエラーメッセージを表示して false を返す。
368: bool
369: Config::UpdateLine(const std::string& line, ConfigItem::from_t from,
370: const std::string& where)
371: {
372: std::string key;
373: std::string val;
374:
375: // キーと値に分解
376: if (SplitKeyVal(&key, &val, line) == false) {
1.1.1.12 root 377: ConfigItem::PrintErr(from, where, "", line, "Syntax error");
1.1 root 378: return false;
379: }
380:
1.1.1.13 root 381: // キーが別名なら正規名に置換
382: key = GetCanonKey(key);
383:
1.1.1.10 root 384: // キーで検索
1.1 root 385: ConfigItem *itemptr = FindItem(key);
386: if (itemptr == NULL) {
1.1.1.14 root 387: switch (from) {
388: default:
389: case ConfigItem::FromHome:
1.1.1.15! root 390: case ConfigItem::FromPerf:
1.1.1.14 root 391: // 共通設定ファイルなら黙って無視する。
392: // このファイルには他機種向けの設定も並んでいる可能性があるため
393: // 無視してくれないと困る。
394: return true;
395:
396: case ConfigItem::FromConfig:
397: // VM 設定ファイルなら警告のみで無視する。
398: // このファイルに他機種向けの設定があるのはおかしいが
399: // 止めるほどではない。
400: ConfigItem::PrintErr(from, where, key, val, "Unknown key, ignored");
401: return true;
402:
403: case ConfigItem::FromOption:
404: // コマンドラインからの場合はエラーにする。
1.1.1.12 root 405: ConfigItem::PrintErr(from, where, key, val, "Unknown key");
1.1.1.10 root 406: return false;
407: }
1.1 root 408: }
409:
410: // 見付かったので更新
411: ConfigItem& item = *itemptr;
412: item.value = val;
413: item.from = from;
414: item.where = where;
415:
416: return true;
417: }
418:
419: // "key=val" 形式の行 line を分解するして *keyp, *valp に代入する。
420: // その際 key, val 前後の空白は取り除く。
421: // 失敗すれば false を返す。
422: /*static*/ bool
423: Config::SplitKeyVal(std::string *keyp, std::string *valp,
424: const std::string& line)
425: {
426: assert(keyp);
427: assert(valp);
428:
429: // キーと値に分解
430: auto pos = line.find('=');
431: if (pos == std::string::npos) {
432: return false;
433: }
434: auto key = line.substr(0, pos++);
435: auto val = line.substr(pos, line.size() - pos);
436:
1.1.1.8 root 437: *keyp = string_trim(key);
438: *valp = string_trim(val);
1.1 root 439:
440: return true;
441: }
442:
1.1.1.13 root 443: // キーがエイリアスなら正規名を返す。
444: // エイリアスでなければキーをそのまま返す。
445: const std::string&
446: Config::GetCanonKey(const std::string& key) const
447: {
448: for (const auto& p : aliases) {
449: const auto& alias = p.first;
450: const auto& canon = p.second;
451:
452: if (key == alias) {
453: return canon;
454: }
455: }
456:
457: return key;
458: }
459:
1.1.1.2 root 460: // 内容を表示する。
461: // all なら隠し設定も含めて表示。
1.1 root 462: void
1.1.1.2 root 463: Config::Show(bool all) const
1.1 root 464: {
1.1.1.2 root 465: assert(fixed);
466:
1.1 root 467: for (const auto& item : list) {
1.1.1.2 root 468: // '!' から始まるのは内部用変数なので隠す
469: if (!all && item.key[0] == '!') {
470: continue;
471: }
1.1 root 472: // ドットから始まるのは隠し設定で、初期値のままなら隠す
1.1.1.2 root 473: if (!all &&
474: item.key[0] == '.' && item.from == ConfigItem::FromInitial) {
1.1 root 475: continue;
476: }
477:
478: std::string buf = string_format("%s=\"%s\"",
479: item.key.c_str(), item.value.c_str());
480: if (buf.size() < 40) {
1.1.1.15! root 481: uint n = ((40 - buf.size()) + 7) / 8;
1.1 root 482: buf.append(n, '\t');
483: } else {
484: buf.push_back('\t');
485: }
486:
487: std::string fromstr;
488: switch (item.from) {
489: case ConfigItem::FromInitial:
490: fromstr = "initial value";
491: break;
1.1.1.14 root 492: case ConfigItem::FromHome:
1.1 root 493: case ConfigItem::FromConfig:
494: fromstr = item.where;
495: break;
496: case ConfigItem::FromOption:
1.1.1.12 root 497: fromstr = "option " + item.where;
1.1 root 498: break;
1.1.1.15! root 499: case ConfigItem::FromPerf:
! 500: fromstr = "option --perf";
! 501: break;
1.1 root 502: default:
1.1.1.15! root 503: fromstr = string_format("corrupted item.from=%u for key=%s",
! 504: (uint)item.from, item.key.c_str());
1.1.1.12 root 505: break;
1.1 root 506: }
507:
508: printf("%s(%s)\n", buf.c_str(), fromstr.c_str());
509: }
510: }
511:
512: // key から ConfigItem を取得する。見付からなければ assert する。
513: const ConfigItem&
1.1.1.2 root 514: Config::Find(const std::string& key) const
1.1 root 515: {
516: for (const auto& item : list) {
517: if (key == item.key) {
518: return item;
519: }
520: }
1.1.1.10 root 521: PANIC("Config::Find() \"%s\" not found", key.c_str());
1.1.1.2 root 522: }
523:
524: // key のデフォルト値を差し替える。key が見付からなければ assert する。
525: void
526: Config::SetDefault(const std::string& key, int val)
527: {
528: std::string valstr = std::to_string(val);
529: SetDefault(key, valstr);
1.1 root 530: }
531:
1.1.1.2 root 532: // key のデフォルト値を差し替える。key が見付からなければ assert する。
533: void
534: Config::SetDefault(const std::string& key, const std::string& val)
1.1 root 535: {
1.1.1.2 root 536: assert(fixed == false);
537:
1.1 root 538: for (auto& item : list) {
539: if (key == item.key) {
1.1.1.2 root 540: item.SetDefault(val);
541: return;
1.1 root 542: }
543: }
1.1.1.2 root 544: assertmsg(0, "Config::SetDefault() \"%s\" not found\n", key.c_str());
1.1 root 545: }
546:
547: // key から ConfigItem を返す。見付からなければ NULL を返す。
548: // (こっちは内部で変更するために使う)
549: ConfigItem *
550: Config::FindItem(const std::string& key)
551: {
552: for (auto& item : list) {
553: if (key == item.key) {
554: return &item;
555: }
556: }
557: return NULL;
558: }
559:
1.1.1.12 root 560: // これ以降は書き込み禁止。
561: bool
1.1.1.2 root 562: Config::Fix()
563: {
564: assert(fixed == false);
565:
1.1.1.11 root 566: // ここで、この機種に不要な変数を削除する。
1.1.1.12 root 567: // が、その前にその変数がユーザから指定されていればエラーにする。
1.1.1.11 root 568: for (auto it = list.begin(); it != list.end(); ) {
569: ConfigItem& item = *it;
570: VMCap vmcap = item.GetVMCap();
571: if (gMainApp.Has(vmcap) == false) {
1.1.1.12 root 572: // この機種用ではない
1.1.1.14 root 573: switch (item.from) {
574: case ConfigItem::FromConfig:
575: case ConfigItem::FromOption:
576: // 明示的に更新されていればエラー
1.1.1.12 root 577: item.Err("Not supported in this vmtype");
578: return false;
1.1.1.14 root 579: default:
580: break;
1.1.1.12 root 581: }
582:
1.1.1.11 root 583: it = list.erase(it);
584: } else {
585: ++it;
586: }
587: }
588:
1.1.1.2 root 589: fixed = true;
1.1.1.12 root 590: return true;
1.1.1.2 root 591: }
592:
1.1 root 593:
594: //
595: // 設定項目
596: //
597:
1.1.1.10 root 598: // 値を整数値として取得してみる。
599: bool
600: ConfigItem::TryInt(int *val) const
601: {
602: char *endp;
603:
604: if (value.empty()) {
605: return false;
606: }
607:
608: errno = 0;
609: int r = strtol(value.c_str(), &endp, 10);
610: if (errno == ERANGE || *endp != '\0') {
611: return false;
612: }
613: *val = r;
614: return true;
615: }
616:
1.1.1.12 root 617: // 値を double 値として取得してみる。
618: bool
619: ConfigItem::TryDouble(double *val) const
620: {
621: char *endp;
622:
623: if (value.empty()) {
624: return false;
625: }
626:
627: errno = 0;
628: double res = strtod(value.c_str(), &endp);
629: if (errno) {
630: return false;
631: }
632: *val = res;
633: return true;
634: }
635:
1.1.1.15! root 636: // b ^ e
! 637: static inline int ipow(int b, int e)
! 638: {
! 639: int rv = 1;
! 640: #if 1
! 641: for (int i = 0; i < e; i++) {
! 642: rv *= b;
! 643: }
! 644: #else
! 645: // e <= 3 とかだと上のほうが速そう。
! 646: for (; e != 0; e >>= 1) {
! 647: if ((e & 1)) {
! 648: rv *= b;
! 649: }
! 650: b *= b;
! 651: }
! 652: #endif
! 653: return rv;
! 654: }
! 655:
! 656: // 値を固定小数点値として取得してみる。
! 657: bool
! 658: ConfigItem::TryFixedDecimal(int *val, int digit) const
! 659: {
! 660: char *endp;
! 661: bool neg = false;
! 662:
! 663: if (value.empty()) {
! 664: return false;
! 665: }
! 666:
! 667: errno = 0;
! 668: int r = strtol(value.c_str(), &endp, 10);
! 669: if (errno == ERANGE || !(*endp == '\0' || *endp == '.')) {
! 670: return false;
! 671: }
! 672: if (r < 0) {
! 673: r = -r;
! 674: neg = true;
! 675: }
! 676: r *= ipow(10, digit);
! 677: if (*endp == '.') {
! 678: char *p = endp + 1;
! 679: errno = 0;
! 680: int f = strtol(p, &endp, 10);
! 681: if (errno == ERANGE || *endp != '\0') {
! 682: return false;
! 683: }
! 684: int n = endp - p;
! 685: if (n <= digit) {
! 686: r += f * ipow(10, digit - n);
! 687: } else {
! 688: r += f / ipow(10, n - digit) + (p[digit] >= '5');
! 689: }
! 690: }
! 691: *val = neg ? -r : r;
! 692: return true;
! 693: }
! 694:
1.1 root 695: // デフォルト値を差し替える
696: void
697: ConfigItem::SetDefault(const std::string& val)
698: {
699: if (from == FromInitial) {
700: value = val;
701: }
702: }
703:
704: void
705: ConfigItem::Err() const
706: {
707: // 定型文
1.1.1.12 root 708: Err("Invalid argument");
1.1 root 709: }
710:
711: void
712: ConfigItem::Err(const char *fmt, ...) const
713: {
714: char buf[1024];
715: va_list ap;
716:
717: va_start(ap, fmt);
718: vsnprintf(buf, sizeof(buf), fmt, ap);
719: va_end(ap);
720:
721: std::string msg(buf);
722: Err(msg);
723: }
724:
725: void
726: ConfigItem::Err(const std::string& msg) const
727: {
1.1.1.10 root 728: PrintErr(from, where, key, value, msg);
729: }
730:
1.1.1.12 root 731: // この item についてエラーを表示する。
732: // key=val の '=' がない場合のみ key を空、value を行全体として呼ぶ。
1.1.1.10 root 733: /*static*/ void
734: ConfigItem::PrintErr(ConfigItem::from_t from, const std::string& where,
735: const std::string& key, const std::string& value, const std::string& msg)
736: {
1.1 root 737: std::string fromstr;
738:
739: switch (from) {
740: case FromInitial:
1.1.1.12 root 741: // 初期値の場合 key が空なことは起きないはず。
742: // というか初期値でエラーが起きることも普通はないはず。
743: fromstr = "initial value: " + key + "=" + value;
1.1 root 744: break;
1.1.1.12 root 745:
1.1.1.14 root 746: case FromHome:
1.1 root 747: case FromConfig:
1.1.1.12 root 748: // 設定ファイルでのエラー。where はファイル名と行番号。
749: fromstr = where + ": ";
750: if (key.empty() == false) {
751: fromstr += key;
1.1.1.13 root 752: fromstr += "=";
1.1.1.12 root 753: }
754: fromstr += value;
1.1 root 755: break;
1.1.1.12 root 756:
1.1 root 757: case FromOption:
1.1.1.15! root 758: case FromPerf:
1.1.1.12 root 759: // コマンドラインオプションの場合は where は
760: // "--fontsize" とか "-V" なので、
761: // "-V" なら (key =) value を追加し、
762: // それ以外なら value のみ追加がいいか。
763: fromstr = "option " + where + " ";
1.1.1.14 root 764: if (where.find("-V") != std::string::npos) {
1.1.1.12 root 765: if (key.empty() == false) {
766: fromstr += key;
767: fromstr += "=";
768: }
769: }
770: fromstr += value;
1.1 root 771: break;
1.1.1.10 root 772:
1.1.1.12 root 773: default:
1.1.1.15! root 774: fromstr = string_format("corrupted item.from=%u for key=%s",
! 775: (uint)from, key.c_str());
1.1.1.12 root 776: break;
1.1.1.10 root 777: }
778:
1.1.1.12 root 779: warnx("%s: %s", fromstr.c_str(), msg.c_str());
1.1 root 780: }
781:
782:
783: //
784: // 設定ファイル
785: //
786:
787: // コンストラクタ
1.1.1.14 root 788: ConfigFile::ConfigFile(const std::string& filepath_, ConfigItem::from_t from_)
1.1 root 789: {
790: filepath = filepath_;
1.1.1.14 root 791: from = from_;
1.1 root 792: }
793:
794: // デストラクタ
795: ConfigFile::~ConfigFile()
796: {
797: }
798:
1.1.1.12 root 799: // ファイルの読み込み。
800: // 成功すれば true を、失敗すればメッセージを出力して false を返す。
801: // ファイルがないのは正常とする (なければスルーするため)。
802: // ファイルがあって読めなければ失敗 (エラー終了したいので)。
1.1 root 803: bool
804: ConfigFile::Load()
805: {
806: char buf[1024];
807: FILE *fp;
808:
1.1.1.15! root 809: if (filepath.empty()) {
! 810: return true;
! 811: }
! 812:
1.1 root 813: fp = fopen(filepath.c_str(), "r");
814: if (fp == NULL) {
1.1.1.12 root 815: if (errno == ENOENT) {
816: return true;
817: }
1.1 root 818: warn("%s", filepath.c_str());
819: return false;
820: }
821:
822: for (int line = 1; fgets(buf, sizeof(buf), fp) != NULL; line++) {
823: // 空行とコメント行を無視
824: rtrim(buf);
825: if (buf[0] == '#') {
826: buf[0] = '\0';
827: }
828: if (buf[0] == '\0') {
829: continue;
830: }
831:
832: // ここでは記憶するだけ
833: lines.emplace_back(buf, line);
834: }
835:
836: fclose(fp);
837: return true;
838: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.