• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "util/options.h"
10 
11 #include <cstdio>
12 #include <cstring>
13 #include <dirent.h>
14 #include <getopt.h>
15 #include <sys/stat.h>
16 #include <unistd.h>
17 
18 #include "util/common.h"
19 #include "util/file.h"
20 #include "util/string_helper.h"
21 
22 #include "util/logger.h"
23 
24 namespace OHOS {
25 namespace HDI {
26 const char *Options::optSupportArgs = "c:d:r:";
27 static struct option g_longOpts[] = {
28     {"help",         no_argument,       nullptr, 'h'},
29     {"version",      no_argument,       nullptr, 'v'},
30     {"gen-c",        no_argument,       nullptr, 'C'},
31     {"gen-cpp",      no_argument,       nullptr, 'P'},
32     {"gen-java",     no_argument,       nullptr, 'J'},
33     {"gen-hash",     no_argument,       nullptr, 'H'},
34     {"build-target", required_argument, nullptr, 'p'},
35     {"module-name",  required_argument, nullptr, 'N'},
36     {"passthrough",  no_argument,       nullptr, 'T'},
37     {"kernel",       no_argument,       nullptr, 'K'},
38     {"dump-ast",     no_argument,       nullptr, 'D'},
39     {nullptr,        0,                 nullptr, 0  }
40 };
41 
GetInstance()42 Options &Options::GetInstance()
43 {
44     static Options option;
45     return option;
46 }
47 
Parse(int argc,char * argv[])48 Options &Options::Parse(int argc, char *argv[])
49 {
50     program_ = argv[0];
51     opterr = 1;
52     int op = 0;
53     int optIndex = 0;
54 
55     while ((op = getopt_long(argc, argv, optSupportArgs, g_longOpts, &optIndex)) != OPT_END) {
56         SetOptionData(op);
57     }
58     CheckOptions();
59 
60     return *this;
61 }
62 
SetOptionData(char op)63 void Options::SetOptionData(char op)
64 {
65     switch (op) {
66         case 'c':
67             AddSources(optarg);
68             break;
69         case 'd':
70             SetOutDir(optarg);
71             break;
72         case 'h':
73             doShowUsage_ = true;
74             break;
75         case 'v':
76             doShowVersion_ = true;
77             break;
78         case 'r':
79             AddPackagePath(optarg);
80             break;
81         case 'K':
82             doModeKernel_ = true;
83             break;
84         case 'N':
85             SetModuleName(optarg);
86             break;
87         case 'C':
88             SetLanguage(Language::C);
89             break;
90         case 'P':
91             SetLanguage(Language::CPP);
92             break;
93         case 'J':
94             SetLanguage(Language::JAVA);
95             break;
96         case 'p':
97             SetCodePart(optarg);
98             break;
99         case 'T':
100             doPassthrough_ = true;
101             break;
102         case 'H':
103             doGetHashKey_ = true;
104             break;
105         case 'D':
106             doDumpAST_ = true;
107             break;
108         case '?':
109         default:
110             doShowUsage_ = true;
111             break;
112     }
113 }
114 
AddPackagePath(const std::string & packagePath)115 void Options::AddPackagePath(const std::string &packagePath)
116 {
117     size_t index = packagePath.find(":");
118     if (index == std::string::npos || index == packagePath.size() - 1) {
119         errors_.push_back(
120             StringHelper::Format("%s: invalid option parameters '%s'.", program_.c_str(), packagePath.c_str()));
121         return;
122     }
123 
124     std::string package = packagePath.substr(0, index);
125     std::string path = File::AdapterRealPath(packagePath.substr(index + 1));
126     if (path.empty()) {
127         errors_.push_back(
128             StringHelper::Format("%s: invalid path '%s'.", program_.c_str(), packagePath.substr(index + 1).c_str()));
129         return;
130     }
131 
132     auto it = packagePath_.find(package);
133     if (it != packagePath_.end()) {
134         errors_.push_back(
135             StringHelper::Format("%s: The '%s:%s' has been set.", program_.c_str(), package.c_str(), path.c_str()));
136     }
137 
138     packagePath_[package] = path;
139 }
140 
AddSources(const std::string & sourceFile)141 void Options::AddSources(const std::string &sourceFile)
142 {
143     doCompile_ = true;
144     sourceFiles_.push_back(sourceFile);
145 }
146 
SetOutDir(const std::string & dir)147 void Options::SetOutDir(const std::string &dir)
148 {
149     doOutDir_ = true;
150     generationDirectory_ = dir;
151 }
152 
SetModuleName(const std::string & moduleName)153 void Options::SetModuleName(const std::string &moduleName)
154 {
155     doSetModuleName_ = true;
156     moduleName_ = moduleName;
157 }
158 
SetLanguage(Language kind)159 void Options::SetLanguage(Language kind)
160 {
161     doGenerateCode_ = true;
162     targetLanguage_ = kind;
163 }
164 
SetCodePart(const std::string & part)165 void Options::SetCodePart(const std::string &part)
166 {
167     // The default parameter is 'all', and the optional parameters is 'client' or 'server'
168     doGeneratePart_ = true;
169     codePart_ = part;
170 }
171 
CheckOptions()172 void Options::CheckOptions()
173 {
174     if (doShowUsage_ || doShowVersion_) {
175         return;
176     }
177 
178     if (doCompile_) {
179         if (!doGetHashKey_ && !doDumpAST_ && !doGenerateCode_ && !doOutDir_) {
180             errors_.push_back(StringHelper::Format("%s: nothing to do.", program_.c_str()));
181             return;
182         }
183 
184         if (!doGenerateCode_ && doOutDir_) {
185             errors_.push_back(StringHelper::Format("%s: no target language.", program_.c_str()));
186             return;
187         }
188 
189         if (doGenerateCode_ && !doOutDir_) {
190             errors_.push_back(StringHelper::Format("%s: no out directory.", program_.c_str()));
191             return;
192         }
193 
194         if (doGeneratePart_ && codePart_ != "all" && codePart_ != "client" && codePart_ != "server") {
195             std::string errorLog = "The '--build-target' option parameter must be 'client' 'server' or 'all'.";
196             errors_.push_back(StringHelper::Format("%s: %s", program_.c_str(), errorLog.c_str()));
197         }
198     } else {
199         if (doGetHashKey_ || doDumpAST_ || doGenerateCode_ || doOutDir_) {
200             errors_.push_back(StringHelper::Format("%s: no '-c' option.", program_.c_str()));
201             return;
202         }
203     }
204 }
205 
ShowErrors() const206 void Options::ShowErrors() const
207 {
208     for (auto error : errors_) {
209         printf("%s\n", error.c_str());
210     }
211     printf("Use \"--help\" to show usage.\n");
212 }
213 
ShowVersion() const214 void Options::ShowVersion() const
215 {
216     printf("HDI-GEN: %d.%d\n"
217            "Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.\n\n",
218         VERSION_MAJOR, VERSION_MINOR);
219 }
220 
ShowUsage() const221 void Options::ShowUsage() const
222 {
223     printf("Compile a .idl file and generate C/C++ and Java codes.\n"
224            "Usage: idl [options] file\n"
225            "Options:\n"
226            "  --help                          Display command line options\n"
227            "  --version                       Display toolchain version information\n"
228            "  --dump-ast                      Display the AST of the compiled file\n"
229            "  -r <rootPackage>:<rootPath>     set root path of root package\n"
230            "  -c <*.idl>                      Compile the .idl file\n"
231            "  --gen-hash                      Generate hash key of the idl file\n"
232            "  --gen-c                         Generate C code\n"
233            "  --gen-cpp                       Generate C++ code\n"
234            "  --gen-java                      Generate Java code\n"
235            "  --kernel                        Generate kernel-mode ioservice stub code,"
236            "default user-mode ioservice stub code\n"
237            "  --passthrough                   Generate code that only supports pass through mode"
238            "  --module-name <module name>     Set driver module name\n"
239            "  --build-target <target name>    Generate client code, server code or all code\n"
240            "  -d <directory>                  Place generated codes into <directory>\n");
241 }
242 
243 /*
244  * -r option: -r ohos.hdi:./drivers/interface
245  * package:ohos.hdi.foo.v1_0
246  * rootPackage:ohos.hdi
247  */
GetRootPackage(const std::string & package)248 std::string Options::GetRootPackage(const std::string &package)
249 {
250     const auto &packagePaths = GetPackagePathMap();
251     for (const auto &packageRoot : packagePaths) {
252         if (StringHelper::StartWith(package, packageRoot.first)) {
253             return packageRoot.first;
254         }
255     }
256 
257     return "";
258 }
259 
260 /*
261  * -r option: -r ohos.hdi:./drivers/interface
262  * package:ohos.hdi.foo.v1_0
263  * rootPath:./drivers/interface
264  */
GetRootPath(const std::string & package)265 std::string Options::GetRootPath(const std::string &package)
266 {
267     const auto &packagePaths = GetPackagePathMap();
268     for (const auto &packageRoot : packagePaths) {
269         if (StringHelper::StartWith(package, packageRoot.first)) {
270             return packageRoot.second;
271         }
272     }
273 
274     return "";
275 }
276 
277 /*
278  * -r option: -r ohos.hdi:./drivers/interface
279  * package:ohos.hdi.foo.v1_0
280  * subPackage:foo.v1_0
281  */
GetSubPackage(const std::string & package)282 std::string Options::GetSubPackage(const std::string &package)
283 {
284     std::string rootPackage = GetRootPackage(package);
285     if (rootPackage.empty()) {
286         return package;
287     }
288 
289     return package.substr(rootPackage.size() + 1);
290 }
291 
292 /*
293  * -r option: -r ohos.hdi:./drivers/interface
294  * package:ohos.hdi.foo.v1_0
295  * packagePath:./drivers/interface/foo/v1_0
296  */
GetPackagePath(const std::string & package)297 std::string Options::GetPackagePath(const std::string &package)
298 {
299     std::string rootPackage = "";
300     std::string rootPath = "";
301     const auto &packagePaths = GetPackagePathMap();
302     for (const auto &packageRoot : packagePaths) {
303         if (StringHelper::StartWith(package, packageRoot.first)) {
304             rootPackage = packageRoot.first;
305             rootPath = packageRoot.second;
306         }
307     }
308 
309     if (rootPackage.empty()) {
310         // The current path is the root path
311         std::string curPath = File::AdapterPath(StringHelper::Replace(package, '.', SEPARATOR));
312         return File::AdapterRealPath(curPath);
313     }
314 
315     if (StringHelper::EndWith(rootPath, SEPARATOR)) {
316         rootPath.pop_back();
317     }
318 
319     std::string subPath = StringHelper::Replace(package.substr(rootPackage.size() + 1), '.', SEPARATOR);
320     return File::AdapterPath(rootPath + "/" + subPath);
321 }
322 
323 /*
324  * -r option: -r ohos.hdi:./drivers/interface
325  * import: ohos.hdi.foo.v1_0.MyTypes
326  * packagePath:./drivers/interface/foo/v1_0/MyTypes.idl
327  */
GetImportFilePath(const std::string & import)328 std::string Options::GetImportFilePath(const std::string &import)
329 {
330     size_t index = import.rfind('.');
331     if (index == std::string::npos) {
332         return import;
333     }
334 
335     std::string dir = GetPackagePath(StringHelper::SubStr(import, 0, index));
336     std::string ClassName = import.substr(index + 1);
337     return StringHelper::Format("%s%c%s.idl", dir.c_str(), SEPARATOR, ClassName.c_str());
338 }
339 } // namespace HDI
340 } // namespace OHOS