mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
is formatted... but has trouble reading sectors above about 1000. Also remember that encoding MFM needs to keep one bit of state at all times.
202 lines
5.2 KiB
C++
202 lines
5.2 KiB
C++
#include "globals.h"
|
|
#include "flags.h"
|
|
#include "fmt/format.h"
|
|
|
|
static FlagGroup* currentFlagGroup;
|
|
static std::vector<Flag*> all_flags;
|
|
static std::map<const std::string, Flag*> flags_by_name;
|
|
|
|
static void doHelp();
|
|
|
|
static FlagGroup helpGroup;
|
|
static ActionFlag helpFlag = ActionFlag(
|
|
{ "--help", "-h" },
|
|
"Shows the help.",
|
|
doHelp);
|
|
|
|
FlagGroup::FlagGroup(const std::initializer_list<FlagGroup*> groups):
|
|
_groups(groups.begin(), groups.end())
|
|
{
|
|
currentFlagGroup = this;
|
|
}
|
|
|
|
FlagGroup::FlagGroup()
|
|
{
|
|
currentFlagGroup = this;
|
|
}
|
|
|
|
void FlagGroup::addFlag(Flag* flag)
|
|
{
|
|
_flags.push_back(flag);
|
|
}
|
|
|
|
std::vector<std::string> FlagGroup::parseFlagsWithFilenames(int argc, const char* argv[])
|
|
{
|
|
if (_initialised)
|
|
throw std::runtime_error("called parseFlags() twice");
|
|
|
|
/* Recursively accumulate a list of all flags. */
|
|
|
|
all_flags.clear();
|
|
flags_by_name.clear();
|
|
std::function<void(FlagGroup*)> recurse;
|
|
recurse = [&](FlagGroup* group)
|
|
{
|
|
if (group->_initialised)
|
|
return;
|
|
|
|
for (FlagGroup* subgroup : group->_groups)
|
|
recurse(subgroup);
|
|
|
|
for (Flag* flag : group->_flags)
|
|
{
|
|
for (const auto& name : flag->names())
|
|
{
|
|
if (flags_by_name.find(name) != flags_by_name.end())
|
|
Error() << "two flags use the name '" << name << "'";
|
|
flags_by_name[name] = flag;
|
|
}
|
|
|
|
all_flags.push_back(flag);
|
|
}
|
|
|
|
group->_initialised = true;
|
|
};
|
|
recurse(this);
|
|
recurse(&helpGroup);
|
|
|
|
/* Now actually parse them. */
|
|
|
|
std::vector<std::string> filenames;
|
|
int index = 1;
|
|
while (index < argc)
|
|
{
|
|
std::string thisarg = argv[index];
|
|
std::string thatarg = (index < (argc-1)) ? argv[index+1] : "";
|
|
|
|
std::string key;
|
|
std::string value;
|
|
bool usesthat = false;
|
|
|
|
if (thisarg.size() == 0)
|
|
{
|
|
/* Ignore this argument. */
|
|
}
|
|
else if (thisarg[0] != '-')
|
|
{
|
|
/* This is a filename. */
|
|
filenames.push_back(thisarg);
|
|
}
|
|
else
|
|
{
|
|
/* This is a flag. */
|
|
|
|
if ((thisarg.size() > 1) && (thisarg[1] == '-'))
|
|
{
|
|
/* Long option. */
|
|
|
|
auto equals = thisarg.rfind('=');
|
|
if (equals != std::string::npos)
|
|
{
|
|
key = thisarg.substr(0, equals);
|
|
value = thisarg.substr(equals+1);
|
|
}
|
|
else
|
|
{
|
|
key = thisarg;
|
|
value = thatarg;
|
|
usesthat = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Short option. */
|
|
|
|
if (thisarg.size() > 2)
|
|
{
|
|
key = thisarg.substr(0, 2);
|
|
value = thisarg.substr(2);
|
|
}
|
|
else
|
|
{
|
|
key = thisarg;
|
|
value = thatarg;
|
|
usesthat = true;
|
|
}
|
|
}
|
|
|
|
auto flag = flags_by_name.find(key);
|
|
if (flag == flags_by_name.end())
|
|
Error() << "unknown flag '" << key << "'; try --help";
|
|
|
|
flag->second->set(value);
|
|
if (usesthat && flag->second->hasArgument())
|
|
index++;
|
|
}
|
|
|
|
index++;
|
|
}
|
|
|
|
return filenames;
|
|
}
|
|
|
|
void FlagGroup::parseFlags(int argc, const char* argv[])
|
|
{
|
|
auto filenames = parseFlagsWithFilenames(argc, argv);
|
|
if (!filenames.empty())
|
|
Error() << "non-option parameter " << *filenames.begin() << " seen (try --help)";
|
|
}
|
|
|
|
void FlagGroup::checkInitialised() const
|
|
{
|
|
if (!_initialised)
|
|
throw std::runtime_error("Attempt to access uninitialised flag");
|
|
}
|
|
|
|
Flag::Flag(const std::vector<std::string>& names, const std::string helptext):
|
|
_group(*currentFlagGroup),
|
|
_names(names),
|
|
_helptext(helptext)
|
|
{
|
|
if (!currentFlagGroup)
|
|
Error() << "no flag group defined for " << *names.begin();
|
|
_group.addFlag(this);
|
|
}
|
|
|
|
void BoolFlag::set(const std::string& value)
|
|
{
|
|
if ((value == "true") || (value == "y"))
|
|
_value = true;
|
|
else if ((value == "false") || (value == "n"))
|
|
_value = false;
|
|
else
|
|
Error() << "can't parse '" << value << "'; try 'true' or 'false'";
|
|
}
|
|
|
|
const std::string HexIntFlag::defaultValueAsString() const
|
|
{
|
|
return fmt::format("0x{:x}", _defaultValue);
|
|
}
|
|
|
|
static void doHelp()
|
|
{
|
|
std::cout << "FluxEngine options:" << std::endl;
|
|
for (auto flag : all_flags)
|
|
{
|
|
std::cout << " ";
|
|
bool firstname = true;
|
|
for (auto name : flag->names())
|
|
{
|
|
if (!firstname)
|
|
std::cout << ", ";
|
|
std::cout << name;
|
|
firstname = false;
|
|
}
|
|
|
|
if (flag->hasArgument())
|
|
std::cout << " <default: \"" << flag->defaultValueAsString() << "\">";
|
|
std::cout << ": " << flag->helptext() << std::endl;
|
|
}
|
|
exit(0);
|
|
}
|