+++ /dev/null
-/*
- 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 <iostream>
-
-
-// --- SET ARGUMENT ---
-void Sarge::setArgument(std::string arg_short, std::string arg_long, std::string desc, bool hasVal) {
- std::unique_ptr<Argument> 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<std::string, Argument*>(arg_short, args.back().get()));
- }
-
- if (!arg_long.empty()) {
- argNames.insert(std::pair<std::string, Argument*>(arg_long, args.back().get()));
- }
-}
-
-
-// --- SET ARGUMENTS ---
-void Sarge::setArguments(std::vector<Argument> 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<std::string, Argument*>::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<std::string, Argument*>::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<std::string, Argument*>::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<std::unique_ptr<Argument> >::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;
- }
-}