* 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 <algorithm>
#include <string>
#include "file.h"
#include "logger.h"
#include "macro_gen.h"
using namespace OHOS::Hardware;
constexpr static const char *FILE_HEAD_COMMENT =
"/*\n"
" * This is an automatically generated HDF config file. Do not modify it manually.\n"
" */\n\n";
MacroGen::MacroGen(std::shared_ptr<Ast> ast) : Generator(ast) {}
const std::string &MacroGen::ToUpperString(std::string &str)
{
for (char &c : str) {
c = static_cast<char>(toupper(c));
}
return str;
}
bool MacroGen::HeaderTopOutput()
{
ofs_ << FILE_HEAD_COMMENT;
std::string defMacro = std::string().append("HCS_CONFIG_").append(ToUpperString(outFileName_)).append("_HEADER_H");
ofs_ << "#ifndef " << defMacro << '\n';
ofs_ << "#define " << defMacro << '\n';
ofs_ << "\r\n#include \"hdf_base.h\"\n";
return true;
}
bool MacroGen::HeaderBottomOutput()
{
std::string defMacro = std::string().append("HCS_CONFIG_").append(ToUpperString(outFileName_)).append("_HEADER_H");
ofs_ << "\n#endif // " << defMacro << '\n';
ofs_.close();
return true;
}
bool MacroGen::Output()
{
if (!Initialize()) {
return false;
}
if (!TemplateNodeSeparate()) {
return false;
}
if (!HeaderTopOutput()) {
return false;
}
if (!NodeWalk()) {
return false;
}
if (!HeaderBottomOutput()) {
return false;
}
return true;
}
bool MacroGen::Initialize()
{
std::string outFileName = Option::Instance().GetOutputName();
if (outFileName.empty()) {
outFileName = Option::Instance().GetSourceNameBase();
}
outFileName = Util::File::StripSuffix(outFileName).append(".h");
outFileName_ = Util::File::FileNameBase(outFileName);
if (outFileName.find(".h") == std::string::npos) {
outFileName.append(".h");
}
ofs_.open(outFileName, std::ofstream::out | std::ofstream::binary);
if (!ofs_.is_open()) {
Logger().Error() << "failed to open output file: " << outFileName;
return false;
}
Logger().Debug() << "output: " << outFileName << outFileName_ << '\n';
return true;
}
bool MacroGen::TemplateNodeSeparate()
{
return ast_->WalkBackward([this](std::shared_ptr<AstObject> &object, int32_t depth) {
(void)depth;
if (object->IsNode() && ConfigNode::CastFrom(object)->GetNodeType() == NODE_TEMPLATE) {
object->Separate();
return NOERR;
}
return NOERR;
});
}
std::string MacroGen::GenFullName(int32_t depth, const std::shared_ptr<AstObject> &node, const std::string &sep)
{
std::string name;
for (int i = 0; i < depth; i++) {
name.append(nodeNameMap_[i]).append(sep);
}
name.append(node->Name());
return name;
}
bool MacroGen::GenArray(
const std::string &arrName, uint32_t &arrSize, uint32_t type, const std::shared_ptr<AstObject> &node)
{
static uint32_t index = 0;
constexpr uint32_t elementPerLine = 8;
if (index == 0) {
ofs_ << "#define " << arrName << "_data {";
}
if (index % elementPerLine == 0) {
ofs_ << " \\\n" << TAB;
}
if (type == PARSEROP_STRING) {
ofs_ << '"' << node->StringValue() << '"';
} else {
ofs_ << node->IntegerValue();
}
index++;
if (index == arrSize) {
index = 0;
arrSize = 0;
ofs_ << " \\\n}\n";
} else {
if (index % elementPerLine == 0) {
ofs_ << ",";
} else {
ofs_ << ", ";
}
}
return true;
}
bool MacroGen::GenNodeForeach(int32_t depth, const std::shared_ptr<AstObject> &node)
{
std::list<std::string> subList;
auto child = node->Child();
uint32_t count = 0;
Logger().Debug() << "node:" << node->Name() << " child:"
<< " depth:" << depth;
while (child != nullptr) {
if (child->IsNode()) {
Logger().Debug() << " " << child->Name();
subList.push_back(GenFullName(depth + 1, child, "_"));
count++;
}
child = child->Next();
}
ofs_ << "// hcs node macros: " << GenFullName(depth, node, "/") << std::endl;
ofs_ << "#define " << GenFullName(depth, node, "_").append("_exists 1") << std::endl;
std::string fullName = GenFullName(depth, node, "_");
ofs_ << "#define " << fullName.append("_nodeName \"").append(node->Name()).append("\"") << std::endl;
if (count > 0) {
uint32_t index = 0;
std::list<std::string>::iterator iter;
ofs_ << "#define " << GenFullName(depth, node, "_").append("_foreach_child(func)") << " \\\n";
for (iter = subList.begin(); iter != subList.end(); ++iter) {
if (++index < count) {
ofs_ << TAB << "func(" << *iter << "); \\\n";
} else {
ofs_ << TAB << "func(" << *iter << ");\n";
}
}
ofs_ << std::endl;
index = 0;
ofs_ << "#define " << GenFullName(depth, node, "_").append("_foreach_child_vargs(func, ...)") << " \\\n";
for (iter = subList.begin(); iter != subList.end(); ++iter) {
if (++index < count) {
ofs_ << TAB << "func(" << *iter << ", __VA_ARGS__); \\\n";
} else {
ofs_ << TAB << "func(" << *iter << ", __VA_ARGS__);\n";
}
}
ofs_ << std::endl;
}
return true;
}
std::string MacroGen::GenRefObjName(int32_t depth, const std::shared_ptr<AstObject> &object)
{
std::string name(object->StringValue());
if (name.find(".") == std::string::npos) {
name = GenFullName(depth - 1, object, "_").append(object->StringValue());
} else {
std::replace(name.begin(), name.end(), '.', '_');
}
return name;
}
bool MacroGen::NodeWalk()
{
return ast_->WalkForward([this](std::shared_ptr<AstObject> ¤t, int32_t depth) {
auto type = current->Type();
static uint32_t arraySize = 0;
Logger().Debug() << "name,type:[" << current->Name() << "," << type << "] depth:" << depth
<< " arraySize:" << std::dec << arraySize << '\n';
SetTypeData(type, current, arraySize, depth);
return NOERR;
});
}
void MacroGen::SetTypeData(uint32_t type, const std::shared_ptr<AstObject> ¤t, uint32_t &arraySize, int32_t depth)
{
static std::string nodeName;
static std::string arrayName;
static uint32_t arrayType = 0;
switch (type) {
case PARSEROP_UINT8:
case PARSEROP_UINT16:
case PARSEROP_UINT32:
case PARSEROP_UINT64: {
SetTypeDataUinit64(arrayName, arraySize, arrayType, current);
break;
}
case PARSEROP_STRING:
if (arraySize != 0) {
GenArray(arrayName, arraySize, arrayType, current);
} else {
ofs_ << " " << '"' << current->StringValue() << '"' << std::endl;
}
break;
case PARSEROP_CONFTERM:
ofs_ << "#define " << GenFullName(depth, current, "_") << "_exists 1" << std::endl;
ofs_ << "#define " << GenFullName(depth, current, "_");
break;
case PARSEROP_CONFNODE: {
if (nodeName != current->Name()) {
ofs_ << std::endl;
}
nodeName = current->Name();
nodeNameMap_[depth] = nodeName;
GenNodeForeach(depth, current);
break;
}
case PARSEROP_ARRAY: {
std::shared_ptr<AstObject> parent(current->Parent());
arraySize = ConfigArray::CastFrom(current)->ArraySize();
arrayType = ConfigArray::CastFrom(current)->ArrayType();
ofs_ << "_array_size " << arraySize << std::endl;
arrayName = GenFullName(depth - 1, parent, "_");
break;
}
case PARSEROP_NODEREF: {
ofs_ << " " << GenRefObjName(depth, current) << std::endl;
break;
}
default:
break;
}
}
void MacroGen::SetTypeDataUinit64(
const std::string &arrayName, uint32_t &arraySize, uint32_t arrayType, const std::shared_ptr<AstObject> ¤t)
{
if (arraySize != 0) {
GenArray(arrayName, arraySize, arrayType, current);
} else {
ofs_ << " " << current->IntegerValue() << std::endl;
}
}