/* * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_LIBARTTOOLS_INCLUDE_TOOLS_CMDLINE_BUILDER_H_ #define ART_LIBARTTOOLS_INCLUDE_TOOLS_CMDLINE_BUILDER_H_ #include #include #include #include #include #include "android-base/stringprintf.h" namespace art { namespace tools { namespace internal { constexpr bool ContainsOneFormatSpecifier(std::string_view format, char specifier) { int count = 0; size_t pos = 0; while ((pos = format.find('%', pos)) != std::string_view::npos) { if (pos == format.length() - 1) { // Invalid trailing '%'. return false; } if (format[pos + 1] == specifier) { count++; } else if (format[pos + 1] != '%') { // "%%" is okay. Otherwise, it's a wrong specifier. return false; } pos += 2; } return count == 1; } } // namespace internal // A util class that builds cmdline arguments. class CmdlineBuilder { public: // Returns all arguments. const std::vector& Get() const { return elements_; } // Adds an argument as-is. CmdlineBuilder& Add(std::string_view arg) { elements_.push_back(std::string(arg)); return *this; } // Same as above but adds a runtime argument. CmdlineBuilder& AddRuntime(std::string_view arg) { return Add("--runtime-arg").Add(arg); } // Adds a string value formatted by the format string. // // Usage: Add("--flag=%s", "value") CmdlineBuilder& Add(const char* arg_format, const std::string& value) __attribute__((enable_if(internal::ContainsOneFormatSpecifier(arg_format, 's'), "'arg' must be a string literal that contains '%s'"))) { return Add(android::base::StringPrintf(arg_format, value.c_str())); } // Same as above but adds a runtime argument. CmdlineBuilder& AddRuntime(const char* arg_format, const std::string& value) __attribute__((enable_if(internal::ContainsOneFormatSpecifier(arg_format, 's'), "'arg' must be a string literal that contains '%s'"))) { return AddRuntime(android::base::StringPrintf(arg_format, value.c_str())); } // Adds an integer value formatted by the format string. // // Usage: Add("--flag=%d", 123) CmdlineBuilder& Add(const char* arg_format, int value) __attribute__((enable_if(internal::ContainsOneFormatSpecifier(arg_format, 'd'), "'arg' must be a string literal that contains '%d'"))) { return Add(android::base::StringPrintf(arg_format, value)); } // Same as above but adds a runtime argument. CmdlineBuilder& AddRuntime(const char* arg_format, int value) __attribute__((enable_if(internal::ContainsOneFormatSpecifier(arg_format, 'd'), "'arg' must be a string literal that contains '%d'"))) { return AddRuntime(android::base::StringPrintf(arg_format, value)); } // Adds a string value formatted by the format string if the value is non-empty. Does nothing // otherwise. // // Usage: AddIfNonEmpty("--flag=%s", "value") CmdlineBuilder& AddIfNonEmpty(const char* arg_format, const std::string& value) __attribute__((enable_if(internal::ContainsOneFormatSpecifier(arg_format, 's'), "'arg' must be a string literal that contains '%s'"))) { if (!value.empty()) { Add(android::base::StringPrintf(arg_format, value.c_str())); } return *this; } // Same as above but adds a runtime argument. CmdlineBuilder& AddRuntimeIfNonEmpty(const char* arg_format, const std::string& value) __attribute__((enable_if(internal::ContainsOneFormatSpecifier(arg_format, 's'), "'arg' must be a string literal that contains '%s'"))) { if (!value.empty()) { AddRuntime(android::base::StringPrintf(arg_format, value.c_str())); } return *this; } // Adds an argument as-is if the boolean value is true. Does nothing otherwise. CmdlineBuilder& AddIf(bool value, std::string_view arg) { if (value) { Add(arg); } return *this; } // Same as above but adds a runtime argument. CmdlineBuilder& AddRuntimeIf(bool value, std::string_view arg) { if (value) { AddRuntime(arg); } return *this; } // Concatenates this builder with another. Returns the concatenated result and nullifies the input // builder. CmdlineBuilder& Concat(CmdlineBuilder&& other) { elements_.reserve(elements_.size() + other.elements_.size()); std::move(other.elements_.begin(), other.elements_.end(), std::back_inserter(elements_)); other.elements_.clear(); return *this; } private: std::vector elements_; }; } // namespace tools } // namespace art #endif // ART_LIBARTTOOLS_INCLUDE_TOOLS_CMDLINE_BUILDER_H_