blob: 3b2ff510bb62f1d5c0f8577448c39a408e3b229e [file] [log] [blame]
Adam Lesinski98aa3ad2015-04-06 11:46:52 -07001#include "Flag.h"
2#include "StringPiece.h"
3
4#include <functional>
5#include <iomanip>
6#include <iostream>
7#include <string>
8#include <vector>
9
10namespace aapt {
11namespace flag {
12
13struct Flag {
14 std::string name;
15 std::string description;
16 std::function<void(const StringPiece&)> action;
17 bool required;
18 bool* flagResult;
Adam Lesinski5886a922015-04-15 20:29:22 -070019 bool flagValueWhenSet;
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070020 bool parsed;
21};
22
23static std::vector<Flag> sFlags;
24static std::vector<std::string> sArgs;
25
26void optionalFlag(const StringPiece& name, const StringPiece& description,
27 std::function<void(const StringPiece&)> action) {
28 sFlags.push_back(
Adam Lesinski5886a922015-04-15 20:29:22 -070029 Flag{ name.toString(), description.toString(), action, false, nullptr, false, false });
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070030}
31
32void requiredFlag(const StringPiece& name, const StringPiece& description,
33 std::function<void(const StringPiece&)> action) {
34 sFlags.push_back(
Adam Lesinski5886a922015-04-15 20:29:22 -070035 Flag{ name.toString(), description.toString(), action, true, nullptr, false, false });
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070036}
37
Adam Lesinski5886a922015-04-15 20:29:22 -070038void optionalSwitch(const StringPiece& name, const StringPiece& description, bool resultWhenSet,
39 bool* result) {
40 sFlags.push_back(Flag{
41 name.toString(), description.toString(), {}, false, result, resultWhenSet, false });
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070042}
43
Adam Lesinski769de982015-04-10 19:43:55 -070044void usageAndDie(const StringPiece& command) {
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070045 std::cerr << command << " [options]";
46 for (const Flag& flag : sFlags) {
47 if (flag.required) {
48 std::cerr << " " << flag.name << " arg";
49 }
50 }
51 std::cerr << " files..." << std::endl << std::endl << "Options:" << std::endl;
52
53 for (const Flag& flag : sFlags) {
54 std::string command = flag.name;
55 if (!flag.flagResult) {
56 command += " arg ";
57 }
58 std::cerr << " " << std::setw(30) << std::left << command
59 << flag.description << std::endl;
60 }
61 exit(1);
62}
63
64void parse(int argc, char** argv, const StringPiece& command) {
65 for (int i = 0; i < argc; i++) {
66 const StringPiece arg(argv[i]);
67 if (*arg.data() != '-') {
68 sArgs.emplace_back(arg.toString());
69 continue;
70 }
71
72 bool match = false;
73 for (Flag& flag : sFlags) {
74 if (arg == flag.name) {
75 match = true;
76 flag.parsed = true;
77 if (flag.flagResult) {
Adam Lesinski5886a922015-04-15 20:29:22 -070078 *flag.flagResult = flag.flagValueWhenSet;
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070079 } else {
80 i++;
81 if (i >= argc) {
82 std::cerr << flag.name << " missing argument." << std::endl
83 << std::endl;
84 usageAndDie(command);
85 }
86 flag.action(argv[i]);
87 }
88 break;
89 }
90 }
91
92 if (!match) {
93 std::cerr << "unknown option '" << arg << "'." << std::endl << std::endl;
94 usageAndDie(command);
95 }
96 }
97
98 for (const Flag& flag : sFlags) {
99 if (flag.required && !flag.parsed) {
100 std::cerr << "missing required flag " << flag.name << std::endl << std::endl;
101 usageAndDie(command);
102 }
103 }
104}
105
106const std::vector<std::string>& getArgs() {
107 return sArgs;
108}
109
110} // namespace flag
111} // namespace aapt