Files
rocm-systems/shared/amdgpu-windows-interop/sc/HSAIL/ext/libamdhsacode/amd_options.cpp
T
2025-09-05 10:32:44 -04:00

382 строки
11 KiB
C++

////////////////////////////////////////////////////////////////////////////////
//
// The University of Illinois/NCSA
// Open Source License (NCSA)
//
// Copyright (c) 2014-2016, Advanced Micro Devices, Inc. All rights reserved.
//
// Developed by:
//
// AMD Research and AMD HSA Software Development
//
// Advanced Micro Devices, Inc.
//
// www.amd.com
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// - Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimers in
// the documentation and/or other materials provided with the distribution.
// - Neither the names of Advanced Micro Devices, Inc,
// nor the names of its contributors may be used to endorse or promote
// products derived from this Software without specific prior written
// permission.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS WITH THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////
#include "amd_options.hpp"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <list>
#include <string>
#include <cstddef>
namespace amd {
namespace options {
//===----------------------------------------------------------------------===//
// StringFactory. //
//===----------------------------------------------------------------------===//
std::string StringFactory::Flatten(const char **cstrs,
const uint32_t &cstrs_count,
const char &spacer) {
if (NULL == cstrs || 0 == cstrs_count) {
return std::string();
}
std::string flattened;
for (uint32_t i = 0; i < cstrs_count; ++i) {
if (NULL == cstrs[i]) {
return std::string();
}
flattened += cstrs[i];
if (i != (cstrs_count - 1)) {
flattened += spacer;
}
}
return flattened;
}
std::list<std::string> StringFactory::Tokenize(const char *cstr,
const char &delim) {
if (NULL == cstr) {
return std::list<std::string>();
}
const std::string str = cstr;
size_t start = 0;
size_t end = 0;
std::list<std::string> tokens;
while ((end = str.find(delim, start)) != std::string::npos) {
if (start != end) {
tokens.push_back(str.substr(start, end - start));
}
start = end + 1;
}
if (str.size() > start) {
tokens.push_back(str.substr(start));
}
return tokens;
}
std::string StringFactory::ToLower(const std::string& str) {
std::string lower(str.length(), ' ');
std::transform(str.begin(), str.end(), lower.begin(), ::tolower);
return lower;
}
std::string StringFactory::ToUpper(const std::string& str) {
std::string upper(str.length(), ' ');
std::transform(str.begin(), str.end(), upper.begin(), ::toupper);
return upper;
}
//===----------------------------------------------------------------------===//
// HelpPrinter, HelpStreambuf. //
//===----------------------------------------------------------------------===//
HelpStreambuf::HelpStreambuf(std::ostream& stream)
: basicStream_(&stream),
basicBuf_(stream.rdbuf()),
wrapWidth_(0),
indentSize_(0),
atLineStart_(true),
lineWidth_(0)
{
basicStream_->rdbuf(this);
}
HelpStreambuf::int_type HelpStreambuf::overflow(HelpStreambuf::int_type ch) {
if (atLineStart_ && ch != '\n') {
std::string indent(indentSize_, ' ');
basicBuf_->sputn(indent.data(), indent.size());
lineWidth_ = indentSize_;
atLineStart_ = false;
} else if (ch == '\n') {
atLineStart_ = true;
lineWidth_ = 0;
}
if (wrapWidth_ > 0 && lineWidth_ == wrapWidth_) {
basicBuf_->sputc('\n');
std::string indent(indentSize_, ' ');
basicBuf_->sputn(indent.data(), indent.size());
lineWidth_ = indentSize_;
atLineStart_ = false;
}
lineWidth_++;
return basicBuf_->sputc(ch);
}
HelpPrinter& HelpPrinter::PrintUsage(const std::string& usage) {
sbuf_.IndentSize(0);
sbuf_.WrapWidth(0);
Stream() << usage;
if (usage.length() < USAGE_WIDTH) {
Stream() << std::string(USAGE_WIDTH - usage.length(), ' ');
}
Stream() << std::string(PADDING_WIDTH, ' ');
return *this;
}
HelpPrinter& HelpPrinter::PrintDescription(const std::string& description) {
sbuf_.WrapWidth(USAGE_WIDTH + PADDING_WIDTH + DESCRIPTION_WIDTH);
sbuf_.IndentSize(USAGE_WIDTH + PADDING_WIDTH);
Stream() << description << std::endl;
sbuf_.IndentSize(0);
sbuf_.WrapWidth(0);
return *this;
}
//===----------------------------------------------------------------------===//
// ChoiceOptioin. //
//===----------------------------------------------------------------------===//
ChoiceOption::ChoiceOption(const std::string& name,
const std::vector<std::string>& choices,
const std::string& help,
std::ostream& error)
: OptionBase(name, help, error) {
for (const auto& choice: choices) {
choices_.insert(choice);
}
}
bool ChoiceOption::ProcessTokens(std::list<std::string> &tokens) {
assert(0 == name_.compare(tokens.front()) && "option name is mismatched");
if (2 != tokens.size()) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
tokens.pop_front();
if (0 == choices_.count(tokens.front())) {
error() << "error: invalid option: \'" << name_ << '\'' << std::endl;
return false;
}
is_set_ = true;
value_ = tokens.front();
tokens.pop_front();
return true;
}
void ChoiceOption::PrintHelp(HelpPrinter& printer) const {
std::string usage = "-" + name_ + "=[";
bool first = true;
for (const auto& choice: choices_) {
if (!first) {
usage += '|';
} else {
first = false;
}
usage += choice;
}
usage += "]";
printer.PrintUsage(usage).PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// PrefixOption. //
//===----------------------------------------------------------------------===//
bool PrefixOption::IsValid() const {
return (0 < name_.size()) && (name_.find(':') == std::string::npos);
}
std::string::size_type PrefixOption::FindPrefix(const std::string& token) const {
auto prefix = name_ + ':';
return token.find(prefix);
}
bool PrefixOption::Accept(const std::string& token) const {
return
(token.compare(0, name_.length(), name_) == 0) &&
token.length() > name_.length() &&
token[name_.length()] == ':';
}
bool PrefixOption::ProcessTokens(std::list<std::string> &tokens) {
assert(1 <= tokens.size());
assert(Accept(tokens.front()) && "option name is mismatched");
std::string value = tokens.front(); tokens.pop_front();
value = value.substr(name_.length() + 1);
for (const auto& token: tokens) {
value += '=';
value += token;
}
tokens.clear();
values_.push_back(value);
is_set_ = true;
return true;
}
void PrefixOption::PrintHelp(HelpPrinter& printer) const {
printer.PrintUsage("-" + name_ + ":[value]").PrintDescription(help_);
}
//===----------------------------------------------------------------------===//
// OptionParser. //
//===----------------------------------------------------------------------===//
std::vector<OptionBase*>::iterator
OptionParser::FindOption(const std::string& name) {
std::vector<OptionBase*>::iterator it = options_.begin();
std::vector<OptionBase*>::iterator end = options_.end();
for (; it != end; ++it) {
if ((*it)->Accept(name)) {
return it;
}
}
return end;
}
bool OptionParser::AddOption(OptionBase *option) {
if (NULL == option || !option->IsValid()) {
return false;
}
if (FindOption(option->name()) != options_.end()) {
return false;
}
options_.push_back(option);
return true;
}
const std::string& OptionParser::Unknown() const {
assert(collectUnknown_);
return unknownOptions_;
}
bool OptionParser::ParseOptions(const char *options) {
std::list<std::string> tokens_l1 = StringFactory::Tokenize(options, ' ');
if (0 == tokens_l1.size()) {
return true;
}
std::list<std::string>::iterator tokens_l1i = tokens_l1.begin();
while (tokens_l1i != tokens_l1.end()) {
if ('-' == tokens_l1i->at(0)) {
std::list<std::string>::iterator option_begin = tokens_l1i;
std::list<std::string> tokens_l2;
do {
tokens_l2.push_back(*tokens_l1i);
tokens_l1i++;
} while (tokens_l1i != tokens_l1.end() && '-' != tokens_l1i->at(0));
std::list<std::string>::iterator option_end = tokens_l1i;
tokens_l2.front().erase(0, 1);
if (1 == tokens_l2.size()) {
tokens_l2 = StringFactory::Tokenize(tokens_l2.front().c_str(), '=');
if (2 < tokens_l2.size()) {
if (collectUnknown_) {
unknownOptions_ += *tokens_l1i + " ";
continue;
} else {
error() << "error: invalid option format: \'"
<< tokens_l2.front() << '\'' << std::endl;
Reset();
return false;
}
}
}
auto find_status = FindOption(tokens_l2.front());
if (find_status == options_.end()) {
if (collectUnknown_) {
for (; option_begin != option_end; ++option_begin) {
unknownOptions_ += *option_begin + " ";
}
continue;
} else {
error() << "error: unknown option: \'"
<< tokens_l2.front() << '\'' << std::endl;
Reset();
return false;
}
}
if (!(*find_status)->ProcessTokens(tokens_l2)) {
Reset();
return false;
}
assert(0 == tokens_l2.size());
} else {
if (collectUnknown_) {
unknownOptions_ += *tokens_l1i + " ";
} else {
error() << "error: unknown option: \'"
<< *tokens_l1i << '\'' << std::endl;
Reset();
return false;
}
}
}
return true;
}
void OptionParser::PrintHelp(std::ostream& out, const std::string& addition) const {
HelpPrinter printer(out);
for (const auto& option: options_) {
option->PrintHelp(printer);
}
out << addition << std::endl;
}
void OptionParser::Reset() {
unknownOptions_.clear();
for (auto &option : options_) {
option->Reset();
}
}
} // namespace options
} // namespace amd