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