* Copyright (c) 2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstring>
#include <getopt.h>
#include <iomanip>
#include <iostream>
#include "file.h"
#include "logger.h"
#include "option.h"
using namespace OHOS::Hardware;
static constexpr int HCS_COMPILER_VERSION_MAJOR = 00;
static constexpr int HCS_COMPILER_VERSION_MINOR = 7;
static constexpr int ARG_COUNT_MIN = 2;
static constexpr int SPACE_WIDTH = 12;
Option &Option::Instance()
{
static Option option;
return option;
}
static constexpr int OPTION_END = -1;
static constexpr const char *HCS_SUPPORT_ARGS = "o:ap:bditmvVhs";
Option &Option::Parse(int argc, char **argv)
{
do {
if (argc < ARG_COUNT_MIN) {
showUsage_ = true;
break;
}
if (!ParseOptions(argc, argv)) {
break;
}
if (optind >= argc || optind < 0) {
Logger().Error() << "Miss input file name";
SetOptionError();
break;
}
SetSourceOption(argv[optind]);
return *this;
} while (false);
return *this;
}
bool Option::ParseOptions(int argc, char **argv)
{
int32_t op = 0;
while (op != OPTION_END) {
op = getopt(argc, argv, HCS_SUPPORT_ARGS);
SetOptionData(op);
if (ShouldShowUsage() || ShouldShowVersion()) {
return false;
}
}
return true;
}
void Option::SetOptionData(char op)
{
switch (op) {
case 'o':
outputName_ = optarg;
break;
case 'a':
shouldAlign_ = true;
break;
case 'b':
shouldGenByteCodeConfig_ = true;
break;
case 't':
shouldGenTextConfig_ = true;
shouldGenByteCodeConfig_ = false;
shouldGenMacroConfig_ = false;
break;
case 'm':
shouldGenTextConfig_ = false;
shouldGenByteCodeConfig_ = false;
shouldGenMacroConfig_ = true;
break;
case 'p':
symbolNamePrefix_ = optarg;
break;
case 'i':
showGenHexDump_ = true;
break;
case 'V':
verboseLog_ = true;
break;
case 'd':
shouldDecompile_ = true;
break;
case 'v':
showVersion_ = true;
break;
case 'h':
showUsage_ = true;
break;
case 's':
genStartCfg_ = true;
shouldGenByteCodeConfig_ = false;
break;
case '?':
SetOptionError();
break;
default:
break;
}
}
void Option::ShowUsage()
{
Logger() << "Usage: hc-gen [Options] [File]\n"
<< "options:";
ShowOption("-o <file>", "output file name, default same as input");
ShowOption("-a", "hcb align with four bytes");
ShowOption("-b", "output binary output, default enable");
ShowOption("-t", "output config in C language source file style");
ShowOption("-m", "output config in macro file style");
ShowOption("-s", "output start config of host");
ShowOption("-i", "output binary hex dump in C language source file style");
ShowOption("-p <prefix>", "prefix of generated symbol name");
ShowOption("-d", "decompile hcb to hcs");
ShowOption("-V", "show verbose info");
ShowOption("-v", "show version");
ShowOption("-h", "show this help message");
}
void Option::ShowOption(const ::std::string &option, const ::std::string &helpInfo)
{
Logger() << " " << ::std::setw(SPACE_WIDTH) << ::std::left << option << " " << helpInfo;
}
bool Option::ShouldShowUsage() const
{
return showUsage_;
}
void Option::ShowVersion()
{
Logger() << "Hcs compiler " << HCS_COMPILER_VERSION_MAJOR << "." << HCS_COMPILER_VERSION_MINOR;
Logger() << "Copyright (c) 2020-2021 Huawei Device Co., Ltd.";
}
bool Option::OptionError() const
{
return optionError_;
}
bool Option::ShouldShowVersion() const
{
return showVersion_;
}
bool Option::ShouldAlign() const
{
return shouldAlign_;
}
bool Option::ShouldGenTextConfig() const
{
return shouldGenTextConfig_;
}
bool Option::ShouldGenMacroConfig() const
{
return shouldGenMacroConfig_;
}
bool Option::ShouldGenBinaryConfig() const
{
return shouldGenByteCodeConfig_;
}
bool Option::ShouldGenHexDump() const
{
return showGenHexDump_;
}
bool Option::ShouldDecompile() const
{
return shouldDecompile_;
}
bool Option::ShouldGenStartConfig() const
{
return genStartCfg_;
}
std::string Option::GetSymbolPrefix() const
{
return symbolNamePrefix_;
}
bool Option::VerboseLog() const
{
return verboseLog_;
}
void Option::SetOptionError(bool shouldShowUsage)
{
showUsage_ = shouldShowUsage;
optionError_ = true;
}
std::string Option::GetSourceName() const
{
return sourceName_;
}
std::string Option::GetSourceNameBase() const
{
return sourceNameBase_;
}
std::string Option::GetOutputName() const
{
return outputName_;
}
bool Option::SetSourceOption(const char *srcName)
{
std::string srcAbsPath(Util::File::AbsPath(srcName));
if (srcAbsPath.empty()) {
Logger().Error() << "invalid source file: " << srcName << ", " << strerror(errno);
SetOptionError(false);
return false;
}
sourceName_ = srcAbsPath;
sourceNameBase_ = Util::File::FileNameBase(srcAbsPath);
return true;
}
void Option::GetVersion(uint32_t &minor, uint32_t &major)
{
minor = HCS_COMPILER_VERSION_MINOR;
major = HCS_COMPILER_VERSION_MAJOR;
}