mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-16 11:30:22 +00:00
Applies parsed arguments.
This commit is contained in:
parent
311458f41f
commit
615ea2f573
@ -82,7 +82,7 @@
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--speed=5"
|
||||
isEnabled = "YES">
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--rompath=/Users/thomasharte/Projects/CLK/ROMImages"
|
||||
@ -90,6 +90,10 @@
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--help"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--model=cpc6128"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
|
@ -39,9 +39,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
/// Takes an enum-style camel-case string (e.g. Mac128k) and
|
||||
//std::string
|
||||
|
||||
struct MachineRunner {
|
||||
MachineRunner() {
|
||||
frame_lock_.clear();
|
||||
@ -473,7 +470,7 @@ int main(int argc, char *argv[]) {
|
||||
SDL_Window *window = nullptr;
|
||||
|
||||
// Attempt to parse arguments.
|
||||
ParsedArguments arguments = parse_arguments(argc, argv);
|
||||
const ParsedArguments arguments = parse_arguments(argc, argv);
|
||||
|
||||
// This may be printed either as
|
||||
const std::string usage_suffix = " [file or --new={machine}] [OPTIONS] [--rompath={path to ROMs}] [--speed={speed multiplier, e.g. 1.5}] [--logical-keyboard]";
|
||||
@ -622,12 +619,13 @@ int main(int argc, char *argv[]) {
|
||||
"/usr/local/share/CLK/",
|
||||
"/usr/share/CLK/"
|
||||
};
|
||||
if(arguments.selections.find("rompath") != arguments.selections.end()) {
|
||||
const std::string user_path = arguments.selections["rompath"];
|
||||
if(user_path.back() != '/') {
|
||||
paths.push_back(user_path + "/");
|
||||
|
||||
const auto rompath = arguments.selections.find("rompath");
|
||||
if(rompath != arguments.selections.end()) {
|
||||
if(rompath->second.back() != '/') {
|
||||
paths.push_back(rompath->second + "/");
|
||||
} else {
|
||||
paths.push_back(user_path);
|
||||
paths.push_back(rompath->second);
|
||||
}
|
||||
}
|
||||
|
||||
@ -662,6 +660,20 @@ int main(int argc, char *argv[]) {
|
||||
return results;
|
||||
};
|
||||
|
||||
// Apply all command-line options to the targets.
|
||||
for(auto &target: targets) {
|
||||
auto reflectable_target = dynamic_cast<Reflection::Struct *>(target.get());
|
||||
if(!reflectable_target) continue;
|
||||
|
||||
for(const auto &argument: arguments.selections) {
|
||||
if(argument.second.empty()) {
|
||||
Reflection::set<bool>(*reflectable_target, argument.first, true);
|
||||
} else {
|
||||
Reflection::fuzzy_set(*reflectable_target, argument.first, argument.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create and configure a machine.
|
||||
::Machine::Error error;
|
||||
std::mutex machine_mutex;
|
||||
@ -685,19 +697,36 @@ int main(int argc, char *argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Apply all command-line options to the machines.
|
||||
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<bool>(*options, argument.first, true);
|
||||
} else {
|
||||
Reflection::fuzzy_set(*options, argument.first, argument.second);
|
||||
}
|
||||
}
|
||||
|
||||
configurable->set_options(options);
|
||||
}
|
||||
|
||||
// Apply the speed multiplier, if one was requested.
|
||||
if(arguments.selections.find("speed") != arguments.selections.end()) {
|
||||
// const char *speed_string = arguments.selections["speed"]->list_selection()->value.c_str();
|
||||
// char *end;
|
||||
// double speed = strtod(speed_string, &end);
|
||||
//
|
||||
// if(size_t(end - speed_string) != strlen(speed_string)) {
|
||||
// std::cerr << "Unable to parse speed: " << speed_string << std::endl;
|
||||
// } else if(speed <= 0.0) {
|
||||
// std::cerr << "Cannot run at speed " << speed_string << "; speeds must be positive." << std::endl;
|
||||
// } else {
|
||||
// machine_runner.set_speed_multiplier(speed);
|
||||
// }
|
||||
const auto speed_argument = arguments.selections.find("speed");
|
||||
if(speed_argument != arguments.selections.end()) {
|
||||
const char *speed_string = speed_argument->second.c_str();
|
||||
char *end;
|
||||
double speed = strtod(speed_string, &end);
|
||||
|
||||
if(size_t(end - speed_string) != strlen(speed_string)) {
|
||||
std::cerr << "Unable to parse speed: " << speed_string << std::endl;
|
||||
} else if(speed <= 0.0) {
|
||||
std::cerr << "Cannot run at speed " << speed_string << "; speeds must be positive." << std::endl;
|
||||
} else {
|
||||
machine_runner.set_speed_multiplier(speed);
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether a 'logical' keyboard has been requested.
|
||||
@ -775,31 +804,6 @@ int main(int argc, char *argv[]) {
|
||||
int window_width, window_height;
|
||||
SDL_GetWindowSize(window, &window_width, &window_height);
|
||||
|
||||
/* Configurable::Device *const configurable_device = machine->configurable_device();
|
||||
if(configurable_device) {
|
||||
// Establish user-friendly options by default.
|
||||
configurable_device->set_selections(configurable_device->get_user_friendly_selections());
|
||||
|
||||
// Consider transcoding any list selections that map to Boolean options.
|
||||
for(const auto &option: configurable_device->get_options()) {
|
||||
// Check for a corresponding selection.
|
||||
auto selection = arguments.selections.find(option->short_name);
|
||||
if(selection != arguments.selections.end()) {
|
||||
// Transcode selection if necessary.
|
||||
if(dynamic_cast<Configurable::BooleanOption *>(option.get())) {
|
||||
arguments.selections[selection->first] = std::unique_ptr<Configurable::Selection>(selection->second->boolean_selection());
|
||||
}
|
||||
|
||||
if(dynamic_cast<Configurable::ListOption *>(option.get())) {
|
||||
arguments.selections[selection->first] = std::unique_ptr<Configurable::Selection>(selection->second->list_selection());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the user's actual selections to final the defaults.
|
||||
configurable_device->set_selections(arguments.selections);
|
||||
}*/
|
||||
|
||||
// If this is a joystick machine, check for and open attached joysticks.
|
||||
/*!
|
||||
Provides a wrapper for SDL_Joystick pointers that can keep track
|
||||
|
@ -113,13 +113,13 @@ class Enum {
|
||||
@returns A @c std::string name for the enum value @c e.
|
||||
*/
|
||||
template <typename Type> static const std::string &to_string(Type e) {
|
||||
return to_string(typeid(Type), size_t(e));
|
||||
return to_string(typeid(Type), int(e));
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns A @c std::string name for the enum value @c e from the enum with type_info @c type.
|
||||
*/
|
||||
static const std::string &to_string(std::type_index type, size_t e) {
|
||||
static const std::string &to_string(std::type_index type, int e) {
|
||||
const auto entry = members_by_type_.find(type);
|
||||
if(entry == members_by_type_.end()) return empty_string_;
|
||||
return entry->second[e];
|
||||
@ -150,15 +150,15 @@ class Enum {
|
||||
}
|
||||
|
||||
/*!
|
||||
@returns A value for the name @c str in the enum with type_info @c type , or @c std::string::npos if
|
||||
@returns A value for the name @c str in the enum with type_info @c type , or @c -1 if
|
||||
the name is not found.
|
||||
*/
|
||||
static size_t from_string(std::type_index type, const std::string &str) {
|
||||
static int from_string(std::type_index type, const std::string &str) {
|
||||
const auto entry = members_by_type_.find(type);
|
||||
if(entry == members_by_type_.end()) return std::string::npos;
|
||||
if(entry == members_by_type_.end()) return -1;
|
||||
const auto iterator = std::find(entry->second.begin(), entry->second.end(), str);
|
||||
if(iterator == entry->second.end()) return std::string::npos;
|
||||
return size_t(iterator - entry->second.begin());
|
||||
if(iterator == entry->second.end()) return -1;
|
||||
return int(iterator - entry->second.begin());
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "Struct.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// MARK: - Setters
|
||||
|
||||
template <> bool Reflection::set(Struct &target, const std::string &name, int value) {
|
||||
@ -38,13 +40,11 @@ template <> bool Reflection::set(Struct &target, const std::string &name, const
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto enum_value = Reflection::Enum::from_string(*target_type, value);
|
||||
if(enum_value == std::string::npos) {
|
||||
const int enum_value = Reflection::Enum::from_string(*target_type, value);
|
||||
if(enum_value < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int int_value = int(enum_value);
|
||||
target.set(name, &int_value);
|
||||
target.set(name, &enum_value);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -54,9 +54,54 @@ template <> bool Reflection::set(Struct &target, const std::string &name, const
|
||||
return set<const std::string &>(target, name, string);
|
||||
}
|
||||
|
||||
template <> bool Reflection::set(Struct &target, const std::string &name, bool value) {
|
||||
const auto target_type = target.type_of(name);
|
||||
if(!target_type) return false;
|
||||
|
||||
if(*target_type == typeid(bool)) {
|
||||
target.set(name, &value);;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// MARK: - Fuzzy setter
|
||||
|
||||
bool Reflection::fuzzy_set(Struct &target, const std::string &name, const std::string &value) {
|
||||
const auto target_type = target.type_of(name);
|
||||
if(!target_type) return false;
|
||||
|
||||
// If the target is a registered enum, ttry to convert the value. Failing that,
|
||||
// try to match without case sensitivity.
|
||||
if(Reflection::Enum::size(*target_type)) {
|
||||
const int from_string = Reflection::Enum::from_string(*target_type, value);
|
||||
if(from_string >= 0) {
|
||||
target.set(name, &from_string);
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto all_values = Reflection::Enum::all_values(*target_type);
|
||||
const auto value_location = std::find_if(all_values.begin(), all_values.end(),
|
||||
[&value] (const auto &entry) {
|
||||
if(value.size() != entry.size()) return false;
|
||||
const char *v = value.c_str();
|
||||
const char *e = entry.c_str();
|
||||
while(*v) {
|
||||
if(tolower(*v) != tolower(*e)) return false;
|
||||
++v;
|
||||
++e;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if(value_location != all_values.end()) {
|
||||
const int offset = int(value_location - all_values.begin());
|
||||
target.set(name, &offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,13 @@ template <> bool set(Struct &target, const std::string &name, int value);
|
||||
template <> bool set(Struct &target, const std::string &name, const std::string &value);
|
||||
template <> bool set(Struct &target, const std::string &name, const char *value);
|
||||
|
||||
/*!
|
||||
Setting a bool:
|
||||
|
||||
* to a bool, copies the value.
|
||||
*/
|
||||
template <> bool set(Struct &target, const std::string &name, bool value);
|
||||
|
||||
|
||||
/*!
|
||||
Fuzzy-set attempts to set any property based on a string value. This is intended to allow input provided by the user.
|
||||
|
Loading…
x
Reference in New Issue
Block a user