// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include #include #include #include "tools/cddl/codegen.h" #include "tools/cddl/logging.h" #include "tools/cddl/parse.h" #include "tools/cddl/sema.h" std::string ReadEntireFile(const std::string& filename) { std::ifstream input(filename); if (!input) { return {}; } input.seekg(0, std::ios_base::end); size_t length = input.tellg(); std::string input_data(length + 1, 0); input.seekg(0, std::ios_base::beg); input.read(const_cast(input_data.data()), length); input_data[length] = 0; return input_data; } struct CommandLineArguments { std::string header_filename; std::string cc_filename; std::string gen_dir; std::string cddl_filename; }; CommandLineArguments ParseCommandLineArguments(int argc, char** argv) { --argc; ++argv; CommandLineArguments result; while (argc) { if (strcmp(*argv, "--header") == 0) { // Parse the filename of the output header file. This is also the name // that will be used for the include guard and as the include path in the // source file. if (!result.header_filename.empty()) { return {}; } if (!argc) { return {}; } --argc; ++argv; result.header_filename = *argv; } else if (strcmp(*argv, "--cc") == 0) { // Parse the filename of the output source file. if (!result.cc_filename.empty()) { return {}; } if (!argc) { return {}; } --argc; ++argv; result.cc_filename = *argv; } else if (strcmp(*argv, "--gen-dir") == 0) { // Parse the directory prefix that should be added to the output header. // and source file if (!result.gen_dir.empty()) { return {}; } if (!argc) { return {}; } --argc; ++argv; result.gen_dir = *argv; } else if (!result.cddl_filename.empty()) { return {}; } else { // The input file which contains the CDDL spec. result.cddl_filename = *argv; } --argc; ++argv; } // If one of the required properties is missed, return empty. Else, return // generated struct. if (result.header_filename.empty() || result.cc_filename.empty() || result.gen_dir.empty() || result.cddl_filename.empty()) { return {}; } return result; } int main(int argc, char** argv) { // Parse and validate all cmdline arguments. CommandLineArguments args = ParseCommandLineArguments(argc, argv); if (args.cddl_filename.empty()) { std::cerr << "Usage: " << std::endl << "cddl --header parsed.h --cc parsed.cc --gen-dir " "output/generated input.cddl" << std::endl << "All flags are required." << std::endl << "Example: " << std::endl << "./cddl --header osp_messages.h --cc osp_messages.cc " "--gen-dir gen/msgs ../../msgs/osp_messages.cddl" << std::endl; return 1; } size_t pos = args.cddl_filename.find_last_of('.'); if (pos == std::string::npos) { return 1; } // Validate and open the provided header file. std::string header_filename = args.gen_dir + "/" + args.header_filename; int header_fd = open(header_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if (header_fd == -1) { std::cerr << "failed to open " << args.header_filename << std::endl; return 1; } // Validate and open the provided output source file. std::string cc_filename = args.gen_dir + "/" + args.cc_filename; int cc_fd = open(cc_filename.c_str(), O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if (cc_fd == -1) { std::cerr << "failed to open " << args.cc_filename << std::endl; return 1; } // Read and parse the CDDL spec file. std::string data = ReadEntireFile(args.cddl_filename); if (data.empty()) { return 1; } Logger::Log("Successfully initialized CDDL Code generator!"); // Parse the full CDDL into a graph structure. Logger::Log("Parsing CDDL input file..."); ParseResult parse_result = ParseCddl(data); if (!parse_result.root) { Logger::Error("Failed to parse CDDL input file"); return 1; } Logger::Log("Successfully parsed CDDL input file!"); // Build the Symbol table from this graph structure. Logger::Log("Generating CDDL Symbol Table..."); std::pair cddl_result = BuildSymbolTable(*parse_result.root); if (!cddl_result.first) { Logger::Error("Failed to generate CDDL symbol table"); return 1; } Logger::Log("Successfully generated CDDL symbol table!"); Logger::Log("Generating CPP symbol table..."); std::pair cpp_result = BuildCppTypes(cddl_result.second); if (!cpp_result.first) { Logger::Error("Failed to generate CPP symbol table"); return 1; } Logger::Log("Successfully generated CPP symbol table!"); // Validate that the provided CDDL doesnt have duplicated indices. if (!ValidateCppTypes(cpp_result.second)) { return 1; } // Create the C++ files from the Symbol table. Logger::Log("Writing Header prologue..."); if (!WriteHeaderPrologue(header_fd, args.header_filename)) { Logger::Error("WriteHeaderPrologue failed"); return 1; } Logger::Log("Successfully wrote header prologue!"); Logger::Log("Writing type definitions..."); if (!WriteTypeDefinitions(header_fd, &cpp_result.second)) { Logger::Error("WriteTypeDefinitions failed"); return 1; } Logger::Log("Successfully wrote type definitions!"); Logger::Log("Writing function declaration..."); if (!WriteFunctionDeclarations(header_fd, &cpp_result.second)) { Logger::Error("WriteFunctionDeclarations failed"); return 1; } Logger::Log("Successfully wrote function declarations!"); Logger::Log("Writing header epilogue..."); if (!WriteHeaderEpilogue(header_fd, args.header_filename)) { Logger::Error("WriteHeaderEpilogue failed"); return 1; } Logger::Log("Successfully wrote header epilogue!"); Logger::Log("Writing source prologue..."); if (!WriteSourcePrologue(cc_fd, args.header_filename)) { Logger::Error("WriteSourcePrologue failed"); return 1; } Logger::Log("Successfully wrote source prologue!"); Logger::Log("Writing encoders..."); if (!WriteEncoders(cc_fd, &cpp_result.second)) { Logger::Error("WriteEncoders failed"); return 1; } Logger::Log("Successfully wrote encoders!"); Logger::Log("Writing decoders..."); if (!WriteDecoders(cc_fd, &cpp_result.second)) { Logger::Error("WriteDecoders failed"); return 1; } Logger::Log("Successfully wrote decoders!"); Logger::Log("Writing equality operators..."); if (!WriteEqualityOperators(cc_fd, &cpp_result.second)) { Logger::Error("WriteStructEqualityOperators failed"); return 1; } Logger::Log("Successfully wrote equality operators!"); Logger::Log("Writing source epilogue..."); if (!WriteSourceEpilogue(cc_fd)) { Logger::Error("WriteSourceEpilogue failed"); return 1; } Logger::Log("Successfully wrote source epilogue!"); close(header_fd); close(cc_fd); Logger::Log("SUCCESSFULLY COMPLETED ALL OPERATIONS"); return 0; }