• 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 
18 using namespace maplecl;
19 
20 /* ################################################################
21  * Utility Fuctions
22  * ################################################################ */
23 
24 /* Anonymous namespace to restrict visibility of utility functions */
25 namespace {
26 
27 #ifdef ARK_LITECG_DEBUG
IsPrefixDetected(std::string_view opt)28 bool IsPrefixDetected(std::string_view opt)
29 {
30     if (opt.substr(0, 2) == "--") { // whether opt start with 2 char "--"
31         return true;
32     }
33 
34     /* It should be "--" or "-" */
35     return (opt[0] == '-');
36 }
37 
38 /* NOTE: Returning size_t parameter is used to show how many command line arguments
39  * handled with this key. argsIndex must be incremented with this parameter outside of ExtractValue. */
ExtractValue(size_t argsIndex,const std::deque<std::string_view> & args,const OptionInterface & opt,KeyArg & keyArg)40 std::pair<RetCode, size_t> ExtractValue(size_t argsIndex, const std::deque<std::string_view> &args,
41                                         const OptionInterface &opt, KeyArg &keyArg)
42 {
43     /* The option like "--key= " does not contain a value after equal symbol */
44     if (keyArg.isEqualOpt == true && keyArg.val.empty()) {
45         return {RetCode::valueEmpty, 0};
46     }
47 
48     bool canValBeSet = (keyArg.isEqualOpt || opt.IsJoinedValPermitted());
49     /* Value is parsed outside OptionType::Parse because it's the option
50      * like "--key=val" or joined option like -DValue */
51     if (canValBeSet && !keyArg.val.empty()) {
52         if (opt.ExpectedVal() == ValueExpectedType::kValueDisallowed) {
53             return {RetCode::unnecessaryValue, 0};
54         }
55         return {RetCode::noError, 0};
56     } else {    // Need to parse second command line argument to check options value
57         /* Optional value can be set only with "=" like this --key=value  */
58         if (opt.ExpectedVal() == ValueExpectedType::kValueDisallowed ||
59             opt.ExpectedVal() == ValueExpectedType::kValueOptional) {
60             return {RetCode::noError, 0};
61         }
62 
63         /* localArgsIndex is used to be sure that nobody breaks the logic by
64          * changing argsIndex to reference. original argsIndex must be not changed here. */
65         size_t localArgsIndex = argsIndex + 1;
66         /* Second command line argument does not exist */
67         if (localArgsIndex >= args.size() || args[localArgsIndex].empty()) {
68             RetCode ret =
69                 (opt.ExpectedVal() == ValueExpectedType::kValueRequired) ? RetCode::valueEmpty : RetCode::noError;
70             return {ret, 0};
71         }
72 
73         keyArg.val = args[localArgsIndex];
74         return {RetCode::noError, 1};
75     }
76 }
77 #endif
78 } /* Anonymous namespace  */
79 
80 /* ################################################################
81  * Option Value Parsers Implementation
82  * ################################################################ */
83 
84 template <>
ParseBool(size_t & argsIndex,const std::deque<std::string_view> & args)85 RetCode Option<bool>::ParseBool(size_t &argsIndex, const std::deque<std::string_view> &args)
86 {
87 #ifdef ARK_LITECG_DEBUG
88     /* DisabledName should set it to false, like --fno-omit-framepointer vs --fomit-framepointer */
89     auto disabledNames = GetDisabledName();
90     auto it = std::find(disabledNames.begin(), disabledNames.end(), args[argsIndex]);
91     SetValue(it == disabledNames.end());
92 
93     ++argsIndex;
94 #endif
95     return RetCode::noError;
96 }
97 
98 /* NOTE: argsIndex must be incremented only if option is handled successfully */
99 template <>
ParseString(size_t & argsIndex,const std::deque<std::string_view> & args,KeyArg & keyArg)100 RetCode Option<std::string>::ParseString(size_t &argsIndex, const std::deque<std::string_view> &args, KeyArg &keyArg)
101 {
102 #ifdef ARK_LITECG_DEBUG
103     RetCode err = RetCode::noError;
104     size_t indexIncCnt = 0;
105     std::tie(err, indexIncCnt) = ExtractValue(argsIndex, args, *this, keyArg);
106     if (err != RetCode::noError) {
107         return err;
108     }
109 
110     if (keyArg.val.empty()) {
111         if (ExpectedVal() == ValueExpectedType::kValueRequired) {
112             return RetCode::valueEmpty;
113         }
114         ++argsIndex;
115         return RetCode::noError;
116     }
117 
118     /* Value is not empty but ValueDisallowed is set */
119     if (ExpectedVal() == ValueExpectedType::kValueDisallowed) {
120         return RetCode::unnecessaryValue;
121     }
122 
123     if (!keyArg.isEqualOpt && IsPrefixDetected(keyArg.val)) {
124         if (ExpectedVal() == ValueExpectedType::kValueRequired) {
125             return RetCode::valueEmpty;
126         }
127         ++argsIndex;
128         return RetCode::noError;
129     }
130 
131     SetValue(std::string(keyArg.val));
132     if (keyArg.isEqualOpt && !keyArg.isJoinedOpt) {
133         /* isJoinedOpt is used to prevent -DMACRO=VALUE.
134          * -DMACRO=VALUE uses "=" sign but it's not the separator between Option and Value,
135          * In this case it's a part of Value.
136          */
137         SetEqualType(EqualType::kWithEqual);
138     }
139 
140     argsIndex += 1 + indexIncCnt;  // 1 for key, indexIncCnt for Key Value from ExtractValue
141 #endif
142     return RetCode::noError;
143 }
144 
145 /* NOTE: argsIndex must be incremented only if option is handled successfully */
146 template <typename T>
ParseDigit(size_t & argsIndex,const std::deque<std::string_view> & args,KeyArg & keyArg)147 RetCode Option<T>::ParseDigit(size_t &argsIndex, const std::deque<std::string_view> &args, KeyArg &keyArg)
148 {
149 #ifdef ARK_LITECG_DEBUG
150     static_assert(digitalCheck<T>, "Expected (u)intXX types");
151 
152     RetCode err = RetCode::noError;
153     size_t indexIncCnt = 0;
154     std::tie(err, indexIncCnt) = ExtractValue(argsIndex, args, *this, keyArg);
155     if (err != RetCode::noError) {
156         return err;
157     }
158 
159     if (keyArg.val.empty()) {
160         if (ExpectedVal() == ValueExpectedType::kValueRequired) {
161             return RetCode::valueEmpty;
162         }
163         ++argsIndex;
164         return RetCode::noError;
165     }
166 
167     /* Value is not empty but ValueDisallowed is set */
168     if (ExpectedVal() == ValueExpectedType::kValueDisallowed) {
169         return RetCode::unnecessaryValue;
170     }
171 
172     T resDig = 0;
173     uint64_t udig = 0;
174     int64_t dig = 0;
175     char *endStrPtr;
176     errno = 0;
177     if constexpr (std::is_same_v<uint64_t, T> || std::is_same_v<uint32_t, T> || std::is_same_v<uint16_t, T> ||
178                   std::is_same_v<uint8_t, T>) {
179         if (keyArg.val.data()[0] == '-') {
180             return RetCode::incorrectValue;
181         }
182 
183         udig = std::strtoull(keyArg.val.data(), &endStrPtr, 0);
184         resDig = static_cast<T>(udig);
185     } else {
186         dig = std::strtoll(keyArg.val.data(), &endStrPtr, 0);
187         resDig = static_cast<T>(dig);
188     }
189 
190     bool u32Type = std::is_same<T, uint32_t>::value;
191     bool i32Type = std::is_same<T, int32_t>::value;
192     bool u16Type = std::is_same<T, uint16_t>::value;
193     bool u8Type = std::is_same<T, uint8_t>::value;
194     bool i16Type = std::is_same<T, int16_t>::value;
195     bool i8Type = std::is_same<T, int8_t>::value;
196 
197     if (*endStrPtr != '\0') {
198         return RetCode::incorrectValue;
199     }
200 
201     if (errno != 0) {
202         return RetCode::outOfRange;
203     }
204 
205     if (u32Type && udig > UINT32_MAX) {
206         return RetCode::outOfRange;
207     }
208 
209     if (i32Type && (dig > INT32_MAX || dig < INT32_MIN)) {
210         return RetCode::outOfRange;
211     }
212 
213     if (u16Type && udig > UINT16_MAX) {
214         return RetCode::outOfRange;
215     }
216 
217     if (i16Type && (dig > INT16_MAX || dig < INT16_MIN)) {
218         return RetCode::outOfRange;
219     }
220 
221     if (u8Type && udig > UINT8_MAX) {
222         return RetCode::outOfRange;
223     }
224 
225     if (i8Type && (dig > INT8_MAX || dig < INT8_MIN)) {
226         return RetCode::outOfRange;
227     }
228 
229     SetValue(resDig);
230     if (keyArg.isEqualOpt && !keyArg.isJoinedOpt) {
231         /* isJoinedOpt is used to prevent -DMACRO=VALUE.
232          * -DMACRO=VALUE uses "=" sign but it's not the separator between Option and Value,
233          * In this case it's a part of Value.
234          */
235         SetEqualType(EqualType::kWithEqual);
236     }
237 
238     argsIndex += 1 + indexIncCnt;  // 1 for key, indexIncCnt for Key Value from ExtractValue
239 #endif
240     return RetCode::noError;
241 }
242 
243 /* Needed to describe OptionType<>::Parse template in this .cpp file */
244 template class maplecl::Option<uint8_t>;
245 template class maplecl::Option<uint16_t>;
246 template class maplecl::Option<uint32_t>;
247 template class maplecl::Option<uint64_t>;
248 template class maplecl::Option<int8_t>;
249 template class maplecl::Option<int16_t>;
250 template class maplecl::Option<int32_t>;
251 template class maplecl::Option<int64_t>;
252