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