/** * * @file create_view.cc * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon * Use of this source code is governed by a MIT license * that can be found in the License file. * * Drogon * */ #include "create_view.h" #include "cmd.h" #include #include #include #include #include #include static const std::string cxx_include = "<%inc"; static const std::string cxx_end = "%>"; static const std::string cxx_lang = "<%c++"; static const std::string cxx_view_data = "@@"; static const std::string cxx_output = "$$"; static const std::string cxx_val_start = "[["; static const std::string cxx_val_end = "]]"; static const std::string sub_view_start = "<%view"; static const std::string sub_view_end = "%>"; using namespace drogon_ctl; static std::string &replace_all(std::string &str, const std::string &old_value, const std::string &new_value) { std::string::size_type pos(0); while (true) { // std::cout<(&val));\n"; oSrcFile << " }else " "if(val.type()==typeid(std::string)||val.type()==typeid(const " "std::string)){\n"; oSrcFile << " " << streamName << "<<*(std::any_cast(&val));\n"; oSrcFile << " }\n"; oSrcFile << "}\n"; } static void outputSubView(std::ofstream &oSrcFile, const std::string &streamName, const std::string &viewDataName, const std::string &keyName) { oSrcFile << "{\n"; oSrcFile << " auto templ=DrTemplateBase::newTemplate(\"" << keyName << "\");\n"; oSrcFile << " if(templ){\n"; oSrcFile << " " << streamName << "<< templ->genText(" << viewDataName << ");\n"; oSrcFile << " }\n"; oSrcFile << "}\n"; } static void parseLine(std::ofstream &oSrcFile, std::string &line, const std::string &streamName, const std::string &viewDataName, int &cxx_flag, int returnFlag = 1) { std::string::size_type pos(0); // std::cout< 0 && line[line.length() - 1] == '\r') { line.resize(line.length() - 1); } if (line.length() == 0) { // std::cout<<"blank line!"< 0) parseLine( oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0); std::string newLine = line.substr(pos + cxx_lang.length()); cxx_flag = 1; if (newLine.length() > 0) parseLine(oSrcFile, newLine, streamName, viewDataName, cxx_flag, returnFlag); } else { if ((pos = line.find(cxx_val_start)) != std::string::npos) { std::string oldLine = line.substr(0, pos); parseLine( oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0); std::string newLine = line.substr(pos + cxx_val_start.length()); if ((pos = newLine.find(cxx_val_end)) != std::string::npos) { std::string keyName = newLine.substr(0, pos); auto iter = keyName.begin(); while (iter != keyName.end() && *iter == ' ') ++iter; auto iterEnd = iter; while (iterEnd != keyName.end() && *iterEnd != ' ') ++iterEnd; keyName = std::string(iter, iterEnd); outputVal(oSrcFile, streamName, viewDataName, keyName); std::string tailLine = newLine.substr(pos + cxx_val_end.length()); parseLine(oSrcFile, tailLine, streamName, viewDataName, cxx_flag, returnFlag); } else { std::cerr << "format err!" << std::endl; exit(1); } } else if ((pos = line.find(sub_view_start)) != std::string::npos) { std::string oldLine = line.substr(0, pos); parseLine( oSrcFile, oldLine, streamName, viewDataName, cxx_flag, 0); std::string newLine = line.substr(pos + sub_view_start.length()); if ((pos = newLine.find(sub_view_end)) != std::string::npos) { std::string keyName = newLine.substr(0, pos); auto iter = keyName.begin(); while (iter != keyName.end() && *iter == ' ') ++iter; auto iterEnd = iter; while (iterEnd != keyName.end() && *iterEnd != ' ') ++iterEnd; keyName = std::string(iter, iterEnd); outputSubView(oSrcFile, streamName, viewDataName, keyName); std::string tailLine = newLine.substr(pos + sub_view_end.length()); parseLine(oSrcFile, tailLine, streamName, viewDataName, cxx_flag, returnFlag); } else { std::cerr << "format err!" << std::endl; exit(1); } } else { if (line.length() > 0) { replace_all(line, "\\", "\\\\"); replace_all(line, "\"", "\\\""); oSrcFile << "\t" << streamName << " << \"" << line; } if (returnFlag) oSrcFile << "\\n\";\n"; else oSrcFile << "\";\n"; } } } else { if ((pos = line.find(cxx_end)) != std::string::npos) { std::string newLine = line.substr(0, pos); parseCxxLine(oSrcFile, newLine, streamName, viewDataName); std::string oldLine = line.substr(pos + cxx_end.length()); cxx_flag = 0; if (oldLine.length() > 0) parseLine(oSrcFile, oldLine, streamName, viewDataName, cxx_flag, returnFlag); } else { parseCxxLine(oSrcFile, line, streamName, viewDataName); } } } void create_view::handleCommand(std::vector ¶meters) { for (auto iter = parameters.begin(); iter != parameters.end();) { auto &file = *iter; if (file == "-o" || file == "--output") { iter = parameters.erase(iter); if (iter != parameters.end()) { outputPath_ = *iter; iter = parameters.erase(iter); } continue; } else if (file == "-n" || file == "--namespace") { iter = parameters.erase(iter); if (iter != parameters.end()) { namespaces_ = utils::splitString(*iter, "::"); iter = parameters.erase(iter); } continue; } else if (file == "--path-to-namespace") { iter = parameters.erase(iter); pathToNamespaceFlag_ = true; continue; } else if (file[0] == '-') { std::cout << ARGS_ERROR_STR << std::endl; return; } ++iter; } createViewFiles(parameters); } void create_view::createViewFiles(std::vector &cspFileNames) { for (auto const &file : cspFileNames) { std::cout << "create view:" << file << std::endl; if (createViewFile(file) != 0) exit(1); } } int create_view::createViewFile(const std::string &script_filename) { std::cout << "create HttpView Class file by " << script_filename << std::endl; if (pathToNamespaceFlag_) { std::string::size_type pos1 = 0, pos2 = 0; if (script_filename.length() >= 2 && script_filename[0] == '.' && (script_filename[1] == '/' || script_filename[1] == '\\')) { pos1 = pos2 = 2; } else if (script_filename.length() >= 1 && (script_filename[0] == '/' || script_filename[0] == '\\')) { pos1 = pos2 = 1; } while (pos2 < script_filename.length() - 1) { if (script_filename[pos2] == '/' || script_filename[pos2] == '\\') { if (pos2 > pos1) { namespaces_.push_back( script_filename.substr(pos1, pos2 - pos1)); } pos1 = ++pos2; } else { ++pos2; } } } std::string npPrefix; for (auto &np : namespaces_) { npPrefix += np; npPrefix += "_"; } std::ifstream infile(script_filename.c_str(), std::ifstream::in); if (infile) { std::string::size_type pos = script_filename.rfind('.'); if (pos != std::string::npos) { std::string className = script_filename.substr(0, pos); if ((pos = className.rfind('/')) != std::string::npos) { className = className.substr(pos + 1); } std::cout << "className=" << className << std::endl; std::string headFileName = outputPath_ + "/" + npPrefix + className + ".h"; std::string sourceFilename = outputPath_ + "/" + npPrefix + className + ".cc"; std::ofstream oHeadFile(headFileName.c_str(), std::ofstream::out); std::ofstream oSourceFile(sourceFilename.c_str(), std::ofstream::out); if (!oHeadFile || !oSourceFile) { std::cerr << "Can't open " << headFileName << " or " << sourceFilename << "\n"; return -1; } newViewHeaderFile(oHeadFile, className); newViewSourceFile(oSourceFile, className, npPrefix, infile); } else return -1; } else { std::cerr << "can't open file " << script_filename << std::endl; return -1; } return 0; } void create_view::newViewHeaderFile(std::ofstream &file, const std::string &className) { file << "//this file is generated by program automatically,don't modify " "it!\n"; file << "#include \n"; for (auto &np : namespaces_) { file << "namespace " << np << "\n"; file << "{\n"; } file << "class " << className << ":public drogon::DrTemplate<" << className << ">\n"; file << "{\npublic:\n\t" << className << "(){};\n\tvirtual ~" << className << "(){};\n\t" "virtual std::string genText(const drogon::DrTemplateData &) " "override;\n};\n"; for (std::size_t i = 0; i < namespaces_.size(); ++i) { file << "}\n"; } } void create_view::newViewSourceFile(std::ofstream &file, const std::string &className, const std::string &namespacePrefix, std::ifstream &infile) { file << "//this file is generated by program(drogon_ctl) " "automatically,don't modify it!\n"; file << "#include \"" << namespacePrefix << className << ".h\"\n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; file << "#include \n"; // Find layout tag std::string layoutName; std::regex layoutReg("<%layout[ \\t]+(((?!%\\}).)*[^ \\t])[ \\t]*%>"); for (std::string buffer; std::getline(infile, buffer);) { std::smatch results; if (std::regex_search(buffer, results, layoutReg)) { if (results.size() > 1) { layoutName = results[1].str(); break; } } } infile.clear(); infile.seekg(0, std::ifstream::beg); bool import_flag{false}; for (std::string buffer; std::getline(infile, buffer);) { std::string::size_type pos(0); if (!import_flag) { std::string lowerBuffer = buffer; std::transform(lowerBuffer.begin(), lowerBuffer.end(), lowerBuffer.begin(), [](unsigned char c) { return tolower(c); }); if ((pos = lowerBuffer.find(cxx_include)) != std::string::npos) { // std::cout<<"haha find it!"< 0) { std::smatch results; if (std::regex_search(buffer, results, layoutReg)) { if (results.size() > 1) { continue; } } std::regex re("\\{%[ \\t]*(((?!%\\}).)*[^ \\t])[ \\t]*%\\}"); buffer = std::regex_replace(buffer, re, "<%c++$$$$<<$1;%>"); } parseLine(file, buffer, streamName, viewDataName, cxx_flag); } file << "if(layoutName.empty())\n{\n"; file << "std::string ret{std::move(" << streamName << ".str())};\n"; file << "return ret;\n}else\n{\n"; file << "auto templ = DrTemplateBase::newTemplate(layoutName);\n"; file << "if(!templ) return \"\";\n"; file << "HttpViewData data = " << viewDataName << ";\n"; file << "auto str = std::move(" << streamName << ".str());\n"; file << "if(!str.empty() && str[str.length()-1] == '\\n') " "str.resize(str.length()-1);\n"; file << "data[\"\"] = std::move(str);\n"; file << "return templ->genText(data);\n"; file << "}\n}\n"; }