• 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 "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