// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef RY_PD_CPP_OUTPUT_H #define RY_PD_CPP_OUTPUT_H #include #include #include #include #include #include inline std::string lcFirst(std::string str) { if (!str.empty() && str[0]>='A' && str[0]<='Z') str[0] += 'a'-'A'; return str; } inline std::string padTab(std::string str, uint sz) { uint i; uint csize = 0; for (i=0; i Methods; std::string DisplayName; std::string Description; std::string Other; }; class SMethodId { public: SMethodId(sint section=-1, sint method=-1, CClassGenerator *generator=NULL) : Section(section), Method(method), Generator(generator) {} sint Section; sint Method; CClassGenerator *Generator; void add(const std::string &instruction); void setDescription(const std::string &description); }; /// name std::string Name; /// std::string Inherit; /// sections std::vector Sections; /// in body std::string Body; /// sint CurrentSection; /// SMethodId CurrentMethod; /// bool StartInline; void init(const std::string &name) { clear(); Name = name; } void clear() { Name.clear(); Sections.clear(); Body.clear(); Inherit.clear(); CurrentSection = -1; } void setSection(const std::string &name) { uint i; for (i=0; i CCppOutput & operator << (const T& t) { addToStream(NLMISC::toString(t).c_str()); return *this; } /// file description void setFileHeader(const std::string& filename, const std::string& description) { if (_Clean) { *this << "/** \\file " << filename << "\n"; if (!description.empty()) *this << description << "\n"; *this << "\n"; *this << "$Id$\n"; *this << "*/\n\n"; } } private: bool _CppMode; bool _XmlMode; bool _NewLine; sint _Indent; std::string _Buffer; bool _DescriptionMode; bool _Clean; std::vector _XmlNodes; bool _XmlInNode; bool _XmlLastSlash; bool _XmlGetNodeName; bool _XmlCloseNode; bool _XmlRootNode; std::string _XmlNodeName; /// Stream operator CCppOutput addToStream (const char* str) { _Clean = false; if (_CppMode) { while (*str != '\0') { if (!_DescriptionMode && *str == '}') unindent(); bool triggerDescriptionStart = false; bool triggerDescriptionEnd = false; if (!strncmp(str, "/**", 3)) { // start description triggerDescriptionStart = true; } if (_DescriptionMode && !strncmp(str, "*/", 2)) { // stop description triggerDescriptionEnd = true; } bool skipChar = false; if (*str != '\r') { if (_NewLine) { if ((*str == ' ' || *str == '\t') && !_DescriptionMode) { skipChar = true; } else { sint i; for (i=0; i<_Indent; ++i) _Buffer += '\t'; _NewLine = false; if (_DescriptionMode) { _Buffer += " "; if (!triggerDescriptionEnd) _Buffer += "* "; if (!triggerDescriptionEnd && *str == '*') { skipChar = true; } } } } if (!_DescriptionMode && *str == '{') indent(); } if (*str == '\n') { _NewLine = true; } if (!skipChar) _Buffer += *str; if (triggerDescriptionStart) _DescriptionMode = true; if (triggerDescriptionEnd) _DescriptionMode = false; ++str; } } else if (_XmlMode) { while (*str != '\0') { bool skipChar = false; bool requireIndent = false; if (*str == '<') { // _XmlCloseNode = (str[1] == '/'); _XmlRootNode = (str[1] == '?'); _XmlInNode = true; _XmlGetNodeName = true; _XmlNodeName.clear(); requireIndent = (!_XmlCloseNode && !_XmlRootNode); if (_XmlCloseNode) unindent(); } else if (*str == '>') { _XmlInNode = false; if (!_XmlCloseNode && !_XmlRootNode) { _XmlNodes.push_back(_XmlNodeName); } if (_XmlCloseNode || _XmlLastSlash) { if (_XmlLastSlash) unindent(); nlassert(!_XmlNodes.empty() && _XmlNodes.back() == _XmlNodeName); _XmlNodes.pop_back(); } } else if (*str == '\n') { _NewLine = true; } if (_NewLine) { if (*str == ' ' || *str == '\t') { skipChar = true; } else if (*str != '\n' && *str != '\r') { sint i; for (i=0; i<_Indent; ++i) _Buffer += '\t'; _NewLine = false; } } _XmlLastSlash = (*str == '/'); if (_XmlInNode && _XmlGetNodeName && *str != '/' && *str != '<') { if (!isalpha(*str)) _XmlGetNodeName = false; if (_XmlGetNodeName) _XmlNodeName += *str; } if (!skipChar) _Buffer += *str; ++str; if (requireIndent) indent(); } } else { _Buffer += str; } return *this; } }; // // Inline implementation // inline void CCppOutput::clear() { _Buffer.clear(); } inline bool searchForId(char* buffer, char** start, char** end) { const char* id = "$Id:"; uint len = (uint)strlen(id); for (; *buffer != '\0'; ++buffer) { if (strncmp(buffer, id, len) == 0) { *start = buffer; *end = buffer+1; while (**end != '\0' && **end != '$') ++(*end); if (**end != (char)'$') return false; ++(*end); return true; } } return false; } inline void CCppOutput::flush(const std::string &fileName) { NLMISC::COFile f; bool overwrite = true; if (NLMISC::CFile::fileExists(fileName)) { NLMISC::CIFile fi; if (fi.open(fileName)) { std::string buffer; buffer.resize(fi.getFileSize(), '*'); fi.serialBuffer((uint8*)(&(buffer[0])), fi.getFileSize()); // search for $Id: cpp_output.h,v 1.15 2004/12/13 17:19:01 legros Exp $ string in file... char *searchidstart, *searchidend; char *replaceidstart, *replaceidend; if (searchForId(&(buffer[0]), &replaceidstart, &replaceidend) && searchForId(&(_Buffer[0]), &searchidstart, &searchidend)) { std::string replace = std::string(replaceidstart, replaceidend-replaceidstart); std::string search = std::string(searchidstart, searchidend-searchidstart); NLMISC::strFindReplace(_Buffer, search, replace); } overwrite = (buffer != _Buffer); } } if (overwrite) { if (f.open(fileName)) { f.serialBuffer((uint8*)(_Buffer.c_str()), (uint)_Buffer.size()); f.close(); } else { nlwarning("Unable to open file '%s' for output", fileName.c_str()); } } else { nldebug("File '%s' did not changed, skipped", fileName.c_str()); } clear(); } inline void CCppOutput::indent() { ++_Indent; } inline void CCppOutput::unindent() { --_Indent; if (_Indent < 0) _Indent = 0; } inline void CClassGenerator::flush(CCppOutput &hFile, CCppOutput &cppFile, CCppOutput &hInlineFile) { hFile << "class " << Name; if (!Inherit.empty()) hFile << " : " << Inherit; hFile << "\n{\n"; hInlineFile << "/* -----------------------------------------\n"; hInlineFile << " * Inline implementation of " << Name << "\n"; hInlineFile << " * ----------------------------------------- */\n"; cppFile << "/* -----------------------------------------\n"; cppFile << " * Static Implementation of " << Name << "\n"; cppFile << " * ----------------------------------------- */\n"; uint i; for (i=0; iadd(instruction, *this); } inline void CClassGenerator::SMethodId::setDescription(const std::string &description) { nlassert(Generator != NULL); Generator->add(description, *this); } inline void CFunctionGenerator::flush(CCppOutput &hFile, CCppOutput &cppFile, CCppOutput &hInlineFile) { std::string inlinekw = (IsInline ? std::string("inline ") : std::string("")); if (!Description.empty()) { hFile << "\n/**\n" << Description << "\n*/\n"; } hFile << padTab(Type, 32) << lcFirst(Name) << "(" << Proto << ");\n"; if (IsInline) { hInlineFile << padTab(inlinekw+Type, 32) << lcFirst(Name) << "(" << removeDefaultArgs(Proto) << ")\n"; hInlineFile << "{\n"; hInlineFile << Body; hInlineFile << "}\n\n"; } else { cppFile << padTab(Type, 32) << lcFirst(Name) << "(" << removeDefaultArgs(Proto) << ")\n"; cppFile << "{\n"; cppFile << Body; cppFile << "}\n\n"; } } #endif