#include "frontends/common2/programoptions.h" #include "frontends/common2/utils.h" #include "frontends/common2/fileregistry.h" #include "linux/version.h" #include "linux/paddle.h" #include #include "StdAfx.h" #include "Memory.h" #include "Log.h" #include "Disk.h" #include "Utilities.h" #include "Core.h" #include #include namespace po = boost::program_options; namespace { void parseGeometry(const std::string & s, common2::Geometry & geometry) { std::smatch m; if (std::regex_match(s, m, std::regex("^(\\d+)x(\\d+)(\\+(\\d+)\\+(\\d+))?$"))) { const size_t groups = m.size(); if (groups == 6) { geometry.width = std::stoi(m.str(1)); geometry.height = std::stoi(m.str(2)); if (!m.str(3).empty()) { geometry.x = std::stoi(m.str(4)); geometry.y = std::stoi(m.str(5)); } return; } } throw std::runtime_error("Invalid sizes: " + s); } } namespace common2 { EmulatorOptions::EmulatorOptions() { memclear = g_nMemoryClearType; configurationFile = GetConfigFile("applewin.conf"); } bool getEmulatorOptions(int argc, const char * argv [], const std::string & edition, EmulatorOptions & options) { const std::string name = "Apple Emulator for " + edition + " (based on AppleWin " + getVersion() + ")"; po::options_description desc(name); desc.add_options() ("help,h", "Print this help message") ; po::options_description configDesc("configuration"); configDesc.add_options() ("conf", po::value()->default_value(options.configurationFile), "Select configuration file") ("registry,r", po::value>(), "Registry options section.path=value") ("qt-ini,q", "Use Qt ini file (read only)") ; desc.add(configDesc); po::options_description diskDesc("Disk"); diskDesc.add_options() ("d1,1", po::value(), "Disk in 1st drive") ("d2,2", po::value(), "Disk in 2nd drive") ; desc.add(diskDesc); po::options_description snapshotDesc("Snapshot"); snapshotDesc.add_options() ("state-filename,f", po::value(), "Set snapshot filename") ("load-state,s", po::value(), "Load snapshot from file") ; desc.add(snapshotDesc); po::options_description memoryDesc("Memory"); memoryDesc.add_options() ("memclear", po::value()->default_value(options.memclear), "Memory initialization pattern [0..7]") ; desc.add(memoryDesc); po::options_description emulatorDesc("Emulator"); emulatorDesc.add_options() ("log", "Log to AppleWin.log") ("headless", "Headless: disable video (freewheel)") ("fixed-speed", "Fixed (non-adaptive) speed") ("ntsc,nt", "NTSC: execute NTSC code") ("benchmark,b", "Benchmark emulator") ("rom", po::value(), "Custom 12k/16k ROM") ("f8rom", po::value(), "Custom 2k ROM") ; desc.add(emulatorDesc); po::options_description sdlDesc("SDL"); sdlDesc.add_options() ("sdl-driver", po::value()->default_value(options.sdlDriver), "SDL driver") ("gl-swap", po::value()->default_value(options.glSwapInterval), "SDL_GL_SwapInterval") ("no-imgui", "Plain SDL2 renderer") ("geometry", po::value(), "WxH[+X+Y]") ; desc.add(sdlDesc); po::options_description paddleDesc("Paddle"); paddleDesc.add_options() ("no-squaring", "Gamepad range is (already) a square") ("device-name", po::value(), "Gamepad device name") ; desc.add(paddleDesc); po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); if (vm.count("help")) { std::cout << desc << std::endl; return false; } options.configurationFile = vm["conf"].as(); options.useQtIni = vm.count("qt-ini"); options.sdlDriver = vm["sdl-driver"].as(); options.glSwapInterval = vm["gl-swap"].as(); options.imgui = vm.count("no-imgui") == 0; if (vm.count("registry")) { options.registryOptions = vm["registry"].as >(); } if (vm.count("d1")) { options.disk1 = vm["d1"].as(); } if (vm.count("d2")) { options.disk2 = vm["d2"].as(); } if (vm.count("load-state")) { options.snapshotFilename = vm["load-state"].as(); options.loadSnapshot = true; } if (vm.count("state-filename")) { options.snapshotFilename = vm["state-filename"].as(); options.loadSnapshot = false; } if (vm.count("rom")) { options.customRom = vm["rom"].as(); } if (vm.count("f8rom")) { options.customRomF8 = vm["f8rom"].as(); } const int memclear = vm["memclear"].as(); if (memclear >=0 && memclear < NUM_MIP) options.memclear = memclear; options.benchmark = vm.count("benchmark") > 0; options.headless = vm.count("headless") > 0; options.log = vm.count("log") > 0; options.ntsc = vm.count("ntsc") > 0; options.fixedSpeed = vm.count("fixed-speed") > 0; options.paddleSquaring = vm.count("no-squaring") == 0; if (vm.count("device-name")) { options.paddleDeviceName = vm["device-name"].as(); } if (vm.count("geometry")) { options.geometry.empty = false; parseGeometry(vm["geometry"].as(), options.geometry); } return true; } catch (const po::error& e) { std::cerr << "ERROR: " << e.what() << std::endl << desc << std::endl; return false; } catch (const std::exception & e) { std::cerr << "ERROR: " << e.what() << std::endl; return false; } } void applyOptions(const EmulatorOptions & options) { g_nMemoryClearType = options.memclear; LPCSTR szImageName_drive[NUM_DRIVES] = {nullptr, nullptr}; bool driveConnected[NUM_DRIVES] = {true, true}; if (!options.disk1.empty()) { szImageName_drive[DRIVE_2] = options.disk1.c_str(); } if (!options.disk2.empty()) { szImageName_drive[DRIVE_2] = options.disk2.c_str(); } bool bBoot; InsertFloppyDisks(SLOT6, szImageName_drive, driveConnected, bBoot); if (!options.snapshotFilename.empty()) { setSnapshotFilename(options.snapshotFilename, options.loadSnapshot); } if (!options.customRom.empty()) { CloseHandle(g_hCustomRom); g_hCustomRom = CreateFile(options.customRom.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, nullptr); if (g_hCustomRom == INVALID_HANDLE_VALUE) { LogFileOutput("Init: Failed to load Custom ROM: %s\n", options.customRom.c_str()); } } if (!options.customRomF8.empty()) { CloseHandle(g_hCustomRomF8); g_hCustomRomF8 = CreateFile(options.customRomF8.c_str(), GENERIC_READ, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, nullptr); if (g_hCustomRomF8 == INVALID_HANDLE_VALUE) { LogFileOutput("Init: Failed to load custom F8 ROM: %s\n", options.customRomF8.c_str()); } } Paddle::setSquaring(options.paddleSquaring); } }