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