blob: 76985da99912f736671cbdcf51e4f552eb1e5651 [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;
Adam Lesinskid13fb242015-05-12 20:40:48 -070016 std::function<bool(const StringPiece&, std::string*)> action;
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070017 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
Adam Lesinskid13fb242015-05-12 20:40:48 -070026static std::function<bool(const StringPiece&, std::string*)> wrap(
27 const std::function<void(const StringPiece&)>& action) {
28 return [action](const StringPiece& arg, std::string*) -> bool {
29 action(arg);
30 return true;
31 };
32}
33
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070034void optionalFlag(const StringPiece& name, const StringPiece& description,
35 std::function<void(const StringPiece&)> action) {
Adam Lesinskid13fb242015-05-12 20:40:48 -070036 sFlags.push_back(Flag{
37 name.toString(), description.toString(), wrap(action),
38 false, nullptr, false, false });
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070039}
40
41void requiredFlag(const StringPiece& name, const StringPiece& description,
42 std::function<void(const StringPiece&)> action) {
Adam Lesinskid13fb242015-05-12 20:40:48 -070043 sFlags.push_back(Flag{ name.toString(), description.toString(), wrap(action),
44 true, nullptr, false, false });
45}
46
47void requiredFlag(const StringPiece& name, const StringPiece& description,
48 std::function<bool(const StringPiece&, std::string*)> action) {
49 sFlags.push_back(Flag{ name.toString(), description.toString(), action,
50 true, nullptr, false, false });
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070051}
52
Adam Lesinski5886a922015-04-15 20:29:22 -070053void optionalSwitch(const StringPiece& name, const StringPiece& description, bool resultWhenSet,
54 bool* result) {
55 sFlags.push_back(Flag{
Adam Lesinskid13fb242015-05-12 20:40:48 -070056 name.toString(), description.toString(), {},
57 false, result, resultWhenSet, false });
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070058}
59
Adam Lesinski769de982015-04-10 19:43:55 -070060void usageAndDie(const StringPiece& command) {
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070061 std::cerr << command << " [options]";
62 for (const Flag& flag : sFlags) {
63 if (flag.required) {
64 std::cerr << " " << flag.name << " arg";
65 }
66 }
67 std::cerr << " files..." << std::endl << std::endl << "Options:" << std::endl;
68
69 for (const Flag& flag : sFlags) {
70 std::string command = flag.name;
71 if (!flag.flagResult) {
72 command += " arg ";
73 }
74 std::cerr << " " << std::setw(30) << std::left << command
75 << flag.description << std::endl;
76 }
77 exit(1);
78}
79
80void parse(int argc, char** argv, const StringPiece& command) {
Adam Lesinskid13fb242015-05-12 20:40:48 -070081 std::string errorStr;
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070082 for (int i = 0; i < argc; i++) {
83 const StringPiece arg(argv[i]);
84 if (*arg.data() != '-') {
Adam Lesinski24aad162015-04-24 19:19:30 -070085 sArgs.push_back(arg.toString());
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070086 continue;
87 }
88
89 bool match = false;
90 for (Flag& flag : sFlags) {
91 if (arg == flag.name) {
92 match = true;
93 flag.parsed = true;
94 if (flag.flagResult) {
Adam Lesinski5886a922015-04-15 20:29:22 -070095 *flag.flagResult = flag.flagValueWhenSet;
Adam Lesinski98aa3ad2015-04-06 11:46:52 -070096 } else {
97 i++;
98 if (i >= argc) {
99 std::cerr << flag.name << " missing argument." << std::endl
100 << std::endl;
101 usageAndDie(command);
102 }
Adam Lesinskid13fb242015-05-12 20:40:48 -0700103
104 if (!flag.action(argv[i], &errorStr)) {
105 std::cerr << errorStr << "." << std::endl << std::endl;
106 usageAndDie(command);
107 }
Adam Lesinski98aa3ad2015-04-06 11:46:52 -0700108 }
109 break;
110 }
111 }
112
113 if (!match) {
114 std::cerr << "unknown option '" << arg << "'." << std::endl << std::endl;
115 usageAndDie(command);
116 }
117 }
118
119 for (const Flag& flag : sFlags) {
120 if (flag.required && !flag.parsed) {
121 std::cerr << "missing required flag " << flag.name << std::endl << std::endl;
122 usageAndDie(command);
123 }
124 }
125}
126
127const std::vector<std::string>& getArgs() {
128 return sArgs;
129}
130
131} // namespace flag
132} // namespace aapt