1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-23 03:32:32 +00:00

Merge pull request #292 from TomHarte/Help

Introduces command-line help and reduces code duplicity in those options.
This commit is contained in:
Thomas Harte 2017-11-20 19:01:06 -08:00 committed by GitHub
commit 723c113186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 343 additions and 51 deletions

View File

@ -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<Configurable::Selection>(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<Configurable::BooleanSelection>(selections_by_option, "quickload");
if(!quickload) return false;
result = quickload->value;
return true;
}
}
// MARK: - Standard option list builder
std::vector<std::unique_ptr<Configurable::Option>> Configurable::standard_options(Configurable::StandardOptions mask) {
std::vector<std::unique_ptr<Configurable::Option>> 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<Configurable::Selection>(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<Configurable::ListSelection>(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;
}

View File

@ -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<std::unique_ptr<Option>> 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 */

View File

@ -24,11 +24,17 @@
#include "../../../Storage/Tape/Tape.hpp"
#include "../../../Storage/Disk/Disk.hpp"
#include "../../../Configurable/StandardOptions.hpp"
#include <algorithm>
namespace Commodore {
namespace Vic20 {
std::vector<std::unique_ptr<Configurable::Option>> 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<std::unique_ptr<Configurable::Option>> get_options() override {
std::vector<std::unique_ptr<Configurable::Option>> 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<Configurable::BooleanSelection>(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<Configurable::Selection>(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<Configurable::Selection>(new Configurable::BooleanSelection(true));
Configurable::append_quick_load_tape_selection(selection_set, true);
return selection_set;
}

View File

@ -41,6 +41,9 @@ enum Region {
Swedish
};
/// @returns The options available for a Vic-20.
std::vector<std::unique_ptr<Configurable::Option>> get_options();
class Machine:
public CRTMachine::Machine,
public ConfigurationTarget::Machine,

View File

@ -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<std::unique_ptr<Configurable::Option>> get_options() {
return Configurable::standard_options(
static_cast<Configurable::StandardOptions>(Configurable::DisplayRGBComposite | Configurable::QuickLoadTape)
);
}
class ConcreteMachine:
public Machine,
public CPU::MOS6502::BusHandler,
@ -418,31 +425,32 @@ class ConcreteMachine:
// MARK: - Configuration options.
std::vector<std::unique_ptr<Configurable::Option>> get_options() override {
std::vector<std::unique_ptr<Configurable::Option>> 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<Configurable::BooleanSelection>(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<Configurable::ListSelection>(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<Configurable::Selection>(new Configurable::BooleanSelection(false));
selection_set["display"] = std::unique_ptr<Configurable::Selection>(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<Configurable::Selection>(new Configurable::BooleanSelection(true));
selection_set["display"] = std::unique_ptr<Configurable::Selection>(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;
}

View File

@ -33,6 +33,9 @@ enum ROMSlot: uint8_t {
ROMSlotADFS1, ROMSlotADFS2
};
/// @returns The options available for an Electron.
std::vector<std::unique_ptr<Configurable::Option>> get_options();
/*!
@abstract Represents an Acorn Electron.

View File

@ -23,11 +23,18 @@
#include "../../Storage/Tape/Parsers/Oric.hpp"
#include "../../ClockReceiver/ForceInline.hpp"
#include "../../Configurable/StandardOptions.hpp"
#include <memory>
namespace Oric {
std::vector<std::unique_ptr<Configurable::Option>> get_options() {
return Configurable::standard_options(
static_cast<Configurable::StandardOptions>(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<std::unique_ptr<Configurable::Option>> get_options() override {
std::vector<std::unique_ptr<Configurable::Option>> 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<Configurable::BooleanSelection>(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<Configurable::ListSelection>(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<Configurable::Selection>(new Configurable::BooleanSelection(false));
selection_set["display"] = std::unique_ptr<Configurable::Selection>(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<Configurable::Selection>(new Configurable::BooleanSelection(true));
selection_set["display"] = std::unique_ptr<Configurable::Selection>(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;
}

View File

@ -23,6 +23,9 @@ enum ROM {
BASIC10 = 0, BASIC11, Microdisc, Colour
};
/// @returns The options available for an Oric.
std::vector<std::unique_ptr<Configurable::Option>> get_options();
/*!
Models an Oric 1/Atmos with or without a Microdisc.
*/

View File

@ -63,8 +63,8 @@ template<typename T> 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<std::string, std::vector<std::unique_ptr<Configurable::Option>>> Machine::AllOptionsByMachineName() {
std::map<std::string, std::vector<std::unique_ptr<Configurable::Option>>> 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;
}

View File

@ -17,6 +17,7 @@
#include "../JoystickMachine.hpp"
#include "../KeyboardMachine.hpp"
#include <map>
#include <string>
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<std::string, std::vector<std::unique_ptr<Configurable::Option>>> AllOptionsByMachineName();
}

View File

@ -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<std::unique_ptr<Configurable::Option>> get_options() {
return Configurable::standard_options(
static_cast<Configurable::StandardOptions>(Configurable::AutomaticTapeMotorControl | Configurable::QuickLoadTape)
);
}
template<bool is_zx81> class ConcreteMachine:
public Utility::TypeRecipient,
public CPU::Z80::BusHandler,
@ -345,31 +352,32 @@ template<bool is_zx81> class ConcreteMachine:
// MARK: - Configuration options.
std::vector<std::unique_ptr<Configurable::Option>> get_options() override {
std::vector<std::unique_ptr<Configurable::Option>> 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<Configurable::BooleanSelection>(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<Configurable::BooleanSelection>(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<Configurable::Selection>(new Configurable::BooleanSelection(false));
selection_set["autotapemotor"] = std::unique_ptr<Configurable::Selection>(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<Configurable::Selection>(new Configurable::BooleanSelection(true));
selection_set["autotapemotor"] = std::unique_ptr<Configurable::Selection>(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;
}

View File

@ -23,6 +23,9 @@ enum ROMType: uint8_t {
ZX80 = 0, ZX81
};
/// @returns The options available for a ZX80 or ZX81.
std::vector<std::unique_ptr<Configurable::Option>> get_options();
class Machine:
public CRTMachine::Machine,
public ConfigurationTarget::Machine,

View File

@ -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 = "<group>"; };
4BFDD78A1F7F2DB4008579B9 /* ImplicitSectors.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ImplicitSectors.hpp; sourceTree = "<group>"; };
4BFDD78B1F7F2DB4008579B9 /* ImplicitSectors.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ImplicitSectors.cpp; sourceTree = "<group>"; };
4BFE7B851FC39BF100160B38 /* StandardOptions.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StandardOptions.cpp; sourceTree = "<group>"; };
4BFE7B861FC39BF100160B38 /* StandardOptions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StandardOptions.hpp; sourceTree = "<group>"; };
/* 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 */,

View File

@ -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<Configurable::ListOption *>(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);

View File

@ -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,