blob: c98cd374602faf03ec6616c76653ba6872d577c5 [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Flags.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070018
19#include <iomanip>
20#include <iostream>
21#include <string>
22#include <vector>
23
Adam Lesinskice5e56e2016-10-21 17:56:45 -070024#include "util/StringPiece.h"
25#include "util/Util.h"
26
Adam Lesinski1ab598f2015-08-14 14:26:04 -070027namespace aapt {
28
Adam Lesinskice5e56e2016-10-21 17:56:45 -070029Flags& Flags::RequiredFlag(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070030 const StringPiece& description, std::string* value) {
31 auto func = [value](const StringPiece& arg) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070032 *value = arg.ToString();
Adam Lesinskicacb28f2016-10-19 12:18:14 -070033 return true;
34 };
Adam Lesinski1ab598f2015-08-14 14:26:04 -070035
Adam Lesinskice5e56e2016-10-21 17:56:45 -070036 flags_.push_back(
37 Flag{name.ToString(), description.ToString(), func, true, 1, false});
Adam Lesinskicacb28f2016-10-19 12:18:14 -070038 return *this;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070039}
40
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041Flags& Flags::RequiredFlagList(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070042 const StringPiece& description,
Adam Lesinski1ab598f2015-08-14 14:26:04 -070043 std::vector<std::string>* value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070044 auto func = [value](const StringPiece& arg) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045 value->push_back(arg.ToString());
Adam Lesinskicacb28f2016-10-19 12:18:14 -070046 return true;
47 };
Adam Lesinski1ab598f2015-08-14 14:26:04 -070048
Adam Lesinskice5e56e2016-10-21 17:56:45 -070049 flags_.push_back(
50 Flag{name.ToString(), description.ToString(), func, true, 1, false});
Adam Lesinskicacb28f2016-10-19 12:18:14 -070051 return *this;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070052}
53
Adam Lesinskice5e56e2016-10-21 17:56:45 -070054Flags& Flags::OptionalFlag(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070055 const StringPiece& description,
Adam Lesinski1ab598f2015-08-14 14:26:04 -070056 Maybe<std::string>* value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070057 auto func = [value](const StringPiece& arg) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070058 *value = arg.ToString();
Adam Lesinskicacb28f2016-10-19 12:18:14 -070059 return true;
60 };
Adam Lesinski1ab598f2015-08-14 14:26:04 -070061
Adam Lesinskice5e56e2016-10-21 17:56:45 -070062 flags_.push_back(
63 Flag{name.ToString(), description.ToString(), func, false, 1, false});
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 return *this;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070065}
66
Adam Lesinskice5e56e2016-10-21 17:56:45 -070067Flags& Flags::OptionalFlagList(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070068 const StringPiece& description,
Adam Lesinski1ab598f2015-08-14 14:26:04 -070069 std::vector<std::string>* value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070070 auto func = [value](const StringPiece& arg) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070071 value->push_back(arg.ToString());
Adam Lesinskicacb28f2016-10-19 12:18:14 -070072 return true;
73 };
Adam Lesinski1ab598f2015-08-14 14:26:04 -070074
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 flags_.push_back(
76 Flag{name.ToString(), description.ToString(), func, false, 1, false});
Adam Lesinskicacb28f2016-10-19 12:18:14 -070077 return *this;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070078}
79
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080Flags& Flags::OptionalFlagList(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070081 const StringPiece& description,
Adam Lesinski9756dec2016-08-08 12:35:04 -070082 std::unordered_set<std::string>* value) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083 auto func = [value](const StringPiece& arg) -> bool {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070084 value->insert(arg.ToString());
Adam Lesinskicacb28f2016-10-19 12:18:14 -070085 return true;
86 };
Adam Lesinski9756dec2016-08-08 12:35:04 -070087
Adam Lesinskice5e56e2016-10-21 17:56:45 -070088 flags_.push_back(
89 Flag{name.ToString(), description.ToString(), func, false, 1, false});
Adam Lesinskicacb28f2016-10-19 12:18:14 -070090 return *this;
Adam Lesinski9756dec2016-08-08 12:35:04 -070091}
92
Adam Lesinskice5e56e2016-10-21 17:56:45 -070093Flags& Flags::OptionalSwitch(const StringPiece& name,
Adam Lesinskicacb28f2016-10-19 12:18:14 -070094 const StringPiece& description, bool* value) {
95 auto func = [value](const StringPiece& arg) -> bool {
96 *value = true;
97 return true;
98 };
Adam Lesinski1ab598f2015-08-14 14:26:04 -070099
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 flags_.push_back(
101 Flag{name.ToString(), description.ToString(), func, false, 0, false});
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700102 return *this;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700103}
104
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700105void Flags::Usage(const StringPiece& command, std::ostream* out) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700106 constexpr size_t kWidth = 50;
Adam Lesinski52364f72016-01-11 13:10:24 -0800107
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700108 *out << command << " [options]";
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700109 for (const Flag& flag : flags_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700110 if (flag.required) {
111 *out << " " << flag.name << " arg";
112 }
113 }
114
115 *out << " files...\n\nOptions:\n";
116
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700117 for (const Flag& flag : flags_) {
118 std::string argline = flag.name;
119 if (flag.num_args > 0) {
120 argline += " arg";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700121 }
122
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700123 // Split the description by newlines and write out the argument (which is
124 // empty after
125 // the first line) followed by the description line. This will make sure
126 // that multiline
127 // descriptions are still right justified and aligned.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700128 for (StringPiece line : util::Tokenize(flag.description, '\n')) {
129 *out << " " << std::setw(kWidth) << std::left << argline << line << "\n";
130 argline = " ";
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700131 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700132 }
133 *out << " " << std::setw(kWidth) << std::left << "-h"
134 << "Displays this help menu\n";
135 out->flush();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700136}
137
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700138bool Flags::Parse(const StringPiece& command,
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700139 const std::vector<StringPiece>& args,
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 std::ostream* out_error) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700141 for (size_t i = 0; i < args.size(); i++) {
142 StringPiece arg = args[i];
143 if (*(arg.data()) != '-') {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700144 args_.push_back(arg.ToString());
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700145 continue;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700146 }
147
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700148 if (arg == "-h" || arg == "--help") {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700149 Usage(command, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 return false;
151 }
152
153 bool match = false;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 for (Flag& flag : flags_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700155 if (arg == flag.name) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700156 if (flag.num_args > 0) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700157 i++;
158 if (i >= args.size()) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700159 *out_error << flag.name << " missing argument.\n\n";
160 Usage(command, out_error);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700161 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700162 }
163 flag.action(args[i]);
164 } else {
165 flag.action({});
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700166 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700167 flag.parsed = true;
168 match = true;
169 break;
170 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700171 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700172
173 if (!match) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700174 *out_error << "unknown option '" << arg << "'.\n\n";
175 Usage(command, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700176 return false;
177 }
178 }
179
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700180 for (const Flag& flag : flags_) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700181 if (flag.required && !flag.parsed) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182 *out_error << "missing required flag " << flag.name << "\n\n";
183 Usage(command, out_error);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700184 return false;
185 }
186 }
187 return true;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700188}
189
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190const std::vector<std::string>& Flags::GetArgs() { return args_; }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700191
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192} // namespace aapt