• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2021 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "tools/common/flag_parser.h"
18 #include "src/common/log_adapter.h"
19 
20 namespace mindspore {
21 namespace lite {
22 // parse flags read from command line
ParseFlags(int argc,const char * const * argv,bool supportUnknown,bool supportDuplicate)23 Option<std::string> FlagParser::ParseFlags(int argc, const char *const *argv, bool supportUnknown,
24                                            bool supportDuplicate) {
25   MS_ASSERT(argv != nullptr);
26   const int FLAG_PREFIX_LEN = 2;
27   if (argc <= 0) {
28     MS_LOG(ERROR) << "The arguments number is out of range";
29     return Option<std::string>("Failed: flags is not valid");
30   }
31   binName = GetFileName(argv[0]);
32 
33   std::multimap<std::string, Option<std::string>> keyValues{};
34   for (int i = 1; i < argc; i++) {
35     std::string tmp = argv[i];
36     Trim(&tmp);
37     const std::string flagItem(tmp);
38 
39     if (flagItem == "--") {
40       break;
41     }
42 
43     if (flagItem.find("--") == std::string::npos) {
44       return Option<std::string>("Failed: flag " + flagItem + " is not valid.");
45     }
46 
47     std::string key;
48     Option<std::string> value = Option<std::string>(None());
49 
50     size_t pos = flagItem.find_first_of('=');
51     if (pos == std::string::npos) {
52       key = flagItem.substr(FLAG_PREFIX_LEN);
53     } else {
54       key = flagItem.substr(FLAG_PREFIX_LEN, pos - FLAG_PREFIX_LEN);
55       value = Option<std::string>(flagItem.substr(pos + 1));
56     }
57 
58     keyValues.insert(std::pair<std::string, Option<std::string>>(key, value));
59   }
60 
61   Option<std::string> ret = Option<std::string>(InnerParseFlags(&keyValues));
62   if (ret.IsSome()) {
63     return Option<std::string>(ret.Get());
64   }
65 
66   return Option<std::string>(None());
67 }
68 
GetRealFlagName(std::string * flagName,const std::string & oriFlagName)69 bool FlagParser::GetRealFlagName(std::string *flagName, const std::string &oriFlagName) {
70   MS_ASSERT(flagName != nullptr);
71   const int BOOL_TYPE_FLAG_PREFIX_LEN = 3;
72   bool opaque = false;
73   if (StartsWithPrefix(oriFlagName, "no-")) {
74     *flagName = oriFlagName.substr(BOOL_TYPE_FLAG_PREFIX_LEN);
75     opaque = true;
76   } else {
77     *flagName = oriFlagName;
78   }
79   return opaque;
80 }
81 
82 // Inner parse function
InnerParseFlags(std::multimap<std::string,Option<std::string>> * keyValues)83 Option<std::string> FlagParser::InnerParseFlags(std::multimap<std::string, Option<std::string>> *keyValues) {
84   MS_ASSERT(keyValues != nullptr);
85   for (auto &keyValue : *keyValues) {
86     std::string flagName;
87     bool opaque = GetRealFlagName(&flagName, keyValue.first);
88     Option<std::string> flagValue = keyValue.second;
89 
90     auto item = flags.find(flagName);
91     if (item == flags.end()) {
92       return Option<std::string>(std::string(flagName + " is not a valid flag"));
93     }
94     FlagInfo *flag = &(item->second);
95     if (flag == nullptr) {
96       return Option<std::string>("Failed: flag is nullptr");
97     }
98     if (flag->isParsed) {
99       return Option<std::string>("Failed: already parsed flag: " + flagName);
100     }
101     std::string tmpValue;
102     if (!flag->isBoolean) {
103       if (opaque) {
104         return Option<std::string>(flagName + " is not a boolean type");
105       }
106       if (flagValue.IsNone()) {
107         return Option<std::string>("No value provided for non-boolean type: " + flagName);
108       }
109       tmpValue = flagValue.Get();
110     } else {
111       if (flagValue.IsNone() || flagValue.Get().empty()) {
112         tmpValue = !opaque ? "true" : "false";
113       } else if (!opaque) {
114         tmpValue = flagValue.Get();
115       } else {
116         return Option<std::string>(std::string("Boolean flag can not have non-empty value"));
117       }
118     }
119     // begin to parse value
120     Option<Nothing> ret = flag->parse(this, tmpValue);
121     if (ret.IsNone()) {
122       return Option<std::string>("Failed to parse value for: " + flag->flagName);
123     }
124     flag->isParsed = true;
125   }
126 
127   // to check flags not given in command line but added as in constructor
128   for (auto &flag : flags) {
129     if (flag.second.isRequired && !flag.second.isParsed) {
130       return Option<std::string>("Error, value of '" + flag.first + "' not provided");
131     }
132   }
133 
134   return Option<std::string>(None());
135 }
136 
ReplaceAll(std::string * str,const std::string & oldValue,const std::string & newValue)137 void ReplaceAll(std::string *str, const std::string &oldValue, const std::string &newValue) {
138   if (str == nullptr) {
139     MS_LOG(ERROR) << "Input str is nullptr";
140     return;
141   }
142   while (true) {
143     std::string::size_type pos(0);
144     if ((pos = str->find(oldValue)) != std::string::npos) {
145       str->replace(pos, oldValue.length(), newValue);
146     } else {
147       break;
148     }
149   }
150 }
151 
Usage(const Option<std::string> & usgMsg) const152 std::string FlagParser::Usage(const Option<std::string> &usgMsg) const {
153   // first line, brief of the usage
154   std::string usageString = usgMsg.IsSome() ? usgMsg.Get() + "\n" : "";
155   // usage of bin name
156   usageString += usageMsg.IsNone() ? "\nusage: " + binName + " [options]\n" : usageMsg.Get() + "\n";
157   // help line of help message, usageLine:message of parameters
158   std::string helpLine;
159   std::string usageLine;
160   uint32_t i = 0;
161   for (auto flag = flags.begin(); flag != flags.end(); flag++) {
162     std::string flagName = flag->second.flagName;
163     std::string helpInfo = flag->second.helpInfo;
164     // parameter line
165     std::string thisLine = flagName == "help" ? " --" + flagName : " --" + flagName + "=VALUE";
166     if (++i <= flags.size()) {
167       // add parameter help message of each line
168       thisLine += " " + helpInfo;
169       ReplaceAll(&helpInfo, "\n\r", "\n");
170       usageLine += thisLine + "\n";
171     } else {
172       // brief help message
173       helpLine = thisLine + " " + helpInfo + "\n";
174     }
175   }
176   // total usage is brief of usage+ brief of bin + help message + brief of
177   // parameters
178   return usageString + helpLine + usageLine;
179 }
180 }  // namespace lite
181 }  // namespace mindspore
182