X-Git-Url: https://git.armaanb.net/?p=gen-shell.git;a=blobdiff_plain;f=src%2FSarge%2Fsrc%2Fsarge.cpp;fp=src%2FSarge%2Fsrc%2Fsarge.cpp;h=eb7d14fbe7836f683540dfd461d04ee8ef2bb30d;hp=0000000000000000000000000000000000000000;hb=d8afd601de1f0d8afe6eff61d40ff52d21d90fd8;hpb=d6f43cecc51a1596669e7f082ec75167a2553555 diff --git a/src/Sarge/src/sarge.cpp b/src/Sarge/src/sarge.cpp new file mode 100644 index 0000000..eb7d14f --- /dev/null +++ b/src/Sarge/src/sarge.cpp @@ -0,0 +1,201 @@ +/* + sarge.cpp - Implementation file for the Sarge command line argument parser project. + + Revision 0 + + Features: + - + + Notes: + - + + 2019/03/16, Maya Posch + +*/ + + +#include "sarge.h" + +#include + + +// --- SET ARGUMENT --- +void Sarge::setArgument(std::string arg_short, std::string arg_long, std::string desc, bool hasVal) { + std::unique_ptr arg(new Argument); + arg->arg_short = arg_short; + arg->arg_long = arg_long; + arg->description = desc; + arg->hasValue = hasVal; + args.push_back(std::move(arg)); + + // Set up links. + if (!arg_short.empty()) { + argNames.insert(std::pair(arg_short, args.back().get())); + } + + if (!arg_long.empty()) { + argNames.insert(std::pair(arg_long, args.back().get())); + } +} + + +// --- SET ARGUMENTS --- +void Sarge::setArguments(std::vector args) { + for (Argument a : args) { + setArgument(a.arg_short, a.arg_long, a.description, a.hasValue); + } +} + + +// --- PARSE ARGUMENTS --- +bool Sarge::parseArguments(int argc, char** argv) { + // The first argument is the name of the executable. After it we loop through the remaining + // arguments, linking flags and values. + execName = std::string(argv[0]); + bool expectValue = false; + std::map::const_iterator flag_it; + for (int i = 1; i < argc; ++i) { + // Each flag will start with a '-' character. Multiple flags can be joined together in the + // same string if they're the short form flag type (one character per flag). + std::string entry(argv[i]); + + if (expectValue) { + // Copy value. + flag_it->second->value = entry; + expectValue = false; + } + else if (entry.compare(0, 1, "-") == 0) { + if (textArguments.size() > 0) { + std::cerr << "Flags not allowed after text arguments." << std::endl; + } + + // Parse flag. + // First check for the long form. + if (entry.compare(0, 2, "--") == 0) { + // Long form of flag. + entry.erase(0, 2); // Erase the double dash since we no longer need it. + + flag_it = argNames.find(entry); + if (flag_it == argNames.end()) { + // Flag wasn't found. Abort. + std::cerr << "Long flag " << entry << " wasn't found." << std::endl; + return false; + } + + // Mark as found. + flag_it->second->parsed = true; + ++flagCounter; + + if (flag_it->second->hasValue) { + expectValue = true; // Next argument has to be a value string. + } + } + else { + // Parse short form flag. Parse all of them sequentially. Only the last one + // is allowed to have an additional value following it. + entry.erase(0, 1); // Erase the dash. + for (int i = 0; i < entry.length(); ++i) { + std::string k(&(entry[i]), 1); + flag_it = argNames.find(k); + if (flag_it == argNames.end()) { + // Flag wasn't found. Abort. + std::cerr << "Short flag " << k << " wasn't found." << std::endl; + return false; + } + + // Mark as found. + flag_it->second->parsed = true; + ++flagCounter; + + if (flag_it->second->hasValue) { + if (i != (entry.length() - 1)) { + // Flag isn't at end, thus cannot have value. + std::cerr << "Flag " << k << " needs to be followed by a value string." + << std::endl; + return false; + } else { + expectValue = true; // Next argument has to be a value string. + } + } + } + } + } + else { + // Add to text argument vector. + textArguments.push_back(entry); + } + } + + parsed = true; + + return true; +} + + +// --- GET FLAG --- +// Returns whether the flag was found, along with the value if relevant. +bool Sarge::getFlag(std::string arg_flag, std::string &arg_value) { + if (!parsed) { return false; } + + std::map::const_iterator it = argNames.find(arg_flag); + if (it == argNames.end()) { return false; } + if (!it->second->parsed) { return false; } + + if (it->second->hasValue) { arg_value = it->second->value; } + + return true; +} + + +// --- EXISTS --- +// Returns whether the flag was found. +bool Sarge::exists(std::string arg_flag) { + if (!parsed) { return false; } + + std::map::const_iterator it = argNames.find(arg_flag); + if (it == argNames.end()) { return false; } + if (!it->second->parsed) { return false; } + + return true; +} + + +// --- GET TEXT ARGUMENT --- +// Updates the value parameter with the text argument (unbound value) if found. +// Index starts at 0. +// Returns true if found, else false. +bool Sarge::getTextArgument(uint32_t index, std::string &value) { + if (index < textArguments.size()) { value = textArguments.at(index); return true; } + + return false; +} + + +// --- PRINT HELP --- +// Prints out the application description, usage and available options. +void Sarge::printHelp() { + std::cout << std::endl << description << std::endl; + std::cout << std::endl << "Usage:" << std::endl; + std::cout << "\t" << usage << std::endl; + std::cout << std::endl; + std::cout << "Options: " << std::endl; + + // Determine whitespace needed between arg_long and description. + int count = 1; + std::vector >::const_iterator it; + for (it = args.cbegin(); it != args.cend(); ++it) { + if ((*it)->arg_long.size() > count) { + count = (*it)->arg_long.size(); + } + } + + count += 3; // Number of actual spaces between the longest arg_long and description. + + // Print out the options. + for (it = args.cbegin(); it != args.cend(); ++it) { + std::cout << ((*it)->arg_short.empty() ? " " : "-" + (*it)->arg_short + ", ") + << "--" << (*it)->arg_long; + std::cout << std::string(count - (*it)->arg_long.size(), ' ') << (*it)->description + << std::endl; + } +}