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 "options.h"
10 #include <cstdio>
11 #include <cstring>
12 #include <dirent.h>
13 #include <getopt.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include "util/file.h"
17
18 namespace OHOS {
19 namespace HDI {
20 const char* Options::optSupportArgs = "c:d:r:";
21 static struct option g_longOpts[] = {
22 {"help", no_argument, nullptr, 'h'},
23 {"version", no_argument, nullptr, 'v'},
24 {"gen-c", no_argument, nullptr, 'C'},
25 {"gen-cpp", no_argument, nullptr, 'P'},
26 {"gen-java", no_argument, nullptr, 'J'},
27 {"gen-hash", no_argument, nullptr, 'H'},
28 {"build-target", required_argument, nullptr, 'p'},
29 {"module-name", required_argument, nullptr, 'N'},
30 {"kernel", no_argument, nullptr, 'K'},
31 {"dump-ast", no_argument, nullptr, 'D'},
32 {nullptr, 0, nullptr, 0}
33 };
34
GetInstance()35 Options& Options::GetInstance()
36 {
37 static Options option;
38 return option;
39 }
40
Parse(int argc,char * argv[])41 Options& Options::Parse(int argc, char *argv[])
42 {
43 program_ = argv[0];
44 opterr = 1;
45 int op = 0;
46 int optIndex = 0;
47
48 while ((op = getopt_long(argc, argv, optSupportArgs, g_longOpts, &optIndex)) != OPT_END) {
49 SetOptionData(op);
50 }
51 CheckOptions();
52
53 return *this;
54 }
55
SetOptionData(char op)56 void Options::SetOptionData(char op)
57 {
58 switch (op) {
59 case 'c':
60 doCompile_ = true;
61 sourceFiles_.push_back(optarg);
62 break;
63 case 'd':
64 doOutDir_ = true;
65 generationDirectory_ = optarg;
66 break;
67 case 'h':
68 doShowUsage_ = true;
69 break;
70 case 'v':
71 doShowVersion_ = true;
72 break;
73 case 'r':
74 AddPackagePath(optarg);
75 break;
76 case 'K':
77 doModeKernel_ = true;
78 break;
79 case 'N':
80 doSetModuleName_ = true;
81 moduleName_ = optarg;
82 break;
83 case 'C':
84 SetLanguage("c");
85 break;
86 case 'P':
87 SetLanguage("cpp");
88 break;
89 case 'J':
90 SetLanguage("java");
91 break;
92 case 'p':
93 SetCodePart(optarg);
94 break;
95 case 'H':
96 doGetHashKey_ = true;
97 break;
98 case 'D':
99 doDumpAST_ = true;
100 break;
101 case '?':
102 default:
103 doShowUsage_ = true;
104 break;
105 }
106 }
107
AddPackagePath(const String & packagePath)108 void Options::AddPackagePath(const String& packagePath)
109 {
110 int index = packagePath.IndexOf(":");
111 if (index == -1 || index == packagePath.GetLength() - 1) {
112 errors_.push_back(String::Format("%s: invalid option parameters '%s'.", program_.string(),
113 packagePath.string()));
114 return;
115 }
116
117 String package = packagePath.Substring(0, index);
118 String path = packagePath.Substring(index + 1);
119
120 auto it = packagePath_.find(package);
121 if (it != packagePath_.end()) {
122 errors_.push_back(String::Format("%s: The '%s:%s' has been set.", program_.string()));
123 }
124
125 packagePath_[package] = path;
126 }
127
SetLanguage(const String & language)128 void Options::SetLanguage(const String& language)
129 {
130 doGenerateCode_ = true;
131 targetLanguage_ = language;
132 }
133
SetCodePart(const String & part)134 void Options::SetCodePart(const String& part)
135 {
136 // The default parameter is 'all', and the optional parameters is 'client' or 'server'
137 doGeneratePart_ = true;
138 codePart_ = part;
139 }
140
CheckOptions()141 void Options::CheckOptions()
142 {
143 if (doShowUsage_ || doShowVersion_) {
144 return;
145 }
146
147 if (doCompile_) {
148 if (!doGetHashKey_ && !doDumpAST_ && !doGenerateCode_ && !doOutDir_) {
149 errors_.push_back(String::Format("%s: nothing to do.", program_.string()));
150 return;
151 }
152
153 if (!doGenerateCode_ && doOutDir_) {
154 errors_.push_back(String::Format("%s: no target language.", program_.string()));
155 return;
156 }
157
158 if (doGenerateCode_ && !doOutDir_) {
159 errors_.push_back(String::Format("%s: no out directory.", program_.string()));
160 return;
161 }
162
163 if (doGeneratePart_ && !codePart_.Equals("all") && !codePart_.Equals("client") &&
164 !codePart_.Equals("server")) {
165 String errorLog = "The '--build-target' option parameter must be 'client' 'server' or 'all'.";
166 errors_.push_back(String::Format("%s: %s", program_.string(), errorLog.string()));
167 }
168 } else {
169 if (doGetHashKey_ || doDumpAST_ || doGenerateCode_ || doOutDir_) {
170 errors_.push_back(String::Format("%s: no '-c' option.", program_.string()));
171 return;
172 }
173 }
174 }
175
ShowErrors() const176 void Options::ShowErrors() const
177 {
178 for (auto error : errors_) {
179 printf("%s\n", error.string());
180 }
181 printf("Use \"--help\" to show usage.\n");
182 }
183
ShowVersion() const184 void Options::ShowVersion() const
185 {
186 printf("HDI-GEN: %d.%d\n"
187 "Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.\n\n",
188 VERSION_MAJOR, VERSION_MINOR);
189 }
190
ShowUsage() const191 void Options::ShowUsage() const
192 {
193 printf("Compile a .idl file and generate C/C++ and Java codes.\n"
194 "Usage: idl [options] file\n"
195 "Options:\n"
196 " --help Display command line options\n"
197 " --version Display toolchain version information\n"
198 " --dump-ast Display the AST of the compiled file\n"
199 " -r <rootPackage>:<rootPath> set root path of root package\n"
200 " -c <*.idl> Compile the .idl file\n"
201 " --gen-hash Generate hash key of the idl file\n"
202 " --gen-c Generate C code\n"
203 " --gen-cpp Generate C++ code\n"
204 " --gen-java Generate Java code\n"
205 " --kernel Generate kernel-mode ioservice stub code," \
206 "default user-mode ioservice stub code\n"
207 " --module-name <module name> Set driver module name\n"
208 " --build-target <target name> Generate client code, server code or all code\n"
209 " -d <directory> Place generated codes into <directory>\n");
210 }
211
212 /*
213 * For Example
214 * -r option: -r OHOS.Hdi:drivers/interface
215 * package:OHOS.Hdi.foo.v1_0
216 * rootPackage:OHOS.Hdi
217 */
GetRootPackage(const String & package)218 String Options::GetRootPackage(const String& package)
219 {
220 const auto& packagePaths = GetPackagePath();
221 for (const auto& packageRoot : packagePaths) {
222 if (package.StartsWith(packageRoot.first)) {
223 return packageRoot.first;
224 }
225 }
226
227 return String("");
228 }
229
230 /*
231 * For Example
232 * -r option: -r OHOS.Hdi:drivers/interface
233 * package:OHOS.Hdi.foo.v1_0
234 * subPackage:foo.v1_0
235 */
GetSubPackage(const String & package)236 String Options::GetSubPackage(const String& package)
237 {
238 String rootPackage = GetRootPackage(package);
239 if (rootPackage.IsEmpty()) {
240 return package;
241 }
242
243 return package.Substring(rootPackage.GetLength() + 1);
244 }
245
246 /*
247 * For Example
248 * -r option: -r OHOS.Hdi:drivers/interface
249 * package:OHOS.Hdi.foo.v1_0
250 * packagePath:drivers/interface/foo/v1_0
251 */
GetPackagePath(const String & package)252 String Options::GetPackagePath(const String& package)
253 {
254 String rootPackage = "";
255 String rootPath = "";
256 const auto& packagePaths = GetPackagePath();
257 for (const auto& packageRoot : packagePaths) {
258 if (package.StartsWith(packageRoot.first)) {
259 rootPackage = packageRoot.first;
260 rootPath = packageRoot.second;
261 }
262 }
263
264 if (rootPackage.IsEmpty()) {
265 return package.Replace('.', File::pathSeparator);
266 }
267
268 if (rootPath.EndsWith(File::pathSeparator)) {
269 rootPath = rootPath.Substring(0, rootPath.GetLength() - 1);
270 }
271
272 return package.Replace(rootPackage, rootPath).Replace('.', File::pathSeparator);
273 }
274 } // namespace HDI
275 } // namespace OHOS