starting a flags parser
This commit is contained in:
		
							parent
							
								
									c2e83613f2
								
							
						
					
					
						commit
						3cefb59310
					
				| 
						 | 
					@ -0,0 +1,191 @@
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// \file Flag.h
 | 
				
			||||||
 | 
					/// \author kyle 
 | 
				
			||||||
 | 
					/// \created 2023-10-12
 | 
				
			||||||
 | 
					/// \brief Flag defines a command-line flag parser.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// \section COPYRIGHT
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Copyright 2023 K. Isom <kyle@imap.cc>
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Permission to use, copy, modify, and/or distribute this software for
 | 
				
			||||||
 | 
					/// any purpose with or without fee is hereby granted, provided that
 | 
				
			||||||
 | 
					/// the above copyright notice and this permission notice appear in all /// copies.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 | 
				
			||||||
 | 
					/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 | 
				
			||||||
 | 
					/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 | 
				
			||||||
 | 
					/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
				
			||||||
 | 
					/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | 
				
			||||||
 | 
					/// PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <regex>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Flag.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace klib {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const std::regex	isFlag("^-[a-zA-Z0-9]+$", 
 | 
				
			||||||
 | 
								       std::regex_constants::nosubs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flag::Flag(FlagType fType, std::string fName, std::string fDescription)
 | 
				
			||||||
 | 
					    : Type(fType), WasSet(false), Name(fName), Description(fDescription)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flags::Flags(std::string fName)
 | 
				
			||||||
 | 
						: name(fName), description("")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flags::Flags(std::string fName, std::string fDescription)
 | 
				
			||||||
 | 
					    : name(fName), description(fDescription)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					Flags::Register(std::string fName, FlagType fType, std::string fDescription)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!std::regex_search(fName, isFlag)) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->flags.count(fName) != 0) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto flag = new Flag;
 | 
				
			||||||
 | 
						flag->Type = fType;
 | 
				
			||||||
 | 
						flag->WasSet = false;
 | 
				
			||||||
 | 
						flag->name = name;
 | 
				
			||||||
 | 
						this->desription = fDescription;
 | 
				
			||||||
 | 
						this->flags[fName] = flag;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Flag *
 | 
				
			||||||
 | 
					Flags::Lookup(std::string fName)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (this->flags.count(fName) == 0) {
 | 
				
			||||||
 | 
							return nullptr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OptFlagValue
 | 
				
			||||||
 | 
					Flags::ValueOf(std::string fName)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (this->flags.count(fName)) {
 | 
				
			||||||
 | 
							return std::nullopt;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return OptFlagValue(this->flags[fName]->Value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ParseStatus
 | 
				
			||||||
 | 
					Flags::parseArg(int argc, char **argv, int &index)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						std::string	arg(argv[index]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						index++;
 | 
				
			||||||
 | 
						if (!std::regex_search(arg, isFlag)) {
 | 
				
			||||||
 | 
							return ParseStatus::EndOfFlags;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (this->flags.count(arg) == 0) {
 | 
				
			||||||
 | 
							return ParseStatus::NotRegistered;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto flag = flags[arg];
 | 
				
			||||||
 | 
						if (flag->Type == FlagType::Boolean) {
 | 
				
			||||||
 | 
							flag->WasSet = true;
 | 
				
			||||||
 | 
							flag->Value.b = true;
 | 
				
			||||||
 | 
							return ParseStatus::OK;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (flag->Type) {
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							throw std::runtime_error("not handled");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ParseStatus::OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ParseStatus
 | 
				
			||||||
 | 
					Flags::Parse(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int	index = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (index != argc) {
 | 
				
			||||||
 | 
							auto result = this->parseArg(argc, argv, index);
 | 
				
			||||||
 | 
							switch (result) {
 | 
				
			||||||
 | 
							case ParseStatus::OK:
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case ParseStatus::EndOfFlags:
 | 
				
			||||||
 | 
								while (index < argc) {
 | 
				
			||||||
 | 
									this->args.push_back(std::string(argv[index]));
 | 
				
			||||||
 | 
									index++;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							case ParseStatus::EndOfFlags:
 | 
				
			||||||
 | 
							case ParseStatus::NotEnoughArgs:
 | 
				
			||||||
 | 
								// fall through //
 | 
				
			||||||
 | 
								return result;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								throw runtime_error("unhandled parse state");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ParseStatus::OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t
 | 
				
			||||||
 | 
					Flags::NumArgs()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return this->args.size();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::vector<std::string>
 | 
				
			||||||
 | 
					Flags::Args()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return this->args;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					Flags::GetBool(std::string name, bool &flagValue)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (this->flags[name] == 0) {
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return std::get<bool>(this->flags[name]->Value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace klib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// \file Flag.h
 | 
				
			||||||
 | 
					/// \author kyle 
 | 
				
			||||||
 | 
					/// \created 2023-10-12
 | 
				
			||||||
 | 
					/// \brief Flag declares a command-line flag parser.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// \section COPYRIGHT
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Copyright 2023 K. Isom <kyle@imap.cc>
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// Permission to use, copy, modify, and/or distribute this software for
 | 
				
			||||||
 | 
					/// any purpose with or without fee is hereby granted, provided that
 | 
				
			||||||
 | 
					/// the above copyright notice and this permission notice appear in all /// copies.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
 | 
				
			||||||
 | 
					/// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 | 
				
			||||||
 | 
					/// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					/// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 | 
				
			||||||
 | 
					/// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
 | 
				
			||||||
 | 
					/// OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | 
				
			||||||
 | 
					/// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 | 
				
			||||||
 | 
					/// PERFORMANCE OF THIS SOFTWARE.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cstdint>
 | 
				
			||||||
 | 
					#include <functional>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
 | 
					#include <variant>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace klib {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class FlagType : uint8_t {
 | 
				
			||||||
 | 
						Unknown		= 0,
 | 
				
			||||||
 | 
						Boolean		= 1,
 | 
				
			||||||
 | 
						Integer		= 2,
 | 
				
			||||||
 | 
						UnsignedInteger	= 3,
 | 
				
			||||||
 | 
						String		= 4,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class ParseStatus : uint8_t {
 | 
				
			||||||
 | 
						OK		= 0,
 | 
				
			||||||
 | 
						EndOfFlags	= 1,
 | 
				
			||||||
 | 
						NotRegistered	= 2,	
 | 
				
			||||||
 | 
						NotEnoughArgs	= 3,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef std::variant<
 | 
				
			||||||
 | 
						std::string *,
 | 
				
			||||||
 | 
						bool *,
 | 
				
			||||||
 | 
						int64_t *,
 | 
				
			||||||
 | 
						uint64_t *> FlagValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Flag {
 | 
				
			||||||
 | 
						Flag(FlagType fType, std::string fName, std::string fDescription);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						FlagType	Type;
 | 
				
			||||||
 | 
						bool		WasSet;
 | 
				
			||||||
 | 
						std::string	Name;
 | 
				
			||||||
 | 
						std::string	Description;
 | 
				
			||||||
 | 
						FlagValue	Value;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef std::optional<FlagValue>	OptFlagValue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Flags {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
						Flags(std::string fName);
 | 
				
			||||||
 | 
						Flags(std::string fName, std::string fDescription);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool	Register(std::string fName, 
 | 
				
			||||||
 | 
								 FlagType fType,
 | 
				
			||||||
 | 
								 std::string fDescription);
 | 
				
			||||||
 | 
						Flag	*Lookup(std::string fName);
 | 
				
			||||||
 | 
						OptFlagValue
 | 
				
			||||||
 | 
							 ValueOf(std::string fName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int	 Parse(int argc, char **argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void	 Usage(std::ostream &os, int exitCode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t	 			NumArgs();
 | 
				
			||||||
 | 
						std::vector<std::string>	Args();
 | 
				
			||||||
 | 
						std::string			Arg(int index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool	GetBool(std::string name, bool &flagValue);
 | 
				
			||||||
 | 
						// bool	GetUnsignedInteger(std::string name, uint64_t &flagValue)
 | 
				
			||||||
 | 
						// bool	GetInteger(std::string name, int64_t &flagValue)
 | 
				
			||||||
 | 
						// bool	GetString(std::string name, std::string &flagValue)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
						ParseStatus		parseArg(int argc, char **argv, int &index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string			name;
 | 
				
			||||||
 | 
						std::string			description;
 | 
				
			||||||
 | 
						std::vector<std::string>	args;
 | 
				
			||||||
 | 
						std::map<std::string, Flag *>	flags;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace klib
 | 
				
			||||||
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							| 
						 | 
					@ -6,7 +6,7 @@ LDFLAGS :=
 | 
				
			||||||
SOURCE_DIR ?=	"/mnt/Kyle/Documents/Fonts/Equity + Concourse Standard + Triplicate"
 | 
					SOURCE_DIR ?=	"/mnt/Kyle/Documents/Fonts/Equity + Concourse Standard + Triplicate"
 | 
				
			||||||
TARGET_DIR ?=	"$(HOME)/.local/share/fonts"
 | 
					TARGET_DIR ?=	"$(HOME)/.local/share/fonts"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SOURCES :=	rcpp.cc
 | 
					SOURCES :=	rcpp.cc Flag.cc Flag.h
 | 
				
			||||||
OBJS := 	$(patsubst %.cc,%.o,$(filter %.cc,$(SOURCES)))
 | 
					OBJS := 	$(patsubst %.cc,%.o,$(filter %.cc,$(SOURCES)))
 | 
				
			||||||
TARGET :=	rcpp
 | 
					TARGET :=	rcpp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										28
									
								
								rcpp.cc
								
								
								
								
							
							
						
						
									
										28
									
								
								rcpp.cc
								
								
								
								
							| 
						 | 
					@ -29,6 +29,9 @@
 | 
				
			||||||
#include <iostream>
 | 
					#include <iostream>
 | 
				
			||||||
#include <regex>
 | 
					#include <regex>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "Flag.h"
 | 
				
			||||||
 | 
					using namespace klib;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALIAS_FS	namespace fs = std::filesystem
 | 
					#define ALIAS_FS	namespace fs = std::filesystem
 | 
				
			||||||
typedef std::filesystem::path	Path;
 | 
					typedef std::filesystem::path	Path;
 | 
				
			||||||
| 
						 | 
					@ -147,13 +150,30 @@ main(int argc, char *argv[])
 | 
				
			||||||
	ALIAS_FS;
 | 
						ALIAS_FS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto regexOptions = std::regex_constants::optimize;
 | 
						auto regexOptions = std::regex_constants::optimize;
 | 
				
			||||||
	if (argc < 4) {
 | 
						Flags	optArgs("rcpp", "recursively copy files by pattern");
 | 
				
			||||||
		std::cerr << "Usage: rcpp pattern files... destination\n";
 | 
					
 | 
				
			||||||
 | 
						optArgs.Register("-e", FlagType::Boolean, "pattern is a file extension");
 | 
				
			||||||
 | 
						optArgs.Register("-i", FlagType::Boolean, "case-insensitive maches");
 | 
				
			||||||
 | 
						if (optArgs.Parse(argc, argv)) {
 | 
				
			||||||
 | 
							optArgs.Usage(std::cerr, 1);	
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	auto pattern = std::string(argv[1]);
 | 
						if (optArgs.NumArgs() < 3) {
 | 
				
			||||||
	auto destDir = fs::absolute(fs::path(argv[argc-1]));
 | 
							optArgs.Usage(std::cerr, 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						auto pattern = optArgs.Arg(0);
 | 
				
			||||||
 | 
						auto destDir = fs::path(optArgs.Arg(optArgs.NumArgs() - 1));
 | 
				
			||||||
	bool value;
 | 
						bool value;
 | 
				
			||||||
 | 
						if (optArgs.GetBool("-e", value) && value) {
 | 
				
			||||||
 | 
							pattern = "\\." + pattern + "$";	
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (optArgs.GetBool("-i", value) && value) {
 | 
				
			||||||
 | 
							regexOptions |= std::regex_constants::icase;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						destDir = fs::absolute(destDir);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	TRACE << "argc: " << argc << "\n";
 | 
						TRACE << "argc: " << argc << "\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue