* Copyright (c) 2021 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "util/options.h"
#include <cstdio>
#include <cstring>
#include <dirent.h>
#include <getopt.h>
#include <sys/stat.h>
#include <unistd.h>
#include "util/file.h"
namespace OHOS {
namespace HDI {
const char *Options::optSupportArgs = "c:d:r:";
static struct option g_longOpts[] = {
{"help", no_argument, nullptr, 'h'},
{"version", no_argument, nullptr, 'v'},
{"gen-c", no_argument, nullptr, 'C'},
{"gen-cpp", no_argument, nullptr, 'P'},
{"gen-java", no_argument, nullptr, 'J'},
{"gen-hash", no_argument, nullptr, 'H'},
{"build-target", required_argument, nullptr, 'p'},
{"module-name", required_argument, nullptr, 'N'},
{"kernel", no_argument, nullptr, 'K'},
{"dump-ast", no_argument, nullptr, 'D'},
{nullptr, 0, nullptr, 0 }
};
Options &Options::GetInstance()
{
static Options option;
return option;
}
Options &Options::Parse(int argc, char *argv[])
{
program_ = argv[0];
opterr = 1;
int op = 0;
int optIndex = 0;
while ((op = getopt_long(argc, argv, optSupportArgs, g_longOpts, &optIndex)) != OPT_END) {
SetOptionData(op);
}
CheckOptions();
return *this;
}
void Options::SetOptionData(char op)
{
switch (op) {
case 'c':
doCompile_ = true;
sourceFiles_.push_back(optarg);
break;
case 'd':
doOutDir_ = true;
generationDirectory_ = optarg;
break;
case 'h':
doShowUsage_ = true;
break;
case 'v':
doShowVersion_ = true;
break;
case 'r':
AddPackagePath(optarg);
break;
case 'K':
doModeKernel_ = true;
break;
case 'N':
doSetModuleName_ = true;
moduleName_ = optarg;
break;
case 'C':
SetLanguage("c");
break;
case 'P':
SetLanguage("cpp");
break;
case 'J':
SetLanguage("java");
break;
case 'p':
SetCodePart(optarg);
break;
case 'H':
doGetHashKey_ = true;
break;
case 'D':
doDumpAST_ = true;
break;
case '?':
default:
doShowUsage_ = true;
break;
}
}
void Options::AddPackagePath(const String &packagePath)
{
int index = packagePath.IndexOf(":");
if (index == -1 || index == packagePath.GetLength() - 1) {
errors_.push_back(
String::Format("%s: invalid option parameters '%s'.", program_.string(), packagePath.string()));
return;
}
String package = packagePath.Substring(0, index);
String path = File::RealPath(packagePath.Substring(index + 1));
if (path.IsEmpty() || path.IsNull()) {
errors_.push_back(
String::Format("%s: invalid path '%s'.", program_.string(), packagePath.Substring(index + 1).string()));
return;
}
auto it = packagePath_.find(package);
if (it != packagePath_.end()) {
errors_.push_back(
String::Format("%s: The '%s:%s' has been set.", program_.string(), package.string(), path.string()));
}
packagePath_[package] = path;
}
void Options::SetLanguage(const String &language)
{
doGenerateCode_ = true;
targetLanguage_ = language;
}
void Options::SetCodePart(const String &part)
{
doGeneratePart_ = true;
codePart_ = part;
}
void Options::CheckOptions()
{
if (doShowUsage_ || doShowVersion_) {
return;
}
if (doCompile_) {
if (!doGetHashKey_ && !doDumpAST_ && !doGenerateCode_ && !doOutDir_) {
errors_.push_back(String::Format("%s: nothing to do.", program_.string()));
return;
}
if (!doGenerateCode_ && doOutDir_) {
errors_.push_back(String::Format("%s: no target language.", program_.string()));
return;
}
if (doGenerateCode_ && !doOutDir_) {
errors_.push_back(String::Format("%s: no out directory.", program_.string()));
return;
}
if (doGeneratePart_ && !codePart_.Equals("all") && !codePart_.Equals("client") && !codePart_.Equals("server")) {
String errorLog = "The '--build-target' option parameter must be 'client' 'server' or 'all'.";
errors_.push_back(String::Format("%s: %s", program_.string(), errorLog.string()));
}
} else {
if (doGetHashKey_ || doDumpAST_ || doGenerateCode_ || doOutDir_) {
errors_.push_back(String::Format("%s: no '-c' option.", program_.string()));
return;
}
}
}
void Options::ShowErrors() const
{
for (auto error : errors_) {
printf("%s\n", error.string());
}
printf("Use \"--help\" to show usage.\n");
}
void Options::ShowVersion() const
{
printf("HDI-GEN: %d.%d\n"
"Copyright (c) Huawei Technologies Co., Ltd. 2021-2021. All rights reserved.\n\n",
VERSION_MAJOR, VERSION_MINOR);
}
void Options::ShowUsage() const
{
printf("Compile a .idl file and generate C/C++ and Java codes.\n"
"Usage: idl [options] file\n"
"Options:\n"
" --help Display command line options\n"
" --version Display toolchain version information\n"
" --dump-ast Display the AST of the compiled file\n"
" -r <rootPackage>:<rootPath> set root path of root package\n"
" -c <*.idl> Compile the .idl file\n"
" --gen-hash Generate hash key of the idl file\n"
" --gen-c Generate C code\n"
" --gen-cpp Generate C++ code\n"
" --gen-java Generate Java code\n"
" --kernel Generate kernel-mode ioservice stub code,"
"default user-mode ioservice stub code\n"
" --module-name <module name> Set driver module name\n"
" --build-target <target name> Generate client code, server code or all code\n"
" -d <directory> Place generated codes into <directory>\n");
}
* For Example
* -r option: -r ohos.hdi:./drivers/interface
* package:ohos.hdi.foo.v1_0
* rootPackage:ohos.hdi
*/
String Options::GetRootPackage(const String &package)
{
const auto &packagePaths = GetPackagePathMap();
for (const auto &packageRoot : packagePaths) {
if (package.StartsWith(packageRoot.first)) {
return packageRoot.first;
}
}
return "";
}
* For Example
* -r option: -r ohos.hdi:./drivers/interface
* package:ohos.hdi.foo.v1_0
* rootPath:./drivers/interface
*/
String Options::GetRootPath(const String &package)
{
const auto &packagePaths = GetPackagePathMap();
for (const auto &packageRoot : packagePaths) {
if (package.StartsWith(packageRoot.first)) {
return packageRoot.second;
}
}
return "";
}
* For Example
* -r option: -r ohos.hdi:./drivers/interface
* package:ohos.hdi.foo.v1_0
* subPackage:foo.v1_0
*/
String Options::GetSubPackage(const String &package)
{
String rootPackage = GetRootPackage(package);
if (rootPackage.IsEmpty()) {
return package;
}
return package.Substring(rootPackage.GetLength() + 1);
}
* For Example
* -r option: -r ohos.hdi:./drivers/interface
* package:ohos.hdi.foo.v1_0
* packagePath:./drivers/interface/foo/v1_0
*/
String Options::GetPackagePath(const String &package)
{
String rootPackage = "";
String rootPath = "";
const auto &packagePaths = GetPackagePathMap();
for (const auto &packageRoot : packagePaths) {
if (package.StartsWith(packageRoot.first)) {
rootPackage = packageRoot.first;
rootPath = packageRoot.second;
}
}
if (rootPackage.IsEmpty()) {
String curPath = File::AdapterPath(package.Replace('.', File::separator));
return File::RealPath(curPath);
}
if (rootPath.EndsWith(File::separator)) {
rootPath = rootPath.Substring(0, rootPath.GetLength() - 1);
}
String subPath = package.Substring(rootPackage.GetLength() + 1).Replace('.', File::separator);
return File::AdapterPath(rootPath + "/" + subPath);
}
* For Example
* -r option: -r ohos.hdi:./drivers/interface
* import: ohos.hdi.foo.v1_0.MyTypes
* packagePath:./drivers/interface/foo/v1_0/MyTypes.idl
*/
String Options::GetImportFilePath(const String &import)
{
int index = import.LastIndexOf('.');
if (index <= 0) {
return import;
}
String dir = GetPackagePath(import.Substring(0, index));
String ClassName = import.Substring(index + 1);
return String::Format("%s%c%s.idl", dir.string(), File::separator, ClassName.string());
}
}
}