|
|
1.1 root 1: //
2: // nono
1.1.1.3 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.8 ! root 7: #include "wxdumpmonitor.h"
1.1 root 8: #include "wxmainframe.h"
9: #include "wxmainview.h"
10: #include "wxtextpanel.h"
1.1.1.4 root 11: #include "wxversion.h"
1.1 root 12: #include "mainapp.h"
1.1.1.3 root 13: #include "mpu680x0.h"
14: #include "mpu88xx0.h"
1.1.1.7 root 15: #include "scheduler.h"
1.1.1.8 ! root 16: #include <algorithm>
1.1.1.3 root 17: #include <wx/intl.h>
1.1 root 18:
19: // イベントタイプの定義
1.1.1.3 root 20: wxDEFINE_EVENT(WXW_EVT_HALT_NOTIFY, wxCommandEvent);
1.1 root 21:
1.1.1.8 ! root 22: class WXApp : public wxApp
1.1 root 23: {
1.1.1.6 root 24: using inherited = wxApp;
1.1 root 25: public:
26: bool OnInit();
1.1.1.6 root 27: int OnRun() override;
1.1 root 28: private:
29: bool ParseMonitors(const wxString& str);
1.1.1.8 ! root 30: void ShowMonitorsName();
1.1 root 31: int SearchMonitorName(const char *name);
1.1.1.3 root 32:
33: wxLocale locale;
1.1 root 34: };
35:
1.1.1.3 root 36: // IMPLEMENT_APP() は闇マクロすぎて clang のちからには耐えられない
37: #if defined(__clang__)
38: #pragma clang diagnostic push
39: #pragma clang diagnostic ignored "-Weverything"
40: #endif
1.1 root 41: IMPLEMENT_APP(WXApp)
1.1.1.3 root 42: #if defined(__clang__)
43: #pragma clang diagnostic pop
44: #endif
1.1 root 45:
46: bool
47: WXApp::OnInit()
48: {
1.1.1.6 root 49: return true;
50: }
51:
52: int
53: WXApp::OnRun()
54: {
1.1.1.5 root 55: int rv;
56:
1.1.1.7 root 57: rv = gMainApp.Init1(false, argc, argv);
1.1.1.5 root 58: if (rv != MainApp::PASS) {
1.1.1.6 root 59: return rv;
1.1 root 60: }
61:
1.1.1.3 root 62: // 環境変数 $NONO_BUILD_HOME が定義されていればカタログ検索パスに
63: // $NONO_BUILD_HOME/po を追加する (システムパスより前に挿入される)。
64: // カタログ開発時にワークツリーにあるカタログを見るため。
65: locale.Init(wxLANGUAGE_DEFAULT);
66: const char *build_home = getenv("NONO_BUILD_HOME");
67: if (build_home) {
68: wxString path(build_home);
69: path += "/po";
70: wxLocale::AddCatalogLookupPathPrefix(path);
71: }
72: locale.AddCatalog("nono");
73:
1.1.1.2 root 74: // --fontsize テキスト系コントロールのフォントサイズ
75: // 紛らわしいが ::global_fontsize は 12, 16 とかいう値。
1.1.1.4 root 76: // WXTextPanel::global_fontsize (FontId) は enum 値。
77: FontId fontid;
1.1.1.2 root 78: switch (gMainApp.fontsize) {
79: case 12:
1.1.1.4 root 80: fontid = FontId::_6x12;
1.1.1.2 root 81: break;
82: case 16:
1.1.1.4 root 83: fontid = FontId::_8x16;
1.1.1.2 root 84: break;
85: default:
86: warnx("invalid fontsize: %d", gMainApp.fontsize);
1.1.1.7 root 87: return EXIT_FAILURE;
1.1 root 88: }
1.1.1.4 root 89: WXTextPanel::global_fontid = fontid;
90:
91: // グローバルオブジェクト (どこでやるのがいいか)
92: gHostInfo.reset(new HostInfoMonitor());
1.1 root 93:
1.1.1.8 ! root 94: // これ以降モニタの登録をしてはいけない。
! 95: gMonitorManager.Fix();
! 96:
1.1 root 97: // -M 起動時に表示するモニタ
1.1.1.2 root 98: if (!gMainApp.monitor_opt.empty()) {
99: if (!ParseMonitors(gMainApp.monitor_opt)) {
1.1.1.7 root 100: return EXIT_FAILURE;
1.1 root 101: }
102: }
103:
1.1.1.2 root 104: // -s screen scale
105: WXMainView::screen_scale = gMainApp.screen_scale;
1.1 root 106:
1.1.1.7 root 107: // 引数処理が終わったので、スレッド作成を伴う初期化。
108: if (!gMainApp.Init2()) {
109: return EXIT_FAILURE;
110: }
111:
112: // VM にコールバックを登録
113: gScheduler->SetPowerOffCallback(wxmainframe_poweroff_callback);
114: if (gMPU680x0) {
115: gMPU680x0->SetHaltCallback(wxmainframe_halt_callback, this);
1.1 root 116: }
117:
1.1.1.2 root 118: // メインウィンドウ
119: gMainFrame = new WXMainFrame(NULL);
120: gMainFrame->Show(true);
121: SetTopWindow(gMainFrame);
1.1.1.6 root 122:
123: return inherited::OnRun();
1.1 root 124: }
125:
126: // -M オプションの解析。書式は
1.1.1.8 ! root 127: // -M <arg>[,<arg>[,...]]
! 128: // <arg> のどれかが "help" なら有効な名前を列挙して終了。
! 129: // <arg> は通常モニタ名(サブウィンドウ名)のみだが
! 130: // memdump* の場合のみ <name>=<hexaddr> 形式を受け付ける。
! 131: // 継続する場合は true、しない場合は false を返す。
1.1 root 132: bool
133: WXApp::ParseMonitors(const wxString& str)
134: {
1.1.1.8 ! root 135: std::vector<std::string> args = string_split(str, ',');
1.1 root 136:
1.1.1.8 ! root 137: // "help" があればヘルプを表示して終了
! 138: for (const auto& arg : args) {
! 139: if (arg == "help") {
! 140: ShowMonitorsName();
! 141: return false;
1.1 root 142: }
143: }
144:
1.1.1.8 ! root 145: // 一致するモニタ(ウィンドウ)の開始フラグを立てる
! 146: for (const auto& arg : args) {
! 147: std::string name;
! 148: std::string value;
! 149:
! 150: auto pos = arg.find('=');
! 151: if (pos != std::string::npos) {
! 152: name = arg.substr(0, pos);
! 153: value = arg.substr(++pos);
! 154: } else {
! 155: name = arg;
1.1.1.3 root 156: }
1.1.1.8 ! root 157:
! 158: // この名前のウィンドウを探して start フラグを立てる
! 159: int id = SearchMonitorName(name.c_str());
! 160: if (id < 0) {
1.1 root 161: return false;
162: }
1.1.1.8 ! root 163: WXMainFrame::subwindow_start[id] = true;
! 164:
! 165: // 値付き memdump の処理
! 166: if (IS_MONITOR_MEMDUMP(id) && value.empty() == false) {
! 167: char *end;
! 168: errno = 0;
! 169: unsigned long u = strtoul(value.c_str(), &end, 16);
! 170: if (end == optarg || end[0] != '\0') {
! 171: warnx("%s: syntax error on monitor address", value.c_str());
! 172: return -1;
! 173: }
! 174: if (errno == ERANGE || u > 0xffffffff) {
! 175: errno = ERANGE;
! 176: warn("%s", value.c_str());
! 177: return -1;
! 178: }
! 179: WXMemdumpWindow::SetStickyAddr(id, (uint32)u);
! 180: }
1.1 root 181: }
182: return true;
183: }
184:
1.1.1.8 ! root 185: // モニタ名の一覧を表示する
! 186: void
! 187: WXApp::ShowMonitorsName()
! 188: {
! 189: std::vector<int> list;
! 190:
! 191: // モニターは登録されていれば列挙
! 192: // (登録されているものを全部列挙ではないことに注意)
! 193: for (int id = ID_MONITOR_START; id <= ID_MONITOR_END; id++) {
! 194: if (gMonitorManager.Find(id)) {
! 195: list.push_back(id);
! 196: }
! 197: }
! 198: // サブウィンドウは機種情報から判断
! 199: for (int id = ID_SUBWIN_START; id <= ID_SUBWIN_END; id++) {
! 200: vmf_t feature = gMonitorManager.GetFeature(id);
! 201: if (gMainApp.HasVMFeature(feature)) {
! 202: list.push_back(id);
! 203: }
! 204: }
! 205:
! 206: // 一覧を表示
! 207: std::string msg = MonitorManager::MakeListString(list);
! 208: printf("%s", msg.c_str());
! 209: }
! 210:
! 211: // モニタ名 name を検索し、一つに確定すればその id を返す。
! 212: // 確定しない、あるいは一致しない場合はエラーメッセージを表示し -1 を返す。
! 213: //
! 214: // "memdump" (数字なし) は空いてる memdump<N> を順に使用する。
! 215: // ただし今の所この処理は1パスで前から順に処理しているだけなので、
! 216: // "memdump0,memdump" は指定可能だが(2つ目が memdump1 になる)、
! 217: // "memdump,memdump0" は memdump0 を2回指定したことになる。
1.1 root 218: int
219: WXApp::SearchMonitorName(const char *name)
220: {
1.1.1.8 ! root 221: std::vector<int> candidates;
! 222: std::vector<std::string> cand_names;
! 223:
! 224: for (int id = ID_MONITOR_START; id <= ID_SUBWIN_END; id++) {
! 225: if (id < ID_SUBWIN_START) {
! 226: // モニターは登録されていなければ除外する
! 227: if (gMonitorManager.Find(id) == NULL) {
! 228: continue;
! 229: }
! 230: } else {
! 231: // サブウィンドウは該当機種でなければ除外する
! 232: vmf_t feature = gMonitorManager.GetFeature(id);
! 233: if (gMainApp.HasVMFeature(feature) == false) {
! 234: continue;
! 235: }
! 236: }
! 237:
! 238: const auto& aliases = gMonitorManager.GetAliases(id);
! 239:
! 240: bool matched = false;
! 241: for (const auto& alias : aliases) {
! 242: // 全文一致したら確定
! 243: // ("lunafb" と "lunafb0" みたいなのがあるため)
! 244: if (alias == name) {
! 245: return id;
! 246: }
! 247:
! 248: // 部分一致したら名前はすべて覚えておく
! 249: if (starts_with_ignorecase(alias, name)) {
! 250: cand_names.push_back(alias);
! 251: matched = true;
! 252: }
! 253: }
! 254: // 同じオブジェクトで別名が複数回部分一致しても、1回として数える
! 255: if (matched) {
! 256: candidates.push_back(id);
! 257: }
! 258: }
! 259:
! 260: if (candidates.empty()) {
! 261: // 一致しない
! 262: warnx("Unknown window name \"%s\"", name);
! 263: return -1;
! 264: } else if (candidates.size() == 1) {
! 265: // 部分一致したのが1つだけなら確定
! 266: return candidates[0];
! 267: } else {
! 268: // 候補が複数あった
! 269:
! 270: // 候補が memdumpN のみなら無記名 memdump とする。
! 271: bool is_memdump = std::all_of(candidates.begin(), candidates.end(),
! 272: [](int x) { return IS_MONITOR_MEMDUMP(x); }
! 273: );
! 274: if (is_memdump) {
! 275: // この時点で空いてるものを返す
! 276: for (int i = 0; i < MAX_MEMDUMP_MONITOR; i++) {
! 277: int id = ID_MONITOR_MEMDUMP0 + i;
! 278: if (WXMainFrame::subwindow_start[id] == false) {
! 279: return id;
! 280: }
! 281: }
! 282: // 空きがなければエラー
! 283: warnx("No more memdump windows available");
! 284: return -1;
! 285: }
! 286:
! 287: // そうでなければ、候補を表示
! 288: std::string candstr;
! 289: for (const auto& cname : cand_names) {
! 290: candstr += ' ';
! 291: candstr += cname;
1.1 root 292: }
1.1.1.8 ! root 293: warnx("Ambiguous window name \"%s\": candidates are%s",
! 294: name, candstr.c_str());
! 295: return -1;
1.1 root 296: }
297: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.