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#include "util/StringPiece.h"
192ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski#include "util/Util.h"
201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <iomanip>
221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <iostream>
231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <string>
241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski#include <vector>
251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskinamespace aapt {
271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
281ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiFlags& Flags::requiredFlag(const StringPiece& name, const StringPiece& description,
291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                         std::string* value) {
301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto func = [value](const StringPiece& arg) -> bool {
311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        *value = arg.toString();
321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return true;
331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    };
341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    mFlags.push_back(Flag{ name.toString(), description.toString(), func, true, 1, false});
361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return *this;
371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
391ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiFlags& Flags::requiredFlagList(const StringPiece& name, const StringPiece& description,
401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                               std::vector<std::string>* value) {
411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto func = [value](const StringPiece& arg) -> bool {
421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        value->push_back(arg.toString());
431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return true;
441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    };
451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    mFlags.push_back(Flag{ name.toString(), description.toString(), func, true, 1, false });
471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return *this;
481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
501ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiFlags& Flags::optionalFlag(const StringPiece& name, const StringPiece& description,
511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                           Maybe<std::string>* value) {
521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto func = [value](const StringPiece& arg) -> bool {
531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        *value = arg.toString();
541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return true;
551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    };
561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    mFlags.push_back(Flag{ name.toString(), description.toString(), func, false, 1, false });
581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return *this;
591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
611ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiFlags& Flags::optionalFlagList(const StringPiece& name, const StringPiece& description,
621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                               std::vector<std::string>* value) {
631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto func = [value](const StringPiece& arg) -> bool {
641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        value->push_back(arg.toString());
651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return true;
661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    };
671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    mFlags.push_back(Flag{ name.toString(), description.toString(), func, false, 1, false });
691ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return *this;
701ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
711ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
721ab598f46c3ff520a67f9d80194847741f3467abAdam LesinskiFlags& Flags::optionalSwitch(const StringPiece& name, const StringPiece& description,
731ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                             bool* value) {
741ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    auto func = [value](const StringPiece& arg) -> bool {
751ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        *value = true;
761ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        return true;
771ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    };
781ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
791ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    mFlags.push_back(Flag{ name.toString(), description.toString(), func, false, 0, false });
801ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return *this;
811ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
821ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
831ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskivoid Flags::usage(const StringPiece& command, std::ostream* out) {
8452364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski    constexpr size_t kWidth = 50;
8552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski
861ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    *out << command << " [options]";
871ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (const Flag& flag : mFlags) {
881ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (flag.required) {
891ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            *out << " " << flag.name << " arg";
901ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
911ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
921ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
931ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    *out << " files...\n\nOptions:\n";
941ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
951ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (const Flag& flag : mFlags) {
961ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        std::string argLine = flag.name;
971ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (flag.numArgs > 0) {
981ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            argLine += " arg";
991ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1002ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski
1012ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski        // Split the description by newlines and write out the argument (which is empty after
1022ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski        // the first line) followed by the description line. This will make sure that multiline
1032ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski        // descriptions are still right justified and aligned.
1042ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski        for (StringPiece line : util::tokenize<char>(flag.description, '\n')) {
10552364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski            *out << " " << std::setw(kWidth) << std::left << argLine << line << "\n";
1062ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski            argLine = " ";
1072ae4a877d1623f851040ce69239552c873f1abf0Adam Lesinski        }
1081ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
10952364f7ae31716d7827ea8f8566f4a28bd30a921Adam Lesinski    *out << " " << std::setw(kWidth) << std::left << "-h" << "Displays this help menu\n";
1101ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    out->flush();
1111ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1121ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1131ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskibool Flags::parse(const StringPiece& command, const std::vector<StringPiece>& args,
1141ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                  std::ostream* outError) {
1151ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (size_t i = 0; i < args.size(); i++) {
1161ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        StringPiece arg = args[i];
1171ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (*(arg.data()) != '-') {
1181ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            mArgs.push_back(arg.toString());
1191ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            continue;
1201ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1211ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1221ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (arg == "-h" || arg == "--help") {
1231ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            usage(command, outError);
1241ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            return false;
1251ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1261ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1271ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        bool match = false;
1281ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        for (Flag& flag : mFlags) {
1291ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            if (arg == flag.name) {
1301ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                if (flag.numArgs > 0) {
1311ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    i++;
1321ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    if (i >= args.size()) {
1331ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        *outError << flag.name << " missing argument.\n\n";
1341ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        usage(command, outError);
1351ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                        return false;
1361ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    }
1371ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    flag.action(args[i]);
1381ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                } else {
1391ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                    flag.action({});
1401ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                }
1411ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                flag.parsed = true;
1421ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                match = true;
1431ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski                break;
1441ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            }
1451ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1461ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1471ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (!match) {
1481ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            *outError << "unknown option '" << arg << "'.\n\n";
1491ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            usage(command, outError);
1501ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            return false;
1511ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1521ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1531ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1541ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    for (const Flag& flag : mFlags) {
1551ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        if (flag.required && !flag.parsed) {
1561ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            *outError << "missing required flag " << flag.name << "\n\n";
1571ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            usage(command, outError);
1581ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski            return false;
1591ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski        }
1601ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    }
1611ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return true;
1621ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1631ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1641ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinskiconst std::vector<std::string>& Flags::getArgs() {
1651ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski    return mArgs;
1661ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski}
1671ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski
1681ab598f46c3ff520a67f9d80194847741f3467abAdam Lesinski} // namespace aapt
169