diff --git a/Machines/Utility/MachineForTarget.cpp b/Machines/Utility/MachineForTarget.cpp index ca306a2c1..253dd4d2a 100644 --- a/Machines/Utility/MachineForTarget.cpp +++ b/Machines/Utility/MachineForTarget.cpp @@ -8,6 +8,8 @@ #include "MachineForTarget.hpp" +#include + // Sources for runtime options. #include "../AmstradCPC/AmstradCPC.hpp" #include "../Apple/AppleII/AppleII.hpp" @@ -148,28 +150,33 @@ std::string Machine::LongNameForTargetMachine(Analyser::Machine machine) { } } -std::vector Machine::AllMachines(bool meaningful_without_media_only, bool long_names) { +std::vector Machine::AllMachines(Type type, bool long_names) { std::vector result; #define AddName(x) result.push_back(long_names ? LongNameForTargetMachine(Analyser::Machine::x) : ShortNameForTargetMachine(Analyser::Machine::x)) -#define AddConditionalName(x) if(!meaningful_without_media_only) result.push_back(long_names ? LongNameForTargetMachine(Analyser::Machine::x) : ShortNameForTargetMachine(Analyser::Machine::x)) - AddName(AmstradCPC); - AddName(AppleII); - AddConditionalName(Atari2600); - AddName(AtariST); - AddConditionalName(ColecoVision); - AddName(Electron); - AddName(Macintosh); - AddConditionalName(MasterSystem); - AddName(MSX); - AddName(Oric); - AddName(Vic20); - AddName(ZX8081); + if(type == Type::Any || type == Type::DoesntRequireMedia) { + AddName(AmstradCPC); + AddName(AppleII); + AddName(AtariST); + AddName(Electron); + AddName(Macintosh); + AddName(MSX); + AddName(Oric); + AddName(Vic20); + AddName(ZX8081); + } + + if(type == Type::Any || type == Type::RequiresMedia) { + AddName(Atari2600); + AddName(ColecoVision); + AddName(MasterSystem); + } -#undef AddConditionalName #undef AddName + std::sort(result.begin(), result.end()); + return result; } diff --git a/Machines/Utility/MachineForTarget.hpp b/Machines/Utility/MachineForTarget.hpp index c1228d610..5d481e0d4 100644 --- a/Machines/Utility/MachineForTarget.hpp +++ b/Machines/Utility/MachineForTarget.hpp @@ -65,14 +65,19 @@ std::string ShortNameForTargetMachine(const Analyser::Machine target); */ std::string LongNameForTargetMachine(const Analyser::Machine target); +enum class Type { + RequiresMedia, + DoesntRequireMedia, + Any +}; + /*! - @param meaningful_without_media_only If this is @c true then only machines that it is meaningful to start without a piece of media will be listed; - otherwise all supported machines will be listed. + @param type the type of machines to include. @param long_names If this is @c true then long names will be returned; otherwise short names will be returned. @returns A list of all available machines. Names are always guaranteed to be in the same order. */ -std::vector AllMachines(bool meaningful_without_media_only, bool long_names); +std::vector AllMachines(Type type, bool long_names); /*! Returns a map from long machine name to the list of options that machine exposes, for all machines. diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme index 583cb9d88..e58d5fee5 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme @@ -90,7 +90,7 @@ + isEnabled = "YES"> selections; // The empty string will be inserted for arguments without an = suffix. + + void apply(Reflection::Struct *reflectable) const { + for(const auto &argument: selections) { + // Replace any dashes with underscores in the argument name. + std::string property; + std::transform(argument.first.begin(), argument.first.end(), std::back_inserter(property), [](char c) { return c == '-' ? '_' : c; }); + + if(argument.second.empty()) { + Reflection::set(*reflectable, property, true); + } else { + Reflection::fuzzy_set(*reflectable, property, argument.second); + } + } + } }; /*! Parses an argc/argv pair to discern program arguments. */ @@ -387,7 +401,7 @@ ParsedArguments parse_arguments(int argc, char *argv[]) { if(split_index == std::string::npos) { arguments.selections[argument]; // To create an entry with the default empty string. } else { - std::string name = argument.substr(0, split_index); + const std::string name = argument.substr(0, split_index); std::string value = argument.substr(split_index+1, std::string::npos); arguments.selections[name] = value; } @@ -477,11 +491,11 @@ int main(int argc, char *argv[]) { // Print a help message if requested. if(arguments.selections.find("help") != arguments.selections.end() || arguments.selections.find("h") != arguments.selections.end()) { - const auto all_machines = Machine::AllMachines(false, false); + const auto all_machines = Machine::AllMachines(Machine::Type::DoesntRequireMedia, false); std::cout << "Usage: " << final_path_component(argv[0]) << usage_suffix << std::endl; std::cout << "Use alt+enter to toggle full screen display. Use control+shift+V to paste text." << std::endl; - std::cout << "Required machine type and configuration is determined from the file if specified; otherwise use:" << std::endl << std::endl; + std::cout << "Required machine type **and all options** are determined from the file if specified; otherwise use:" << std::endl << std::endl; std::cout << "\t--new={"; bool is_first = true; for(const auto &name: all_machines) { @@ -491,11 +505,21 @@ int main(int argc, char *argv[]) { } std::cout << "}" << std::endl << std::endl; - std::cout << "Further machine options:" << std::endl; + std::cout << "Media is required to start the: "; + const auto other_machines = Machine::AllMachines(Machine::Type::RequiresMedia, true); + is_first = true; + for(const auto &name: other_machines) { + if(!is_first) std::cout << ", "; + std::cout << name; + is_first = false; + } + std::cout << "." << std::endl << std::endl; + + std::cout << "Further machine options:" << std::endl << std::endl;; const auto targets = Machine::TargetsByMachineName(false); const auto runtime_options = Machine::AllOptionsByMachineName(); - const auto machine_names = Machine::AllMachines(false, true); + const auto machine_names = Machine::AllMachines(Machine::Type::Any, true); for(const auto &machine: machine_names) { const auto target = targets.find(machine); const auto options = runtime_options.find(machine); @@ -522,7 +546,10 @@ int main(int argc, char *argv[]) { std::sort(all_options.begin(), all_options.end()); for(const auto &option: all_options) { - std::cout << '\t' << "--" << option; + // Replace any underscores with hyphens, better to conform to command-line norms. + std::string mapped_option; + std::transform(option.begin(), option.end(), std::back_inserter(mapped_option), [](char c) { return c == '_' ? '-' : c; }); + std::cout << '\t' << "--" << mapped_option; auto source = target_reflectable; auto type = target_reflectable ? target_reflectable->type_of(option) : nullptr; @@ -538,6 +565,7 @@ int main(int argc, char *argv[]) { for(const auto &value: source->values_for(option)) { if(!is_first) std::cout << '|'; is_first = false; + std::cout << value; } std::cout << "}"; @@ -564,7 +592,7 @@ int main(int argc, char *argv[]) { const auto new_argument = arguments.selections.find("new"); if(new_argument != arguments.selections.end() && !new_argument->second.empty()) { // Perform for a case-insensitive search against short names. - const auto short_names = Machine::AllMachines(false, false); + const auto short_names = Machine::AllMachines(Machine::Type::DoesntRequireMedia, false); auto short_name = short_names.begin(); while(short_name != short_names.end()) { if(std::equal( @@ -579,7 +607,7 @@ int main(int argc, char *argv[]) { // If a match was found, use the corresponding long name to look up a suitable // Analyser::Statuc::Target and move that to the targets list. if(short_name != short_names.end()) { - const auto long_name = Machine::AllMachines(false, true)[short_name - short_names.begin()]; + const auto long_name = Machine::AllMachines(Machine::Type::DoesntRequireMedia, true)[short_name - short_names.begin()]; auto targets_by_machine = Machine::TargetsByMachineName(false); std::unique_ptr tgt = std::move(targets_by_machine[long_name]); targets.push_back(std::move(tgt)); @@ -664,14 +692,7 @@ int main(int argc, char *argv[]) { for(auto &target: targets) { auto reflectable_target = dynamic_cast(target.get()); if(!reflectable_target) continue; - - for(const auto &argument: arguments.selections) { - if(argument.second.empty()) { - Reflection::set(*reflectable_target, argument.first, true); - } else { - Reflection::fuzzy_set(*reflectable_target, argument.first, argument.second); - } - } + arguments.apply(reflectable_target); } // Create and configure a machine. @@ -701,15 +722,7 @@ int main(int argc, char *argv[]) { auto configurable = machine->configurable_device(); if(configurable) { const auto options = configurable->get_options(); - - for(const auto &argument: arguments.selections) { - if(argument.second.empty()) { - Reflection::set(*options, argument.first, true); - } else { - Reflection::fuzzy_set(*options, argument.first, argument.second); - } - } - + arguments.apply(options.get()); configurable->set_options(options); }