Fix flags usage and make Commander Flags capable.

- Programs should exit on Flags parse error.
- Commander now accepts a string vector for interop with Flags.
This commit is contained in:
2023-10-21 19:45:07 -07:00
parent 1420ff343d
commit 8b63985ac9
17 changed files with 127 additions and 99 deletions

View File

@@ -27,48 +27,50 @@ using namespace std;
#include <scsl/Arena.h>
#include <scsl/Commander.h>
#include <scsl/Dictionary.h>
#include <scsl/Flags.h>
using namespace scsl;
static const char *defaultPhonebook = "pb.dat";
static char *pbFile = (char *)defaultPhonebook;
static std::string pbFile(defaultPhonebook);
static Arena arena;
static Dictionary pb(arena);
static bool
listFiles(int argc, char **argv)
listFiles(std::vector<std::string> argv)
{
(void)argc; (void)argv;
(void) argv; // provided for interface compatibility.
cout << "[+] keys in '" << pbFile << "':\n";
cout << pb;
return true;
}
static bool
newPhonebook(int argc, char **argv)
{
(void)argc;
auto size = std::stoul(string(argv[0]));
static bool
newPhonebook(std::vector<std::string> argv)
{
auto size = std::stoul(argv[0]);
cout << "[+] create new " << size << "B phonebook '" << pbFile << "'\n";
return arena.Create(pbFile, size) == 0;
return arena.Create(pbFile.c_str(), size) == 0;
}
static bool
delKey(int argc, char **argv)
delKey(std::vector<std::string> argv)
{
(void)argc;
string key = argv[0];
cout << "[+] deleting key '" << key << "'\n";
return pb.Delete(key.c_str(), key.size());
}
static bool
hasKey(int argc, char **argv)
hasKey(std::vector<std::string> argv)
{
(void)argc;
string key = argv[0];
cout << "[+] looking up '" << key << "': ";
@@ -81,10 +83,10 @@ hasKey(int argc, char **argv)
return true;
}
static bool
getKey(int argc, char **argv)
getKey(std::vector<std::string> argv)
{
(void)argc;
TLV::Record rec;
auto key = string(argv[0]);
@@ -100,9 +102,8 @@ getKey(int argc, char **argv)
static bool
putKey(int argc, char **argv)
putKey(std::vector<std::string> argv)
{
(void)argc;
auto key = string(argv[0]);
auto val = string(argv[1]);
@@ -116,6 +117,7 @@ putKey(int argc, char **argv)
return true;
}
static void
usage(ostream &os, int exc)
{
@@ -136,28 +138,35 @@ usage(ostream &os, int exc)
int
main(int argc, char *argv[])
{
int optind = 1;
bool help = false;
std::string fileName(pbFile);
for (optind = 1; optind < argc; optind++) {
auto arg = string(argv[optind]);
if (arg[0] != '-') break;
if (arg == "-h") usage(cout, 0);
if (arg == "-f") {
pbFile = argv[optind+1];
optind++;
continue;
}
auto *flags = new scsl::Flags("phonebook",
"A tool for interacting with Arena-backed dictionary files.");
flags->Register("-f", pbFile, "path to a phonebook file");
flags->Register("-h", false, "print a help message");
usage(cerr, 1);
auto parsed = flags->Parse(argc, argv);
if (parsed != scsl::Flags::ParseStatus::OK) {
std::cerr << "Failed to parse flags: "
<< scsl::Flags::ParseStatusToString(parsed) << "\n";
exit(1);
}
if (argc <= 1) {
usage(cout, 0);
flags->GetString("-f", fileName);
flags->GetBool("-h", help);
pbFile = fileName;
if (help) {
usage(std::cerr, 1);
}
if (flags->NumArgs() == 0) {
usage(std::cerr, 1);
}
auto command = string(argv[optind++]);
Commander commander;
commander.Register(Subcommand("list", 0, listFiles));
commander.Register(Subcommand("new", 1, newPhonebook));
commander.Register(Subcommand("del", 1, delKey));
@@ -165,15 +174,19 @@ main(int argc, char *argv[])
commander.Register(Subcommand("get", 1, getKey));
commander.Register(Subcommand("put", 2, putKey));
auto command = flags->Arg(0);
if (command != "new") {
cout << "[+] loading phonebook from " << pbFile << "\n";
if (arena.Open(pbFile) != 0) {
if (arena.Open(pbFile.c_str()) != 0) {
cerr << "Failed to open " << pbFile << "\n";
exit(1);
}
}
auto result = commander.Run(command, argc-optind, argv+optind);
auto args = flags->Args();
args.erase(args.begin());
auto result = commander.Run(command, args);
switch (result) {
case Subcommand::Status::OK:
std::cout << "[+] OK\n";

View File

@@ -29,15 +29,16 @@ namespace scsl {
Subcommand::Status
Subcommand::Run(int argc, char **argv)
Subcommand::Run(std::vector<std::string> args)
{
if (argc < this->args) {
auto argc = args.size();
if (argc < this->requiredArgs) {
std::cerr << "[!] " << this->command << " expects ";
std::cerr << this->args << " args, but was given ";
std::cerr << this->requiredArgs << " args, but was given ";
std::cerr << argc << " args.\n";
return Subcommand::Status::NotEnoughArgs;
}
if (this->fn(argc, argv)) {
if (this->fn(args)) {
return Subcommand::Status::OK;
}
@@ -64,14 +65,14 @@ Commander::Register(Subcommand scmd)
Subcommand::Status
Commander::Run(std::string command, int argc, char **argv)
Commander::Run(std::string command, std::vector<std::string> args)
{
if (this->cmap.count(command) != 1) {
return Subcommand::Status::CommandNotRegistered;
}
auto scmd = this->cmap[command];
return scmd->Run(argc, argv);
return scmd->Run(args);
}

View File

@@ -95,7 +95,7 @@ Flags::~Flags()
bool
Flags::Register(std::string fName, FlagType fType, std::string fDescription)
{
if (!std::regex_search(fName, isFlag) || fName == "-h") {
if (!std::regex_search(fName, isFlag)) {
return false;
}