2 sarge.cpp - Implementation file for the Sarge command line argument parser project.
12 2019/03/16, Maya Posch
22 // --- SET ARGUMENT ---
23 void Sarge::setArgument(std::string arg_short, std::string arg_long, std::string desc, bool hasVal) {
24 std::unique_ptr<Argument> arg(new Argument);
25 arg->arg_short = arg_short;
26 arg->arg_long = arg_long;
27 arg->description = desc;
28 arg->hasValue = hasVal;
29 args.push_back(std::move(arg));
32 if (!arg_short.empty()) {
33 argNames.insert(std::pair<std::string, Argument*>(arg_short, args.back().get()));
36 if (!arg_long.empty()) {
37 argNames.insert(std::pair<std::string, Argument*>(arg_long, args.back().get()));
42 // --- SET ARGUMENTS ---
43 void Sarge::setArguments(std::vector<Argument> args) {
44 for (Argument a : args) {
45 setArgument(a.arg_short, a.arg_long, a.description, a.hasValue);
50 // --- PARSE ARGUMENTS ---
51 bool Sarge::parseArguments(int argc, char** argv) {
52 // The first argument is the name of the executable. After it we loop through the remaining
53 // arguments, linking flags and values.
54 execName = std::string(argv[0]);
55 bool expectValue = false;
56 std::map<std::string, Argument*>::const_iterator flag_it;
57 for (int i = 1; i < argc; ++i) {
58 // Each flag will start with a '-' character. Multiple flags can be joined together in the
59 // same string if they're the short form flag type (one character per flag).
60 std::string entry(argv[i]);
64 flag_it->second->value = entry;
67 else if (entry.compare(0, 1, "-") == 0) {
68 if (textArguments.size() > 0) {
69 std::cerr << "Flags not allowed after text arguments." << std::endl;
73 // First check for the long form.
74 if (entry.compare(0, 2, "--") == 0) {
76 entry.erase(0, 2); // Erase the double dash since we no longer need it.
78 flag_it = argNames.find(entry);
79 if (flag_it == argNames.end()) {
80 // Flag wasn't found. Abort.
81 std::cerr << "Long flag " << entry << " wasn't found." << std::endl;
86 flag_it->second->parsed = true;
89 if (flag_it->second->hasValue) {
90 expectValue = true; // Next argument has to be a value string.
94 // Parse short form flag. Parse all of them sequentially. Only the last one
95 // is allowed to have an additional value following it.
96 entry.erase(0, 1); // Erase the dash.
97 for (int i = 0; i < entry.length(); ++i) {
98 std::string k(&(entry[i]), 1);
99 flag_it = argNames.find(k);
100 if (flag_it == argNames.end()) {
101 // Flag wasn't found. Abort.
102 std::cerr << "Short flag " << k << " wasn't found." << std::endl;
107 flag_it->second->parsed = true;
110 if (flag_it->second->hasValue) {
111 if (i != (entry.length() - 1)) {
112 // Flag isn't at end, thus cannot have value.
113 std::cerr << "Flag " << k << " needs to be followed by a value string."
117 expectValue = true; // Next argument has to be a value string.
124 // Add to text argument vector.
125 textArguments.push_back(entry);
136 // Returns whether the flag was found, along with the value if relevant.
137 bool Sarge::getFlag(std::string arg_flag, std::string &arg_value) {
138 if (!parsed) { return false; }
140 std::map<std::string, Argument*>::const_iterator it = argNames.find(arg_flag);
141 if (it == argNames.end()) { return false; }
142 if (!it->second->parsed) { return false; }
144 if (it->second->hasValue) { arg_value = it->second->value; }
151 // Returns whether the flag was found.
152 bool Sarge::exists(std::string arg_flag) {
153 if (!parsed) { return false; }
155 std::map<std::string, Argument*>::const_iterator it = argNames.find(arg_flag);
156 if (it == argNames.end()) { return false; }
157 if (!it->second->parsed) { return false; }
163 // --- GET TEXT ARGUMENT ---
164 // Updates the value parameter with the text argument (unbound value) if found.
165 // Index starts at 0.
166 // Returns true if found, else false.
167 bool Sarge::getTextArgument(uint32_t index, std::string &value) {
168 if (index < textArguments.size()) { value = textArguments.at(index); return true; }
174 // --- PRINT HELP ---
175 // Prints out the application description, usage and available options.
176 void Sarge::printHelp() {
177 std::cout << std::endl << description << std::endl;
178 std::cout << std::endl << "Usage:" << std::endl;
179 std::cout << "\t" << usage << std::endl;
180 std::cout << std::endl;
181 std::cout << "Options: " << std::endl;
183 // Determine whitespace needed between arg_long and description.
185 std::vector<std::unique_ptr<Argument> >::const_iterator it;
186 for (it = args.cbegin(); it != args.cend(); ++it) {
187 if ((*it)->arg_long.size() > count) {
188 count = (*it)->arg_long.size();
192 count += 3; // Number of actual spaces between the longest arg_long and description.
194 // Print out the options.
195 for (it = args.cbegin(); it != args.cend(); ++it) {
196 std::cout << ((*it)->arg_short.empty() ? " " : "-" + (*it)->arg_short + ", ")
197 << "--" << (*it)->arg_long;
198 std::cout << std::string(count - (*it)->arg_long.size(), ' ') << (*it)->description