--- nono/lib/mainapp.cpp 2026/04/29 17:04:40 1.1.1.5 +++ nono/lib/mainapp.cpp 2026/04/29 17:04:51 1.1.1.7 @@ -22,7 +22,7 @@ MainApp::ShowHelp(bool all) const printf("usage: %s []\n", getprogname()); p("-A load and execute host binary (a.out or ELF)"); - p("-c vm directory"); + p("-c vm directory or configuration file"); p("-f fast mode"); if (IsGUI()) p("--fontsize fontsize in monitors {12,16} (default:12)"); @@ -65,13 +65,14 @@ static struct option longopts[] = { { NULL, 0, NULL, 0 }, }; -// 起動時の処理、VM の実行開始前まで。 +// VM の初期化、ステージ1。 +// VM 作成と設定確定あたりまで。スレッド生成を伴わないもの。 // 所々 CLI と GUI で処理が違う。 // 戻り値は以下のいずれか。 // MainApp::PASS .. 実行を継続(通常パス) // EXIT_SUCCESS / EXIT_FAILURE .. この終了コードでアプリケーションを終了 int -MainApp::Init(bool is_cli_, int ac, char *av[]) +MainApp::Init1(bool is_cli_, int ac, char *av[]) { is_cli = is_cli_; @@ -87,8 +88,8 @@ MainApp::Init(bool is_cli_, int ac, char // 設定を作成。コンストラクタで初期値を用意 gConfig.reset(new Config()); - // 引数で指定されたディレクトリの設定ファイルを読み込んで設定を更新 - ConfigFile file(vmdir + "nono.cfg"); + // 引数で指定されたディレクトリの設定ファイルがあれば読み込んで設定を更新 + ConfigFile file(vmfile); if (file.Load() == false) { return EXIT_FAILURE; } @@ -132,7 +133,7 @@ MainApp::Init(bool is_cli_, int ac, char break; case VMTYPE_LUNA1: - gVM.reset(new VM_LUNA()); + gVM.reset(new VM_LUNA1()); break; case VMTYPE_RXZ: @@ -149,6 +150,7 @@ MainApp::Init(bool is_cli_, int ac, char // 動的なコンストラクション if (!gVM->Create()) { + gVM.reset(); return EXIT_FAILURE; } @@ -158,24 +160,26 @@ MainApp::Init(bool is_cli_, int ac, char gConfig->Fix(); if (show_config) { gConfig->Show(show_config - 1); + gVM.reset(); return EXIT_SUCCESS; } // ログレベルを設定。コンストラクト後すぐに行う。 // -L help もここで処理。 if (!ParseLogopt()) { + gVM.reset(); return EXIT_FAILURE; } return PASS; } -// VM の実行部分。 -// Init() で引数を受け付けてから Start() でデバッガスレッドなどを起動するが、 +// VM の初期化、ステージ2。スレッド生成を伴う。 +// Init1() で引数を受け付けてから Init2() でデバッガスレッドなどを起動するが、 // -Mhelp とかが指定された場合はここでスレッド開始する前にプロセスを終了する -// 必要があるので、分けてある。 +// 必要があるので分けてある。wxapp.cpp も参照。 bool -MainApp::Start() +MainApp::Init2() { // VM 初期化。 // これ以降はスレッドを開始したかもしれないので false を返す際には @@ -201,11 +205,14 @@ MainApp::Start() bool MainApp::ParseOpt(int ac, char *av[]) { + struct stat st; + const char *cpath; int b; int c; fontsize = 12; screen_scale = 1.0; + cpath = "."; while ((c = getopt_long(ac, av, "A:b:B:c:CdDfhL:M:s:vV:X:", longopts, NULL)) != -1) { @@ -228,7 +235,11 @@ MainApp::ParseOpt(int ac, char *av[]) break; case 'c': - vmdir = std::string(optarg); + cpath = optarg; + // 空文字列なら再び初期値に + if (cpath[0] == '\0') { + cpath = "."; + } break; case 'C': @@ -320,12 +331,33 @@ MainApp::ParseOpt(int ac, char *av[]) } } - // vmdir に '/' を付けておく - if (vmdir.empty()) { - vmdir = "."; + // 引数がディレクトリなら、それを VM ディレクトリとし、その中の + // nono.cfg を設定ファイルとする。 + // 引数がファイルなら、それを設定ファイルとし、そのファイルがある + // ディレクトリを VM ディレクトリとする。 + // -c DIR => vmdir = DIR, vmfile = DIR/nono.cfg + // -c DIR/FILE => vmdir = DIR, vmfile = FILE + if (stat(cpath, &st) < 0) { + warn("stat %s", cpath); + return false; } - if (vmdir.back() != '/') { - vmdir += '/'; + if (S_ISDIR(st.st_mode)) { + vmdir = std::string(cpath); + if (vmdir.back() != '/') { + vmdir += '/'; + } + vmfile = vmdir + "nono.cfg"; + } else if (S_ISREG(st.st_mode)) { + vmfile = std::string(cpath); + auto pos = vmfile.rfind('/'); + if (pos != std::string::npos) { + vmdir = vmfile.substr(0, pos + 1); + } else { + vmdir = "./"; + } + } else { + warnx("-c %s: path must be file or directory", cpath); + return false; } // CLI 版で -Mhelp つけても黙って起動するのはさすがにどうかと思う。 @@ -439,7 +471,7 @@ MainApp::ParseLogopt() printf("invalid logname '%s'\n", name); goto abort; } - } + } } rv = true;