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);
 | |
| }
 |