diff --git a/Configurable/StandardOptions.cpp b/Configurable/StandardOptions.cpp new file mode 100644 index 000000000..bc72fce3e --- /dev/null +++ b/Configurable/StandardOptions.cpp @@ -0,0 +1,76 @@ +// +// StandardOptions.cpp +// Clock Signal +// +// Created by Thomas Harte on 20/11/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#include "StandardOptions.hpp" + +namespace { + +/*! + Appends a Boolean selection of @c selection for option @c name to @c selection_set. +*/ +void append_bool(Configurable::SelectionSet &selection_set, const std::string &name, bool selection) { + selection_set[name] = std::unique_ptr(new Configurable::BooleanSelection(selection)); +} + +/*! + Enquires for a Boolean selection for option @c name from @c selections_by_option, storing it to @c result if found. +*/ +bool get_bool(const Configurable::SelectionSet &selections_by_option, const std::string &name, bool &result) { + auto quickload = Configurable::selection(selections_by_option, "quickload"); + if(!quickload) return false; + result = quickload->value; + return true; +} + +} + +// MARK: - Standard option list builder +std::vector> Configurable::standard_options(Configurable::StandardOptions mask) { + std::vector> options; + if(mask & QuickLoadTape) options.emplace_back(new Configurable::BooleanOption("Load Tapes Quickly", "quickload")); + if(mask & DisplayRGBComposite) options.emplace_back(new Configurable::ListOption("Display", "display", {"composite", "rgb"})); + if(mask & AutomaticTapeMotorControl) options.emplace_back(new Configurable::BooleanOption("Automatic Tape Motor Control", "autotapemotor")); + return options; +} + +// MARK: - Selection appenders +void Configurable::append_quick_load_tape_selection(Configurable::SelectionSet &selection_set, bool selection) { + append_bool(selection_set, "quickload", selection); +} + +void Configurable::append_automatic_tape_motor_control_selection(SelectionSet &selection_set, bool selection) { + append_bool(selection_set, "autotapemotor", selection); +} + +void Configurable::append_display_selection(Configurable::SelectionSet &selection_set, Display selection) { + selection_set["display"] = std::unique_ptr(new Configurable::ListSelection((selection == Display::RGB) ? "rgb" : "composite")); +} + +// MARK: - Selection parsers +bool Configurable::get_quick_load_tape(const Configurable::SelectionSet &selections_by_option, bool &result) { + return get_bool(selections_by_option, "quickload", result); +} + +bool Configurable::get_automatic_tape_motor_control_selection(const SelectionSet &selections_by_option, bool &result) { + return get_bool(selections_by_option, "autotapemotor", result); +} + +bool Configurable::get_display(const Configurable::SelectionSet &selections_by_option, Configurable::Display &result) { + auto display = Configurable::selection(selections_by_option, "display"); + if(display) { + if(display->value == "rgb") { + result = Configurable::Display::RGB; + return true; + } + if(display->value == "composite") { + result = Configurable::Display::Composite; + return true; + } + } + return false; +} diff --git a/Configurable/StandardOptions.hpp b/Configurable/StandardOptions.hpp new file mode 100644 index 000000000..9c7fefb9d --- /dev/null +++ b/Configurable/StandardOptions.hpp @@ -0,0 +1,76 @@ +// +// StandardOptions.hpp +// Clock Signal +// +// Created by Thomas Harte on 20/11/2017. +// Copyright © 2017 Thomas Harte. All rights reserved. +// + +#ifndef StandardOptions_hpp +#define StandardOptions_hpp + +#include "Configurable.hpp" + +namespace Configurable { + +enum StandardOptions { + DisplayRGBComposite = (1 << 0), + QuickLoadTape = (1 << 1), + AutomaticTapeMotorControl = (1 << 2) +}; + +enum class Display { + RGB, + Composite +}; + +/*! + @returns An option list comprised of the standard names for all the options indicated by @c mask. +*/ +std::vector> standard_options(StandardOptions mask); + +/*! + Appends to @c selection_set a selection of @c selection for QuickLoadTape. +*/ +void append_quick_load_tape_selection(SelectionSet &selection_set, bool selection); + +/*! + Appends to @c selection_set a selection of @c selection for AutomaticTapeMotorControl. +*/ +void append_automatic_tape_motor_control_selection(SelectionSet &selection_set, bool selection); + +/*! + Appends to @c selection_set a selection of @c selection for DisplayRGBComposite. +*/ +void append_display_selection(SelectionSet &selection_set, Display selection); + +/*! + Attempts to discern a QuickLoadTape selection from @c selections_by_option. + + @param selections_by_option The user selections. + @param result The location to which the selection will be stored if found. + @returns @c true if a selection is found; @c false otherwise. +*/ +bool get_quick_load_tape(const SelectionSet &selections_by_option, bool &result); + +/*! + Attempts to discern an AutomaticTapeMotorControl selection from @c selections_by_option. + + @param selections_by_option The user selections. + @param result The location to which the selection will be stored if found. + @returns @c true if a selection is found; @c false otherwise. +*/ +bool get_automatic_tape_motor_control_selection(const SelectionSet &selections_by_option, bool &result); + +/*! + Attempts to discern a display RGB/composite selection from @c selections_by_option. + + @param selections_by_option The user selections. + @param result The location to which the selection will be stored if found. + @returns @c true if a selection is found; @c false otherwise. +*/ +bool get_display(const SelectionSet &selections_by_option, Display &result); + +} + +#endif /* StandardOptions_hpp */ diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index edf231b0f..a4aff72fb 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -24,11 +24,17 @@ #include "../../../Storage/Tape/Tape.hpp" #include "../../../Storage/Disk/Disk.hpp" +#include "../../../Configurable/StandardOptions.hpp" + #include namespace Commodore { namespace Vic20 { +std::vector> get_options() { + return Configurable::standard_options(Configurable::QuickLoadTape); +} + enum JoystickInput { Up = 0x04, Down = 0x08, @@ -638,25 +644,25 @@ class ConcreteMachine: // MARK: - Configuration options. std::vector> get_options() override { - std::vector> options; - options.emplace_back(new Configurable::BooleanOption("Load Tapes Quickly", "quickload")); - return options; + return Commodore::Vic20::get_options(); } void set_selections(const Configurable::SelectionSet &selections_by_option) override { - auto quickload = Configurable::selection(selections_by_option, "quickload"); - if(quickload) set_use_fast_tape_hack(quickload->value); + bool quickload; + if(Configurable::get_quick_load_tape(selections_by_option, quickload)) { + set_use_fast_tape_hack(quickload); + } } Configurable::SelectionSet get_accurate_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(false)); + Configurable::append_quick_load_tape_selection(selection_set, false); return selection_set; } Configurable::SelectionSet get_user_friendly_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(true)); + Configurable::append_quick_load_tape_selection(selection_set, true); return selection_set; } diff --git a/Machines/Commodore/Vic-20/Vic20.hpp b/Machines/Commodore/Vic-20/Vic20.hpp index a7e4f5e4b..ee52e03e7 100644 --- a/Machines/Commodore/Vic-20/Vic20.hpp +++ b/Machines/Commodore/Vic-20/Vic20.hpp @@ -41,6 +41,9 @@ enum Region { Swedish }; +/// @returns The options available for a Vic-20. +std::vector> get_options(); + class Machine: public CRTMachine::Machine, public ConfigurationTarget::Machine, diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 8e00ed376..b20b42a5f 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -8,6 +8,7 @@ #include "Electron.hpp" +#include "../../Configurable/StandardOptions.hpp" #include "../../Processors/6502/6502.hpp" #include "../../Storage/Tape/Tape.hpp" #include "../../ClockReceiver/ClockReceiver.hpp" @@ -24,6 +25,12 @@ namespace Electron { +std::vector> get_options() { + return Configurable::standard_options( + static_cast(Configurable::DisplayRGBComposite | Configurable::QuickLoadTape) + ); +} + class ConcreteMachine: public Machine, public CPU::MOS6502::BusHandler, @@ -418,31 +425,32 @@ class ConcreteMachine: // MARK: - Configuration options. std::vector> get_options() override { - std::vector> options; - options.emplace_back(new Configurable::BooleanOption("Load Tapes Quickly", "quickload")); - options.emplace_back(new Configurable::ListOption("Display", "display", {"composite", "rgb"})); - return options; + return Electron::get_options(); } void set_selections(const Configurable::SelectionSet &selections_by_option) override { - auto quickload = Configurable::selection(selections_by_option, "quickload"); - if(quickload) set_use_fast_tape_hack(quickload->value); + bool quickload; + if(Configurable::get_quick_load_tape(selections_by_option, quickload)) { + set_use_fast_tape_hack(quickload); + } - auto display = Configurable::selection(selections_by_option, "display"); - if(display) get_crt()->set_output_device((display->value == "rgb") ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + Configurable::Display display; + if(Configurable::get_display(selections_by_option, display)) { + get_crt()->set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + } } Configurable::SelectionSet get_accurate_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(false)); - selection_set["display"] = std::unique_ptr(new Configurable::ListSelection("composite")); + Configurable::append_quick_load_tape_selection(selection_set, false); + Configurable::append_display_selection(selection_set, Configurable::Display::Composite); return selection_set; } Configurable::SelectionSet get_user_friendly_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(true)); - selection_set["display"] = std::unique_ptr(new Configurable::ListSelection("rgb")); + Configurable::append_quick_load_tape_selection(selection_set, true); + Configurable::append_display_selection(selection_set, Configurable::Display::RGB); return selection_set; } diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index 53f05bd15..fbea6a3ce 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -33,6 +33,9 @@ enum ROMSlot: uint8_t { ROMSlotADFS1, ROMSlotADFS2 }; +/// @returns The options available for an Electron. +std::vector> get_options(); + /*! @abstract Represents an Acorn Electron. diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 985faef52..ef423aa56 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -23,11 +23,18 @@ #include "../../Storage/Tape/Parsers/Oric.hpp" #include "../../ClockReceiver/ForceInline.hpp" +#include "../../Configurable/StandardOptions.hpp" #include namespace Oric { +std::vector> get_options() { + return Configurable::standard_options( + static_cast(Configurable::DisplayRGBComposite | Configurable::QuickLoadTape) + ); +} + /*! Models the Oric's keyboard: eight key rows, containing a bitfield of keys set. @@ -429,31 +436,32 @@ class ConcreteMachine: // MARK: - Configuration options. std::vector> get_options() override { - std::vector> options; - options.emplace_back(new Configurable::BooleanOption("Load Tapes Quickly", "quickload")); - options.emplace_back(new Configurable::ListOption("Display", "display", {"composite", "rgb"})); - return options; + return Oric::get_options(); } void set_selections(const Configurable::SelectionSet &selections_by_option) override { - auto quickload = Configurable::selection(selections_by_option, "quickload"); - if(quickload) set_use_fast_tape_hack(quickload->value); + bool quickload; + if(Configurable::get_quick_load_tape(selections_by_option, quickload)) { + set_use_fast_tape_hack(quickload); + } - auto display = Configurable::selection(selections_by_option, "display"); - if(display) get_crt()->set_output_device((display->value == "rgb") ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + Configurable::Display display; + if(Configurable::get_display(selections_by_option, display)) { + get_crt()->set_output_device((display == Configurable::Display::RGB) ? Outputs::CRT::OutputDevice::Monitor : Outputs::CRT::OutputDevice::Television); + } } Configurable::SelectionSet get_accurate_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(false)); - selection_set["display"] = std::unique_ptr(new Configurable::ListSelection("composite")); + Configurable::append_quick_load_tape_selection(selection_set, false); + Configurable::append_display_selection(selection_set, Configurable::Display::Composite); return selection_set; } Configurable::SelectionSet get_user_friendly_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(true)); - selection_set["display"] = std::unique_ptr(new Configurable::ListSelection("rgb")); + Configurable::append_quick_load_tape_selection(selection_set, true); + Configurable::append_display_selection(selection_set, Configurable::Display::RGB); return selection_set; } diff --git a/Machines/Oric/Oric.hpp b/Machines/Oric/Oric.hpp index 2aa05f46e..6bba6eb93 100644 --- a/Machines/Oric/Oric.hpp +++ b/Machines/Oric/Oric.hpp @@ -23,6 +23,9 @@ enum ROM { BASIC10 = 0, BASIC11, Microdisc, Colour }; +/// @returns The options available for an Oric. +std::vector> get_options(); + /*! Models an Oric 1/Atmos with or without a Microdisc. */ diff --git a/Machines/Utility/MachineForTarget.cpp b/Machines/Utility/MachineForTarget.cpp index c03431fb7..b92b4fd33 100644 --- a/Machines/Utility/MachineForTarget.cpp +++ b/Machines/Utility/MachineForTarget.cpp @@ -63,8 +63,8 @@ template class TypedDynamicMachine: public ::Machine::DynamicMachine } } -std::string Machine::NameForTarget(const StaticAnalyser::Target &target) { - switch(target.machine) { +std::string Machine::ShortNameForTargetMachine(const StaticAnalyser::Target::Machine machine) { + switch(machine) { case StaticAnalyser::Target::AmstradCPC: return "AmstradCPC"; case StaticAnalyser::Target::Atari2600: return "Atari2600"; case StaticAnalyser::Target::Electron: return "Electron"; @@ -75,3 +75,27 @@ std::string Machine::NameForTarget(const StaticAnalyser::Target &target) { default: return ""; } } + +std::string Machine::LongNameForTargetMachine(StaticAnalyser::Target::Machine machine) { + switch(machine) { + case StaticAnalyser::Target::AmstradCPC: return "Amstrad CPC"; + case StaticAnalyser::Target::Atari2600: return "Atari 2600"; + case StaticAnalyser::Target::Electron: return "Acorn Electron"; + case StaticAnalyser::Target::Oric: return "Oric"; + case StaticAnalyser::Target::Vic20: return "Vic 20"; + case StaticAnalyser::Target::ZX8081: return "ZX80/81"; + + default: return ""; + } +} + +std::map>> Machine::AllOptionsByMachineName() { + std::map>> options; + + options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::Electron), Electron::get_options())); + options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::Oric), Oric::get_options())); + options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::Vic20), Commodore::Vic20::get_options())); + options.emplace(std::make_pair(LongNameForTargetMachine(StaticAnalyser::Target::ZX8081), ZX8081::get_options())); + + return options; +} diff --git a/Machines/Utility/MachineForTarget.hpp b/Machines/Utility/MachineForTarget.hpp index fbfb05466..1932ec73e 100644 --- a/Machines/Utility/MachineForTarget.hpp +++ b/Machines/Utility/MachineForTarget.hpp @@ -17,6 +17,7 @@ #include "../JoystickMachine.hpp" #include "../KeyboardMachine.hpp" +#include #include namespace Machine { @@ -45,7 +46,19 @@ DynamicMachine *MachineForTarget(const StaticAnalyser::Target &target); which is guaranteed not to have any spaces or other potentially filesystem-bothering contents. */ -std::string NameForTarget(const StaticAnalyser::Target &target); +std::string ShortNameForTargetMachine(const StaticAnalyser::Target::Machine target); + +/*! + Returns a long string name for the machine identified by the target, + usable for presentation to a human. +*/ +std::string LongNameForTargetMachine(const StaticAnalyser::Target::Machine target); + +/*! + Returns a map from machine name to the list of options that machine + exposes, for all machines. +*/ +std::map>> AllOptionsByMachineName(); } diff --git a/Machines/ZX8081/ZX8081.cpp b/Machines/ZX8081/ZX8081.cpp index 97b410d02..197dd8911 100644 --- a/Machines/ZX8081/ZX8081.cpp +++ b/Machines/ZX8081/ZX8081.cpp @@ -13,6 +13,7 @@ #include "../../Storage/Tape/Parsers/ZX8081.hpp" #include "../../ClockReceiver/ForceInline.hpp" +#include "../../Configurable/StandardOptions.hpp" #include "../Utility/MemoryFuzzer.hpp" #include "../Utility/Typer.hpp" @@ -29,6 +30,12 @@ namespace { namespace ZX8081 { +std::vector> get_options() { + return Configurable::standard_options( + static_cast(Configurable::AutomaticTapeMotorControl | Configurable::QuickLoadTape) + ); +} + template class ConcreteMachine: public Utility::TypeRecipient, public CPU::Z80::BusHandler, @@ -345,31 +352,32 @@ template class ConcreteMachine: // MARK: - Configuration options. std::vector> get_options() override { - std::vector> options; - options.emplace_back(new Configurable::BooleanOption("Load Tapes Quickly", "quickload")); - options.emplace_back(new Configurable::BooleanOption("Automatic Tape Motor Control", "autotapemotor")); - return options; + return ZX8081::get_options(); } void set_selections(const Configurable::SelectionSet &selections_by_option) override { - auto quickload = Configurable::selection(selections_by_option, "quickload"); - if(quickload) set_use_fast_tape_hack(quickload->value); + bool quickload; + if(Configurable::get_quick_load_tape(selections_by_option, quickload)) { + set_use_fast_tape_hack(quickload); + } - auto autotapemotor = Configurable::selection(selections_by_option, "autotapemotor"); - if(autotapemotor) set_use_automatic_tape_motor_control(autotapemotor->value); + bool autotapemotor; + if(Configurable::get_automatic_tape_motor_control_selection(selections_by_option, autotapemotor)) { + set_use_automatic_tape_motor_control(autotapemotor); + } } Configurable::SelectionSet get_accurate_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(false)); - selection_set["autotapemotor"] = std::unique_ptr(new Configurable::BooleanSelection(false)); + Configurable::append_quick_load_tape_selection(selection_set, false); + Configurable::append_automatic_tape_motor_control_selection(selection_set, false); return selection_set; } Configurable::SelectionSet get_user_friendly_selections() override { Configurable::SelectionSet selection_set; - selection_set["quickload"] = std::unique_ptr(new Configurable::BooleanSelection(true)); - selection_set["autotapemotor"] = std::unique_ptr(new Configurable::BooleanSelection(true)); + Configurable::append_quick_load_tape_selection(selection_set, true); + Configurable::append_automatic_tape_motor_control_selection(selection_set, true); return selection_set; } diff --git a/Machines/ZX8081/ZX8081.hpp b/Machines/ZX8081/ZX8081.hpp index 3297c85ea..b79830f65 100644 --- a/Machines/ZX8081/ZX8081.hpp +++ b/Machines/ZX8081/ZX8081.hpp @@ -23,6 +23,9 @@ enum ROMType: uint8_t { ZX80 = 0, ZX81 }; +/// @returns The options available for a ZX80 or ZX81. +std::vector> get_options(); + class Machine: public CRTMachine::Machine, public ConfigurationTarget::Machine, diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 6e8532ab6..7092eddbb 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -578,6 +578,8 @@ 4BFCA1291ECBE7A700AC40C1 /* zexall.com in Resources */ = {isa = PBXBuildFile; fileRef = 4BFCA1281ECBE7A700AC40C1 /* zexall.com */; }; 4BFCA12B1ECBE7C400AC40C1 /* ZexallTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */; }; 4BFDD78C1F7F2DB4008579B9 /* ImplicitSectors.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */; }; + 4BFE7B871FC39BF100160B38 /* StandardOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */; }; + 4BFE7B881FC39D8900160B38 /* StandardOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1268,6 +1270,8 @@ 4BFCA12A1ECBE7C400AC40C1 /* ZexallTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZexallTests.swift; sourceTree = ""; }; 4BFDD78A1F7F2DB4008579B9 /* ImplicitSectors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ImplicitSectors.hpp; sourceTree = ""; }; 4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImplicitSectors.cpp; sourceTree = ""; }; + 4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StandardOptions.cpp; sourceTree = ""; }; + 4BFE7B861FC39BF100160B38 /* StandardOptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StandardOptions.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1518,6 +1522,8 @@ children = ( 4B31B88F1FBFBCD800C140D5 /* Configurable.hpp */, 4B0783591FC11D10001D12BB /* Configurable.cpp */, + 4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */, + 4BFE7B861FC39BF100160B38 /* StandardOptions.hpp */, ); name = Configurable; path = ../../Configurable; @@ -3187,6 +3193,7 @@ 4B055A991FAE85CB0060FFFF /* DiskController.cpp in Sources */, 4B055ACC1FAE9B030060FFFF /* Electron.cpp in Sources */, 4B055AB11FAE86070060FFFF /* Tape.cpp in Sources */, + 4BFE7B881FC39D8900160B38 /* StandardOptions.cpp in Sources */, 4B055AA91FAE85EF0060FFFF /* CommodoreGCR.cpp in Sources */, 4B055A7F1FAE852F0060FFFF /* StaticAnalyser.cpp in Sources */, 4B055ADB1FAE9B460060FFFF /* 6560.cpp in Sources */, @@ -3357,6 +3364,7 @@ 4B5073071DDD3B9400C48FBD /* ArrayBuilder.cpp in Sources */, 4BEE0A6F1D72496600532C7B /* Cartridge.cpp in Sources */, 4B8805FB1DCFF807003085B1 /* Oric.cpp in Sources */, + 4BFE7B871FC39BF100160B38 /* StandardOptions.cpp in Sources */, 4B5FADC01DE3BF2B00AEC565 /* Microdisc.cpp in Sources */, 4B54C0C81F8D91E50050900F /* Keyboard.cpp in Sources */, 4BEE0A701D72496600532C7B /* PRG.cpp in Sources */, diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index ca8211c82..dd0e9394a 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -115,8 +115,6 @@ bool KeyboardKeyForSDLScancode(SDL_Keycode scancode, Inputs::Keyboard::Key &key) return true; } -} - struct ParsedArguments { std::string file_name; Configurable::SelectionSet selections; @@ -158,15 +156,70 @@ ParsedArguments parse_arguments(int argc, char *argv[]) { return arguments; } +std::string final_path_component(const std::string &path) { + // An empty path has no final component. + if(path.empty()) { + return ""; + } + + // Find the last slash... + auto final_slash = path.find_last_of("/\\"); + + // If no slash was found at all, return the whole path. + if(final_slash == std::string::npos) { + return path; + } + + // If a slash was found in the final position, remove it and recurse. + if(final_slash == path.size() - 1) { + return final_path_component(path.substr(0, path.size() - 1)); + } + + // Otherwise return everything from just after the slash to the end of the path. + return path.substr(final_slash+1, path.size() - final_slash - 1); +} + +} + int main(int argc, char *argv[]) { SDL_Window *window = nullptr; // Attempt to parse arguments. ParsedArguments arguments = parse_arguments(argc, argv); + // Print a help message if requested. + if(arguments.selections.find("help") != arguments.selections.end() || arguments.selections.find("h") != arguments.selections.end()) { + std::cout << "Usage: " << final_path_component(argv[0]) << " [file] [OPTIONS]" << std::endl; + std::cout << "Required machine type and configuration is determined from the file. Machines with further options:" << std::endl << std::endl; + + auto all_options = Machine::AllOptionsByMachineName(); + for(auto &machine_options: all_options) { + std::cout << machine_options.first << ":" << std::endl; + for(auto &option: machine_options.second) { + std::cout << '\t' << "--" << option->short_name; + + Configurable::ListOption *list_option = dynamic_cast(option.get()); + if(list_option) { + std::cout << "={"; + bool is_first = true; + for(auto option: list_option->options) { + if(!is_first) std::cout << '|'; + is_first = false; + std::cout << option; + } + std::cout << "}"; + } + std::cout << std::endl; + } + std::cout << std::endl; + } + return 0; + } + // Perform a sanity check on arguments. if(arguments.file_name.empty()) { - std::cerr << "Usage: " << argv[0] << " [file]" << std::endl; + std::cerr << "Usage: " << final_path_component(argv[0]) << " [file] [OPTIONS]" << std::endl; + std::cerr << "Use --help to learn more about available options." << std::endl; return -1; } @@ -206,7 +259,7 @@ int main(int argc, char *argv[]) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetSwapInterval(1); - window = SDL_CreateWindow( "Clock Signal", + window = SDL_CreateWindow( final_path_component(arguments.file_name).c_str(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 400, 300, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); diff --git a/StaticAnalyser/StaticAnalyser.hpp b/StaticAnalyser/StaticAnalyser.hpp index df8d7755f..943c67089 100644 --- a/StaticAnalyser/StaticAnalyser.hpp +++ b/StaticAnalyser/StaticAnalyser.hpp @@ -66,7 +66,7 @@ struct Media { and instructions on how to launch the software attached, plus a measure of confidence in this target's correctness. */ struct Target { - enum { + enum Machine { AmstradCPC, Atari2600, Electron,