• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "cl_option.h"
17 #include "cl_parser.h"
18 
19 using namespace maplecl;
20 
GetCommandLine()21 CommandLine &CommandLine::GetCommandLine()
22 {
23     static CommandLine cl;
24     return cl;
25 }
26 
27 #ifdef ARK_LITECG_DEBUG
CheckJoinedOption(KeyArg & keyArg,OptionCategory & optCategory)28 OptionInterface *CommandLine::CheckJoinedOption(KeyArg &keyArg, OptionCategory &optCategory)
29 {
30     auto &str = keyArg.rawArg;
31 
32     for (auto joinedOption : optCategory.joinedOptions) {
33         /* Joined Option (like -DMACRO) can be detected as substring (-D) in the option string */
34         if (str.find(joinedOption.first) == 0) {
35             size_t keySize = joinedOption.first.size();
36 
37             keyArg.val = str.substr(keySize);
38             keyArg.key = str.substr(0, keySize);
39             keyArg.isJoinedOpt = true;
40             return joinedOption.second;
41         }
42     }
43 
44     return nullptr;
45 }
46 
ParseJoinedOption(size_t & argsIndex,const std::deque<std::string_view> & args,KeyArg & keyArg,OptionCategory & optCategory)47 RetCode CommandLine::ParseJoinedOption(size_t &argsIndex, const std::deque<std::string_view> &args, KeyArg &keyArg,
48                                        OptionCategory &optCategory)
49 {
50     OptionInterface *option = CheckJoinedOption(keyArg, optCategory);
51     if (option != nullptr) {
52         RetCode err = option->Parse(argsIndex, args, keyArg);
53         if (err != RetCode::noError) {
54             return err;
55         }
56 
57         /* Set Option in all categories registering for this option */
58         for (auto &category : option->optCategories) {
59             category->AddEnabledOption(option);
60         }
61     } else {
62         return RetCode::notRegistered;
63     }
64 
65     return RetCode::noError;
66 }
67 
ParseOption(size_t & argsIndex,const std::deque<std::string_view> & args,KeyArg & keyArg,OptionCategory & optCategory,OptionInterface * opt)68 RetCode CommandLine::ParseOption(size_t &argsIndex, const std::deque<std::string_view> &args, KeyArg &keyArg,
69                                  OptionCategory &optCategory, OptionInterface *opt)
70 {
71     RetCode err = opt->Parse(argsIndex, args, keyArg);
72     if (err != RetCode::noError) {
73         return err;
74     }
75 
76     /* Set Option in all categories registering for this option */
77     for (auto &category : opt->optCategories) {
78         category->AddEnabledOption(opt);
79     }
80 
81     return RetCode::noError;
82 }
83 
ParseEqualOption(size_t & argsIndex,const std::deque<std::string_view> & args,KeyArg & keyArg,OptionCategory & optCategory,const OptionsMapType & optMap,size_t pos)84 RetCode CommandLine::ParseEqualOption(size_t &argsIndex, const std::deque<std::string_view> &args, KeyArg &keyArg,
85                                       OptionCategory &optCategory, const OptionsMapType &optMap, size_t pos)
86 {
87     keyArg.isEqualOpt = true;
88     auto &arg = args[argsIndex];
89 
90     /* To handle joined option, we must have full (not splitted key),
91      * because joined option splitting is different:
92      * As example for -Dkey=value: default splitting key="Dkey" value="value",
93      * Joined option splitting key="D" value="key=value"
94      */
95     auto item = optMap.find(std::string(arg.substr(0, pos)));
96     if (item != optMap.end()) {
97         /* equal option, like --key=value */
98         keyArg.key = arg.substr(0, pos);
99         keyArg.val = arg.substr(pos + 1);
100         return ParseOption(argsIndex, args, keyArg, optCategory, item->second);
101     } else {
102         /* It can be joined option, like: -DMACRO=VALUE */
103         return ParseJoinedOption(argsIndex, args, keyArg, optCategory);
104     }
105 }
106 
ParseSimpleOption(size_t & argsIndex,const std::deque<std::string_view> & args,KeyArg & keyArg,OptionCategory & optCategory,const OptionsMapType & optMap)107 RetCode CommandLine::ParseSimpleOption(size_t &argsIndex, const std::deque<std::string_view> &args, KeyArg &keyArg,
108                                        OptionCategory &optCategory, const OptionsMapType &optMap)
109 {
110     keyArg.isEqualOpt = false;
111     auto &arg = args[argsIndex];
112 
113     auto item = optMap.find(std::string(arg));
114     if (item != optMap.end()) {
115         /* --key or --key value */
116         return ParseOption(argsIndex, args, keyArg, optCategory, item->second);
117     } else {
118         /* It can be joined option, like: -DMACRO */
119         return ParseJoinedOption(argsIndex, args, keyArg, optCategory);
120     }
121 }
122 #endif
123 
HandleInputArgs(const std::deque<std::string_view> & args,OptionCategory & optCategory)124 RetCode CommandLine::HandleInputArgs(const std::deque<std::string_view> &args, OptionCategory &optCategory)
125 {
126     RetCode err = RetCode::noError;
127 
128     /* badCLArgs contains option parsing errors for each incorrect option.
129      * We should clear old badCLArgs results. */
130     badCLArgs.clear();
131 
132 #ifdef ARK_LITECG_DEBUG
133     bool wasError = false;
134 #endif
135     for (size_t argsIndex = 0; argsIndex < args.size();) {
136         auto &arg = args[argsIndex];
137         if (arg == "") {
138             ++argsIndex;
139             continue;
140         }
141 #ifdef ARK_LITECG_DEBUG
142         KeyArg keyArg(arg);
143 
144         auto pos = arg.find('=');
145         /* option like --key=value */
146         if (pos != std::string::npos) {
147             DEBUG_ASSERT(pos > 0, "CG internal error, composite unit with less than 2 unit elements.");
148             err = ParseEqualOption(argsIndex, args, keyArg, optCategory, optCategory.options, pos);
149             if (err != RetCode::noError) {
150                 badCLArgs.emplace_back(args[argsIndex], err);
151                 ++argsIndex;
152                 wasError = true;
153             }
154             continue;
155         } else {
156             /* option like "--key value" or "--key" */
157             err = ParseSimpleOption(argsIndex, args, keyArg, optCategory, optCategory.options);
158             if (err != RetCode::noError) {
159                 badCLArgs.emplace_back(args[argsIndex], err);
160                 ++argsIndex;
161                 wasError = true;
162             }
163             continue;
164         }
165 #endif
166         ++argsIndex;
167         continue;
168     }
169 
170 #ifdef ARK_LITECG_DEBUG
171     if (wasError == true) {
172         return RetCode::parsingErr;
173     }
174 #endif
175 
176     return err;
177 }
178 
Parse(std::vector<std::string> argvs,OptionCategory & optCategory)179 RetCode CommandLine::Parse(std::vector<std::string> argvs, OptionCategory &optCategory)
180 {
181     std::deque<std::string_view> args;
182     for (size_t i = 0; i < argvs.size(); i++) {
183         args.emplace_back(argvs[i]);
184     }
185     return HandleInputArgs(args, optCategory);
186 }
187 
Register(const std::vector<std::string> & optNames,OptionInterface & opt,OptionCategory & optCategory)188 void CommandLine::Register(const std::vector<std::string> &optNames, OptionInterface &opt, OptionCategory &optCategory)
189 {
190     for (auto &optName : optNames) {
191         if (optName.empty()) {
192             continue;
193         }
194 
195         DEBUG_ASSERT(optCategory.options.count(optName) == 0, "Duplicated options name %s", optName.data());
196         optCategory.options.emplace(optName, &opt);
197 
198         if (opt.IsJoinedValPermitted()) {
199             optCategory.joinedOptions.emplace(optName, &opt);
200         }
201     }
202 
203     auto &disabledWith = opt.GetDisabledName();
204     if (!disabledWith.empty()) {
205         for (auto &disabledName : disabledWith) {
206             DEBUG_ASSERT(optCategory.options.count(disabledName) == 0, "Duplicated options name %s",
207                          disabledName.data());
208             optCategory.options.emplace(disabledName, &opt);
209         }
210     }
211 
212     optCategory.registredOptions.push_back(&opt);
213     opt.optCategories.push_back(&optCategory);
214 }