blob: 28c3797226e1d388eeb2855f33d4b59e986daae4 [file] [log] [blame]
MÃ¥rten Kongstad02751232018-04-27 13:16:32 +02001/*
2 * Copyright (C) 2018 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 <algorithm>
18#include <iomanip>
19#include <iostream>
20#include <memory>
21#include <set>
22#include <string>
23#include <vector>
24
25#include "android-base/macros.h"
26
27#include "idmap2/CommandLineOptions.h"
28
29namespace android {
30namespace idmap2 {
31
32std::unique_ptr<std::vector<std::string>> CommandLineOptions::ConvertArgvToVector(
33 int argc, const char** argv) {
34 return std::unique_ptr<std::vector<std::string>>(
35 new std::vector<std::string>(argv + 1, argv + argc));
36}
37
38CommandLineOptions& CommandLineOptions::OptionalFlag(const std::string& name,
39 const std::string& description, bool* value) {
40 assert(value != nullptr);
41 auto func = [value](const std::string& arg ATTRIBUTE_UNUSED) -> void { *value = true; };
42 options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL, false});
43 return *this;
44}
45
46CommandLineOptions& CommandLineOptions::MandatoryOption(const std::string& name,
47 const std::string& description,
48 std::string* value) {
49 assert(value != nullptr);
50 auto func = [value](const std::string& arg) -> void { *value = arg; };
51 options_.push_back(Option{name, description, func, Option::COUNT_EXACTLY_ONCE, true});
52 return *this;
53}
54
55CommandLineOptions& CommandLineOptions::MandatoryOption(const std::string& name,
56 const std::string& description,
57 std::vector<std::string>* value) {
58 assert(value != nullptr);
59 auto func = [value](const std::string& arg) -> void { value->push_back(arg); };
60 options_.push_back(Option{name, description, func, Option::COUNT_ONCE_OR_MORE, true});
61 return *this;
62}
63
64CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
65 const std::string& description,
66 std::string* value) {
67 assert(value != nullptr);
68 auto func = [value](const std::string& arg) -> void { *value = arg; };
69 options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL, true});
70 return *this;
71}
72
73bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
74 const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
75 return opt.count != Option::COUNT_OPTIONAL;
76 });
77 std::set<std::string> mandatory_opts;
78 std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()),
79 [](const Option& opt) -> std::string { return opt.name; });
80
81 const size_t argv_size = argv.size();
82 for (size_t i = 0; i < argv_size; i++) {
83 const std::string arg = argv[i];
84 if ("--help" == arg || "-h" == arg) {
85 Usage(outError);
86 return false;
87 }
88 bool match = false;
89 for (const Option& opt : options_) {
90 if (opt.name == arg) {
91 match = true;
92
93 if (opt.argument) {
94 i++;
95 if (i >= argv_size) {
96 outError << "error: " << opt.name << ": missing argument" << std::endl;
97 Usage(outError);
98 return false;
99 }
100 }
101 opt.action(argv[i]);
102 mandatory_opts.erase(opt.name);
103 break;
104 }
105 }
106 if (!match) {
107 outError << "error: " << arg << ": unknown option" << std::endl;
108 Usage(outError);
109 return false;
110 }
111 }
112
113 if (!mandatory_opts.empty()) {
114 for (auto iter = mandatory_opts.cbegin(); iter != mandatory_opts.cend(); ++iter) {
115 outError << "error: " << *iter << ": missing mandatory option" << std::endl;
116 }
117 Usage(outError);
118 return false;
119 }
120 return true;
121}
122
123void CommandLineOptions::Usage(std::ostream& out) const {
124 size_t maxLength = 0;
125 out << "usage: " << name_;
126 for (const Option& opt : options_) {
127 const bool mandatory = opt.count != Option::COUNT_OPTIONAL;
128 out << " ";
129 if (!mandatory) {
130 out << "[";
131 }
132 if (opt.argument) {
133 out << opt.name << " arg";
134 maxLength = std::max(maxLength, opt.name.size() + 4);
135 } else {
136 out << opt.name;
137 maxLength = std::max(maxLength, opt.name.size());
138 }
139 if (!mandatory) {
140 out << "]";
141 }
142 if (opt.count == Option::COUNT_ONCE_OR_MORE) {
143 out << " [" << opt.name << " arg [..]]";
144 }
145 }
146 out << std::endl << std::endl;
147 for (const Option& opt : options_) {
148 out << std::left << std::setw(maxLength);
149 if (opt.argument) {
150 out << (opt.name + " arg");
151 } else {
152 out << opt.name;
153 }
154 out << " " << opt.description;
155 if (opt.count == Option::COUNT_ONCE_OR_MORE) {
156 out << " (can be provided multiple times)";
157 }
158 out << std::endl;
159 }
160}
161
162} // namespace idmap2
163} // namespace android