• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "argument_parser.h"
17 #include <iomanip>
18 #include <cstring>
19 #include <sstream>
20 #include <vector>
21 #include <memory>
22 #include <cstring>
23 #include "securec.h"
24 #include "sp_utils.h"
25 
26 namespace OHOS::SmartPerf {
27 namespace {
28 constexpr int LINE_W = 20;
29 }
30 
AddArgument(const std::string & name,ArgumentSpec info)31 void ArgumentParser::AddArgument(const std::string& name, ArgumentSpec info)
32 {
33     if (specs_.count(name)) {
34         errors_.push_back("Duplicate argument registered: " + name);
35         return;
36     }
37 
38     if ((info.type == ArgType::STRING || info.type == ArgType::BOOL) && (info.min || info.max)) {
39         errors_.push_back("Only INT type supports min/max: " + name);
40         return;
41     }
42 
43     specs_[name] = info;
44 }
45 
Parse(const std::string & input)46 void ArgumentParser::Parse(const std::string& input)
47 {
48     std::istringstream iss(input);
49     std::vector<std::string> tokens;
50     std::string token;
51 
52     while (iss >> std::quoted(token)) {
53         tokens.push_back(token);
54     }
55 
56     std::vector<std::unique_ptr<char[]>> storage;
57     std::vector<char*> argv;
58     for (auto& tok : tokens) {
59         size_t tokLength = tok.size() + 1;
60         storage.emplace_back(std::make_unique<char[]>(tokLength));
61         if (strcpy_s(storage.back().get(), tokLength, tok.c_str()) != EOK) {
62             return;
63         }
64         argv.push_back(storage.back().get());
65     }
66 
67     int argc = static_cast<int>(argv.size());
68     Parse(argc, argv.data());
69 }
70 
HandleIntParameter(const std::string & key,std::string value,const ArgumentSpec & spec)71 void ArgumentParser::HandleIntParameter(const std::string& key, std::string value, const ArgumentSpec& spec)
72 {
73     if (spec.type == ArgType::INT) {
74         int val = SPUtilesTye::StringToSometype<int>(value);
75         if (spec.min && val < *spec.min) {
76             errors_.push_back("Value for " + key + " below min: " + std::to_string(*spec.min));
77             return;
78         }
79         if (spec.max && val > *spec.max) {
80             errors_.push_back("Value for " + key + " above max: " + std::to_string(*spec.max));
81             return;
82         }
83         values_[key] = val;
84     } else {
85         values_[key] = value;
86     }
87 }
88 
Parse(int argc,char * argv[])89 void ArgumentParser::Parse(int argc, char* argv[])
90 {
91     std::set<std::string> seen_args;
92     for (int i = 1; i < argc; ++i) {
93         std::string key = argv[i];
94         if (key == "--help") {
95             helpMode_ = true;
96             return;
97         }
98         if (!specs_.count(key)) {
99             errors_.push_back("Unknown argument: " + key);
100             continue;
101         }
102         if (seen_args.count(key)) {
103             errors_.push_back("Duplicate argument: " + key);
104             const auto& spec = specs_[key];
105             if (spec.type != ArgType::BOOL && i + 1 < argc && specs_.count(argv[i + 1]) == 0) {
106                 ++i;
107             }
108             continue;
109         }
110         seen_args.insert(key);
111         const auto& spec = specs_[key];
112         if (spec.type == ArgType::BOOL) {
113             values_[key] = true;
114             continue;
115         }
116         if (i + 1 >= argc || specs_.count(argv[i + 1])) {
117             errors_.push_back("Missing value for argument: " + key);
118             continue;
119         }
120         HandleIntParameter(key, std::string(argv[++i]), spec);
121     }
122 }
123 
Get(const std::string & name) const124 std::optional<ArgumentParser::ArgValue> ArgumentParser::Get(const std::string& name) const
125 {
126     auto it = values_.find(name);
127     return it != values_.end() ? std::optional<ArgValue>(it->second) : std::nullopt;
128 }
129 
PrintHelp() const130 void ArgumentParser::PrintHelp() const
131 {
132     std::cout << "Available arguments:\n";
133     for (const auto& [k, v] : specs_) {
134         std::cout << "  " << std::left << std::setw(LINE_W) << k;
135 
136         switch (v.type) {
137             case ArgType::STRING: std::cout << std::right << "(string) - "; break;
138             case ArgType::INT:
139                 std::cout << "(int";
140                 if (v.min) std::cout << ", min=" << *v.min;
141                 if (v.max) std::cout << ", max=" << *v.max;
142                 std::cout << ") - ";
143                 break;
144             case ArgType::BOOL: break;
145         }
146 
147         if (!v.description.empty())
148             std::cout  << v.description;
149 
150         std::cout << "\n";
151     }
152 }
153 
Values() const154 const std::unordered_map<std::string, ArgumentParser::ArgValue>& ArgumentParser::Values() const
155 {
156     return values_;
157 }
158 
Errors() const159 const std::vector<std::string>& ArgumentParser::Errors() const
160 {
161     return errors_;
162 }
163 
Ok() const164 bool ArgumentParser::Ok() const
165 {
166     return errors_.empty();
167 }
168 
IsHelpMode() const169 bool ArgumentParser::IsHelpMode() const
170 {
171     return helpMode_;
172 }
173 
SetValue(const std::string & key,const ArgValue & value)174 void ArgumentParser::SetValue(const std::string& key, const ArgValue& value)
175 {
176     values_[key] = value;
177 }
178 }