11ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski/*
21ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Copyright (C) 2015 The Android Open Source Project
31ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
41ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
51ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * you may not use this file except in compliance with the License.
61ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * You may obtain a copy of the License at
71ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
81ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
91ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski *
101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * Unless required by applicable law or agreed to in writing, software
111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * See the License for the specific language governing permissions and
141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski * limitations under the License.
151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski */
161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include "Flags.h"
181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <iomanip>
201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <iostream>
211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <string>
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <vector>
231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
24d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski#include "androidfw/StringPiece.h"
25d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski
26ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski#include "util/Util.h"
27ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski
28d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinskiusing android::StringPiece;
29d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski
301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt {
311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
32ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiFlags& Flags::RequiredFlag(const StringPiece& name,
33cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                           const StringPiece& description, std::string* value) {
34cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto func = [value](const StringPiece& arg) -> bool {
35d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski    *value = arg.to_string();
36cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
37cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
38cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
39d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
40cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return *this;
411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
43ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiFlags& Flags::RequiredFlagList(const StringPiece& name,
44cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                               const StringPiece& description,
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                               std::vector<std::string>* value) {
46cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto func = [value](const StringPiece& arg) -> bool {
47d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski    value->push_back(arg.to_string());
48cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
49cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
51d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  flags_.push_back(Flag{name.to_string(), description.to_string(), func, true, 1, false});
52cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return *this;
531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
55ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiFlags& Flags::OptionalFlag(const StringPiece& name,
56cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                           const StringPiece& description,
571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                           Maybe<std::string>* value) {
58cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto func = [value](const StringPiece& arg) -> bool {
59d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski    *value = arg.to_string();
60cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
61cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
63d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
64cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return *this;
651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
67ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiFlags& Flags::OptionalFlagList(const StringPiece& name,
68cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                               const StringPiece& description,
691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                               std::vector<std::string>* value) {
70cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto func = [value](const StringPiece& arg) -> bool {
71d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski    value->push_back(arg.to_string());
72cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
73cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
75d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
76cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return *this;
779756dec248458abc7f4e7c59907299bba85521b4Adam Lesinski}
789756dec248458abc7f4e7c59907299bba85521b4Adam Lesinski
79ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiFlags& Flags::OptionalFlagList(const StringPiece& name,
80cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                               const StringPiece& description,
819756dec248458abc7f4e7c59907299bba85521b4Adam Lesinski                               std::unordered_set<std::string>* value) {
82cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto func = [value](const StringPiece& arg) -> bool {
83d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski    value->insert(arg.to_string());
84cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
85cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
869756dec248458abc7f4e7c59907299bba85521b4Adam Lesinski
87d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 1, false});
88cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return *this;
891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
91ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam LesinskiFlags& Flags::OptionalSwitch(const StringPiece& name,
92cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                             const StringPiece& description, bool* value) {
93cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  auto func = [value](const StringPiece& arg) -> bool {
94cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    *value = true;
95cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    return true;
96cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  };
971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
98d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski  flags_.push_back(Flag{name.to_string(), description.to_string(), func, false, 0, false});
99cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return *this;
1001ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1011ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
102ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskivoid Flags::Usage(const StringPiece& command, std::ostream* out) {
103cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  constexpr size_t kWidth = 50;
10452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
105cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  *out << command << " [options]";
106ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  for (const Flag& flag : flags_) {
107cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (flag.required) {
108cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      *out << " " << flag.name << " arg";
1091ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
110cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
1111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
112cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  *out << " files...\n\nOptions:\n";
1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
114ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  for (const Flag& flag : flags_) {
115ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    std::string argline = flag.name;
116ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    if (flag.num_args > 0) {
117ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      argline += " arg";
118cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
1192ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski
120cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // Split the description by newlines and write out the argument (which is
121cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // empty after
122cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // the first line) followed by the description line. This will make sure
123cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // that multiline
124cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    // descriptions are still right justified and aligned.
125ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (StringPiece line : util::Tokenize(flag.description, '\n')) {
126ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      *out << " " << std::setw(kWidth) << std::left << argline << line << "\n";
127ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      argline = " ";
1281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
129cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
130cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  *out << " " << std::setw(kWidth) << std::left << "-h"
131cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski       << "Displays this help menu\n";
132cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  out->flush();
1331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
135ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskibool Flags::Parse(const StringPiece& command,
136cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski                  const std::vector<StringPiece>& args,
137ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski                  std::ostream* out_error) {
138cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  for (size_t i = 0; i < args.size(); i++) {
139cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    StringPiece arg = args[i];
140cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (*(arg.data()) != '-') {
141d5083f6f6b9bc76bbe64052bcec639eee752a321Adam Lesinski      args_.push_back(arg.to_string());
142cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      continue;
143cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
1441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
145cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (arg == "-h" || arg == "--help") {
146ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      Usage(command, out_error);
147cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return false;
148cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
1491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
150cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    bool match = false;
151ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski    for (Flag& flag : flags_) {
152cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      if (arg == flag.name) {
153ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski        if (flag.num_args > 0) {
154cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          i++;
155cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          if (i >= args.size()) {
156ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            *out_error << flag.name << " missing argument.\n\n";
157ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski            Usage(command, out_error);
1581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            return false;
159cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          }
160cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          flag.action(args[i]);
161cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        } else {
162cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski          flag.action({});
1631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
164cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        flag.parsed = true;
165cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        match = true;
166cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski        break;
167cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      }
1681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
170cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (!match) {
171ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      *out_error << "unknown option '" << arg << "'.\n\n";
172ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      Usage(command, out_error);
173cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return false;
1741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
175cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
1761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
177ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski  for (const Flag& flag : flags_) {
178cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    if (flag.required && !flag.parsed) {
179ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      *out_error << "missing required flag " << flag.name << "\n\n";
180ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinski      Usage(command, out_error);
181cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski      return false;
182cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski    }
183cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  }
184cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski  return true;
1851ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
187ce5e56e243d262a9b65459c3bd0bb9eaadd40628Adam Lesinskiconst std::vector<std::string>& Flags::GetArgs() { return args_; }
188cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski
189cacb28f2d60858106e2819cc7d95a65e8bda890bAdam Lesinski}  // namespace aapt
190