• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 <map>
19 
20 #include "util/common.h"
21 #include "util/file.h"
22 #include "util/logger.h"
23 #include "util/string_helper.h"
24 
25 namespace OHOS {
26 namespace HDI {
27 const char *Options::optSupportArgs = "hvs:m:l:p:c:d:r:o:D:";
28 static struct option g_longOpts[] = {
29     {"help",         no_argument,       nullptr, 'h'},
30     {"version",      no_argument,       nullptr, 'v'},
31     {"system",       required_argument, nullptr, 's'},
32     {"mode",         required_argument, nullptr, 'm'},
33     {"language",     required_argument, nullptr, 'l'},
34     {"package",      required_argument, nullptr, 'p'},
35     {"dump-ast",     no_argument,       nullptr, 'a'},
36     {"hash",         no_argument,       nullptr, 'H'},
37     {nullptr,        0,                 nullptr, 0  }
38 };
39 
GetInstance()40 Options &Options::GetInstance()
41 {
42     static Options option;
43     return option;
44 }
45 
Parse(int argc,char * argv[])46 bool Options::Parse(int argc, char *argv[])
47 {
48     int ret = true;
49     program = argv[0];
50     opterr = 1;
51     int op = 0;
52     int optIndex = 0;
53     while ((op = getopt_long(argc, argv, optSupportArgs, g_longOpts, &optIndex)) != OPT_END) {
54         switch (op) {
55             case 'v':
56                 doShowVersion = true;
57                 break;
58             case 's':
59                 ret = SetSystemLevel(optarg);
60                 break;
61             case 'm':
62                 ret = SetGenerateMode(optarg);
63                 break;
64             case 'l':
65                 SetLanguage(optarg);
66                 break;
67             case 'p':
68                 SetPackage(optarg);
69                 break;
70             case 'a':
71                 doDumpAST = true;
72                 break;
73             case 'H':
74                 doHashKey = true;
75                 break;
76             case 'c':
77                 AddSources(optarg);
78                 break;
79             case 'D':
80                 AddSourcesByDir(optarg);
81                 break;
82             case 'd':
83                 SetOutDir(optarg);
84                 break;
85             case 'r':
86                 ret = AddPackagePath(optarg);
87                 break;
88             case 'o':
89                 outPutFile = optarg;
90                 break;
91             default:
92                 doShowUsage = true;
93                 break;
94         }
95     }
96     return ret ? CheckOptions() : ret;
97 }
98 
SetSystemLevel(const std::string & system)99 bool Options::SetSystemLevel(const std::string &system)
100 {
101     static std::map<std::string, SystemLevel> systemLevelMap = {
102         {"mini", SystemLevel::MINI},
103         {"lite", SystemLevel::LITE},
104         {"full", SystemLevel::FULL},
105     };
106 
107     auto levelIter = systemLevelMap.find(system);
108     if (levelIter == systemLevelMap.end()) {
109         Logger::E(TAG, "invalid system level set: '%s', please input mini/lite/full", system.c_str());
110         return false;
111     }
112     systemLevel = levelIter->second;
113     return true;
114 }
115 
SetGenerateMode(const std::string & mode)116 bool Options::SetGenerateMode(const std::string &mode)
117 {
118     static std::map<std::string, GenMode> codeGenMap = {
119         {"low", GenMode::LOW},
120         {"passthrough", GenMode::PASSTHROUGH},
121         {"ipc", GenMode::IPC},
122         {"kernel", GenMode::KERNEL},
123     };
124 
125     auto codeGenIter = codeGenMap.find(mode);
126     if (codeGenIter == codeGenMap.end()) {
127         Logger::E(TAG, "invalid generate mode set: '%s', please input low/passthrough/ipc/kernel.", mode.c_str());
128         return false;
129     }
130     genMode = codeGenIter->second;
131     return true;
132 }
133 
SetLanguage(const std::string & language)134 bool Options::SetLanguage(const std::string &language)
135 {
136     static const std::map<std::string, Language> languageMap = {
137         {"c", Language::C},
138         {"cpp", Language::CPP},
139         {"java", Language::JAVA},
140     };
141 
142     const auto kindIter = languageMap.find(language);
143     if (kindIter == languageMap.end()) {
144         Logger::E(TAG, "invalid language '%s', please input c, cpp or java", language.c_str());
145         return false;
146     }
147 
148     doGenerateCode = true;
149     genLanguage = kindIter->second;
150     return true;
151 }
152 
SetPackage(const std::string & infPackage)153 void Options::SetPackage(const std::string &infPackage)
154 {
155     idlPackage = infPackage;
156 }
157 
AddSources(const std::string & sourceFile)158 void Options::AddSources(const std::string &sourceFile)
159 {
160     std::string realPath = File::AdapterRealPath(sourceFile);
161     if (realPath.empty()) {
162         Logger::E(TAG, "invalid idl file path:%s", sourceFile.c_str());
163         return;
164     }
165 
166     if (sourceFiles.insert(realPath).second == false) {
167         Logger::E(TAG, "this idl file has been add:%s", sourceFile.c_str());
168         return;
169     }
170     doCompile = true;
171 }
172 
AddSourcesByDir(const std::string & dir)173 void Options::AddSourcesByDir(const std::string &dir)
174 {
175     std::set<std::string> files = File::FindFiles(dir);
176     if (!files.empty()) {
177         doCompile = true;
178         sourceFiles.insert(files.begin(), files.end());
179     }
180 }
181 
AddPackagePath(const std::string & packagePath)182 bool Options::AddPackagePath(const std::string &packagePath)
183 {
184     size_t index = packagePath.find(":");
185     if (index == std::string::npos || index == packagePath.size() - 1) {
186         Logger::E(TAG, "invalid option parameters '%s'.", packagePath.c_str());
187         return false;
188     }
189 
190     std::string package = packagePath.substr(0, index);
191     std::string path = File::AdapterRealPath(packagePath.substr(index + 1));
192     if (path.empty()) {
193         Logger::E(TAG, "invalid path '%s'.", packagePath.substr(index + 1).c_str());
194         return false;
195     }
196 
197     auto it = packagePathMap.find(package);
198     if (it != packagePathMap.end()) {
199         Logger::E(TAG, "The '%s:%s' has been set.", package.c_str(), path.c_str());
200         return false;
201     }
202 
203     packagePathMap[package] = path;
204     return true;
205 }
206 
SetOutDir(const std::string & dir)207 void Options::SetOutDir(const std::string &dir)
208 {
209     doOutDir = true;
210     genDir = dir;
211 }
212 
CheckOptions()213 bool Options::CheckOptions()
214 {
215     if (doShowUsage || doShowVersion) {
216         return true;
217     }
218 
219     if (doCompile) {
220         if (!DoGetHashKey() && !doDumpAST && !doGenerateCode && !doOutDir) {
221             Logger::E(TAG, "nothing to do.");
222             return false;
223         }
224 
225         if (!doGenerateCode && doOutDir) {
226             Logger::E(TAG, "no target language.");
227             return false;
228         }
229 
230         if (doGenerateCode && !doOutDir) {
231             Logger::E(TAG, "no out directory.");
232             return false;
233         }
234     } else {
235         if (DoGetHashKey() || doDumpAST || doGenerateCode || doOutDir) {
236             Logger::E(TAG, "no idl files.");
237             return false;
238         }
239     }
240     return true;
241 }
242 
ShowVersion() const243 void Options::ShowVersion() const
244 {
245     printf("HDI-GEN: %d.%d\n"
246            "Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.\n\n",
247         VERSION_MAJOR, VERSION_MINOR);
248 }
249 
ShowUsage() const250 void Options::ShowUsage() const
251 {
252     printf("Compile a .idl file and generate C/C++ and Java codes.\n"
253            "Usage: idl [options] file\n"
254            "Options:\n"
255            "  -h, --help                      Display command line options\n"
256            "  -v, --version                   Display toolchain version information\n"
257            "  -s, --system <value>            Set system level 'mini','lite' or 'full', the default value is 'full'\n"
258            "  -m, --mode <value>              Set generate code mode 'low', 'passthrough', 'ipc' or 'kernel',"
259            " the default value is 'ipc'\n"
260            "  -l, --language <value>          Set language of generate code 'c','cpp','java' or 'hash',"
261            " the default value is 'cpp'\n"
262            "  -p, --package <package name>    Set package of idl files\n"
263            "      --dump-ast                  Display the AST of the compiled file\n"
264            "      --hash                      Generate hash info of idl files\n"
265            "  -r <rootPackage>:<rootPath>     Set root path of root package\n"
266            "  -c <*.idl>                      Compile the .idl file\n"
267            "  -D <directory>                  Directory of the idl file\n"
268            "  -d <directory>                  Place generated codes into <directory>\n"
269            "  -o <file>                       Place the output into <file>\n");
270 }
271 
272 /*
273  * -r option: -r ohos.hdi:./drivers/interface
274  * package:ohos.hdi.foo.v1_0
275  * rootPackage:ohos.hdi
276  */
GetRootPackage(const std::string & package) const277 std::string Options::GetRootPackage(const std::string &package) const
278 {
279     const auto &packagePaths = GetPackagePathMap();
280     for (const auto &packageRoot : packagePaths) {
281         if (StringHelper::StartWith(package, packageRoot.first)) {
282             return packageRoot.first;
283         }
284     }
285 
286     return "";
287 }
288 
289 /*
290  * -r option: -r ohos.hdi:./drivers/interface
291  * package:ohos.hdi.foo.v1_0
292  * rootPath:./drivers/interface
293  */
GetRootPath(const std::string & package) const294 std::string Options::GetRootPath(const std::string &package) const
295 {
296     const auto &packagePaths = GetPackagePathMap();
297     for (const auto &packageRoot : packagePaths) {
298         if (StringHelper::StartWith(package, packageRoot.first)) {
299             return packageRoot.second;
300         }
301     }
302 
303     return "";
304 }
305 
306 /*
307  * -r option: -r ohos.hdi:./drivers/interface
308  * package:ohos.hdi.foo.v1_0
309  * subPackage:foo.v1_0
310  */
GetSubPackage(const std::string & package) const311 std::string Options::GetSubPackage(const std::string &package) const
312 {
313     std::string rootPackage = GetRootPackage(package);
314     if (rootPackage.empty()) {
315         return package;
316     }
317 
318     return package.substr(rootPackage.size() + 1);
319 }
320 
321 /*
322  * -r option: -r ohos.hdi:./drivers/interface
323  * package:ohos.hdi.foo.v1_0
324  * packagePath:./drivers/interface/foo/v1_0
325  */
GetPackagePath(const std::string & package) const326 std::string Options::GetPackagePath(const std::string &package) const
327 {
328     std::string rootPackage = "";
329     std::string rootPath = "";
330     const auto &packagePaths = GetPackagePathMap();
331     for (const auto &packageRoot : packagePaths) {
332         if (StringHelper::StartWith(package, packageRoot.first)) {
333             rootPackage = packageRoot.first;
334             rootPath = packageRoot.second;
335         }
336     }
337 
338     if (rootPackage.empty()) {
339         // The current path is the root path
340         std::string curPath = File::AdapterPath(StringHelper::Replace(package, '.', SEPARATOR));
341         return File::AdapterRealPath(curPath);
342     }
343 
344     if (StringHelper::EndWith(rootPath, SEPARATOR)) {
345         rootPath.pop_back();
346     }
347 
348     std::string subPath = StringHelper::Replace(package.substr(rootPackage.size() + 1), '.', SEPARATOR);
349     return File::AdapterPath(rootPath + "/" + subPath);
350 }
351 
352 /*
353  * -r option: -r ohos.hdi:./drivers/interface
354  * import: ohos.hdi.foo.v1_0.MyTypes
355  * packagePath:./drivers/interface/foo/v1_0/MyTypes.idl
356  */
GetImportFilePath(const std::string & import) const357 std::string Options::GetImportFilePath(const std::string &import) const
358 {
359     size_t index = import.rfind('.');
360     if (index == std::string::npos) {
361         return import;
362     }
363 
364     std::string dir = GetPackagePath(StringHelper::SubStr(import, 0, index));
365     std::string className = import.substr(index + 1);
366     return StringHelper::Format("%s%c%s.idl", dir.c_str(), SEPARATOR, className.c_str());
367 }
368 } // namespace HDI
369 } // namespace OHOS