/** * @file * * @copyright * @verbatim Copyright @ 2017 Audi Electronics Venture GmbH. All rights reserved. This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. @endverbatim */ #include #include "header_printer.h" #include "header_header.h" #include "header_basic_type.h" namespace ddl_generator { namespace oo { //define all needed error types and values locally _MAKE_RESULT(0, ERR_NOERROR) _MAKE_RESULT(-4, ERR_POINTER) _MAKE_RESULT(-5, ERR_INVALID_ARG) _MAKE_RESULT(-11, ERR_INVALID_FILE) _MAKE_RESULT(-20, ERR_NOT_FOUND) _MAKE_RESULT(-24, ERR_PATH_NOT_FOUND) _MAKE_RESULT(-27, ERR_OPEN_FAILED) _MAKE_RESULT(-38, ERR_FAILED) } } using namespace ddl_generator::oo; using namespace ddl; namespace ddl { HeaderPrinter::HeaderPrinter() : _header(NULL) { } HeaderPrinter::~HeaderPrinter() { } a_util::result::Result HeaderPrinter::writeToFile(const a_util::filesystem::Path &filename) { std::string guarded_header_output = addHeaderGuards(filename, _header_output); if (a_util::filesystem::writeTextFile(filename, guarded_header_output) != a_util::filesystem::OK) { return (ERR_OPEN_FAILED); } return ERR_NOERROR; } const std::string& HeaderPrinter::getHeader() { return _header_output; } a_util::result::Result HeaderPrinter::visit(const Header* header) { _header = header; _header_output = ""; _header_output.append("// This is a generated file, changes to it may be overwritten in the future.\n\n"); if (_name_space.length() > 0) { _header_output.append(a_util::strings::format("namespace %s\n{\n", _name_space.c_str())); } HeaderTypedefs typedefs = header->getTypedefs(); for (HeaderTypedefs::iterator iter = typedefs.begin(); iter != typedefs.end(); iter++) { if (isFailed((appendType(*iter)))) { return ERR_FAILED; } } HeaderEnums enums = header->getEnums(); for (auto iter = enums.begin(); iter != enums.end(); iter++) { if (isFailed(((*iter)->accept(this)))) { return ERR_FAILED; } } HeaderStructs structs = header->getStructs(); for (HeaderStructs::iterator iter = structs.begin(); iter != structs.end(); iter++) { if (isFailed((appendType(*iter)))) { return ERR_FAILED; } } HeaderConstants constants = header->getConstants(); for (HeaderConstants::iterator iter = constants.begin(); iter != constants.end(); iter++) { if (isFailed(((*iter)->accept(this)))) { return ERR_FAILED; } } if (isFailed((printUnknownTypes()))) { return ERR_FAILED; } if (_name_space.length() > 0) { _header_output.append(a_util::strings::format("} // namespace %s\n", _name_space.c_str())); } return ERR_NOERROR; } a_util::result::Result HeaderPrinter::visit(const HeaderBasicType* basic_type) { CollectType(basic_type, true); _header_output.append("// The following type is assumed to be known:\n"); _header_output.append("// "); _header_output.append(basic_type->getName()); _header_output.append("\n\n"); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::visit(const HeaderTypedef* type_def) { printDescription(type_def); // Set known first, so no infinite loop will occur when looking for base type CollectType(type_def, true); appendType(type_def->getOriginalType()); _header_output.append(a_util::strings::format("typedef %s %s;\n\n", type_def->getOriginalType()->getName().c_str(), type_def->getName().c_str())); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::visit(const HeaderConstant* constant) { appendType(constant->getType()); _header_output.append("const "); _header_output.append(constant->getType()->getName()); _header_output.append(" "); _header_output.append(constant->getName()); _header_output.append(" = "); _header_output.append(constant->asString()); _header_output.append(";\n\n"); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::visit(const HeaderStruct* header_struct) { printDescription(header_struct); // Set known first, so no infinite loop will occur when looking for base type CollectType(header_struct, true); // Make sure all types are already defined HeaderStructElementVec elements = header_struct->getElements(); for (HeaderStructElementVec::iterator iter = elements.begin(); iter != elements.end(); iter++) { appendType((*iter)->getType()); } _header_output.append(a_util::strings::format("#pragma pack(push,%d)\n", header_struct->getPacking())); _header_output.append("typedef struct\n{\n"); for (HeaderStructElementVec::iterator iter = elements.begin(); iter != elements.end(); iter++) { if (isFailed(((*iter)->accept(this)))) { return ERR_FAILED; } } _header_output.append(a_util::strings::format("} %s;\n", header_struct->getName().c_str())); _header_output.append("#pragma pack(pop)\n\n"); CollectType(header_struct, true); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::visit(const HeaderStructElement* header_struct) { if (!header_struct || !header_struct->getType()) { return ERR_INVALID_ARG; } printDescription(header_struct->getDescription(), header_struct->getComment(), true); appendType(header_struct->getType()); _header_output.append(" "); if (header_struct->isStatic()) { _header_output.append("static "); } if (header_struct->isConst()) { _header_output.append("const "); } _header_output.append(header_struct->getType()->getName()); if (header_struct->isPointer()) { _header_output.append("* "); } _header_output.append(" "); _header_output.append(header_struct->getName()); if (header_struct->getArraySize() > 1) { _header_output.append(a_util::strings::format("[%d]", header_struct->getArraySize())); } _header_output.append(";\n"); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::visit(const HeaderEnum* header_enum) { CollectType(header_enum, true); printDescription(header_enum); _header_output.append("typedef enum {\n"); for (auto iter = header_enum->getValues().begin(); iter != header_enum->getValues().end(); iter++) { _header_output.append(a_util::strings::format(" %s=%i,\n", iter->second.c_str(), iter->first)); } if (header_enum->getValues().size() > 0) { // remove last ',' since some versions of C/C++ don't allow trailing commas in enums _header_output.resize(_header_output.length() - 2); } _header_output.append(a_util::strings::format("\n} %s;\n\n", header_enum->getName().c_str())); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::appendType(const HeaderType* type) { // See if we already know this type and therefore have printed it already for (HeaderConstTypes::iterator iter = _known_types.begin(); iter != _known_types.end(); iter++) { if (*iter == type) { return ERR_NOERROR; } } // Search the header for the type. if (_header != NULL) { for (HeaderTypedefs::const_iterator iter = _header->getTypedefs().begin(); iter != _header->getTypedefs().end(); iter++) { if (*iter == type) { // Found it, append it return ((*iter)->accept(this)); } } for (HeaderStructs::const_iterator iter = _header->getStructs().begin(); iter != _header->getStructs().end(); iter++) { if (*iter == type) { // Found it, append it return ((*iter)->accept(this)); } } } // Nothing found so far, so type is unknown CollectType(type, false); return (ERR_NOT_FOUND); } a_util::result::Result HeaderPrinter::CollectType(const ddl::HeaderType* type, bool is_known) { if (is_known) { if (std::find(_known_types.begin(), _known_types.end(), type) == _known_types.end()) { _known_types.push_back(type); } } else { if (std::find(_unknown_types.begin(), _unknown_types.end(), type) == _unknown_types.end()) { _unknown_types.push_back(type); } } return ERR_NOERROR; } a_util::result::Result HeaderPrinter::printUnknownTypes() { // visit all types that are in the unknown types set but not in the knowN types set HeaderConstTypes vec = _unknown_types; for (HeaderConstTypes::iterator iter = vec.begin(); iter != vec.end(); iter++) { if (std::find(_known_types.begin(), _known_types.end(), *iter) == _known_types.end()) { (*iter)->accept(this); } } if (vec.size() != _unknown_types.size()) { printUnknownTypes(); } return ERR_NOERROR; } a_util::result::Result HeaderPrinter::printDescription(const std::string& description, const std::string& comment, bool indent) { if (description.length() == 0 && comment.length() == 0) { return ERR_NOERROR; } std::string indent_string; if (indent) { indent_string = " "; } _header_output.append(indent_string); _header_output.append("/**\n"); if (description.length() > 0) { _header_output.append(a_util::strings::format("%s * %s\n", indent_string.c_str(), description.c_str())); } if (comment.length() > 0) { _header_output.append(a_util::strings::format("%s * %s\n", indent_string.c_str(), comment.c_str())); } _header_output.append(indent_string); _header_output.append("*/\n"); return ERR_NOERROR; } a_util::result::Result HeaderPrinter::printDescription(const HeaderType* type) { return printDescription(type->getDescription(), type->getComment()); } bool invalidHeaderChar(char c) { bool is_num = (c >= '0' && c <= '9'); bool is_uppercase_alpha = (c >= 'A' && c <= 'Z'); bool is_lowercase_alpha = (c >= 'a' && c <= 'z'); bool is_allowed_punctuation = (c == '.' || c == '_' || c == '-'); return !(is_num || is_uppercase_alpha || is_lowercase_alpha || is_allowed_punctuation); } std::string HeaderPrinter::addHeaderGuards(const a_util::filesystem::Path &filename, const std::string &unguarded_header_content) { std::string guard_name = filename.getLastElement().toString(); guard_name.erase(std::remove_if(guard_name.begin(), guard_name.end(), invalidHeaderChar), guard_name.end()); std::replace(guard_name.begin(), guard_name.end(), '.', '_'); std::transform(guard_name.begin(), guard_name.end(), guard_name.begin(), ::toupper); std::string output; output.append("#ifndef "); output.append(guard_name + "\n"); output.append("#define "); output.append(guard_name + "\n\n"); output.append(unguarded_header_content); output.append("\n#endif //"); output.append(guard_name + "\n"); return output; } void HeaderPrinter::SetNamespace(std::string name_space) { _name_space = name_space; } } // namespace ddl