diff options
Diffstat (limited to 'src')
107 files changed, 5113 insertions, 4559 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 598f73c..8b11a2d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -136,14 +136,14 @@ foreach(lex_file ${LEX_FILES}) ) FLEX_TARGET(${lex_file} - ${lex_file}.l + ${CMAKE_CURRENT_LIST_DIR}/${lex_file}.l ${GENERATED_SRC}/${lex_file}.cpp COMPILE_FLAGS "${LEX_FLAGS}") endforeach() BISON_TARGET(constexp - constexp.y + ${CMAKE_CURRENT_LIST_DIR}/constexp.y ${GENERATED_SRC}/ce_parse.cpp COMPILE_FLAGS "${YACC_FLAGS}") @@ -167,6 +167,7 @@ add_library(doxycfg STATIC message.cpp debug.cpp ) +add_sanitizers(doxycfg) add_library(doxymain STATIC # generated for/by flex/bison @@ -296,6 +297,7 @@ add_library(doxymain STATIC xmldocvisitor.cpp xmlgen.cpp ) +add_sanitizers(doxymain) # LLVM/clang headers give a lot of warnings with -Wshadow and -Wcast-align so we disable them for # the one file that includes them @@ -311,6 +313,7 @@ endif() add_executable(doxygen main.cpp ) +add_sanitizers(doxygen) if (use_libclang) find_package(LLVM REQUIRED CONFIG) @@ -319,20 +322,23 @@ if (use_libclang) cmake_minimum_required(VERSION 3.1) target_compile_features(doxymain PRIVATE cxx_alignof) target_compile_features(doxygen PRIVATE cxx_alignof) - target_compile_options(doxymain PRIVATE -stdlib=libc++) - target_compile_options(doxygen PRIVATE -stdlib=libc++) - elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - target_compile_options(doxymain PRIVATE -std=c++11) - target_compile_options(doxygen PRIVATE -std=c++11) + if (use_libc++) + target_compile_options(doxymain PRIVATE -stdlib=libc++) + target_compile_options(doxygen PRIVATE -stdlib=libc++) + endif() endif() include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) - llvm_map_components_to_libnames(llvm_libs support core option) + if (static_libclang) + set(CLANG_LIBS libclang clangTooling) + else() # dynamically linked version of clang + llvm_config(doxymain USE_SHARED support) + set(CLANG_LIBS libclang clang-cpp) + endif() target_compile_definitions(doxygen PRIVATE ${LLVM_DEFINITIONS}) - set(CLANG_LIBS libclang clangTooling ${llvm_libs}) endif() -target_link_libraries(doxygen +target_link_libraries(doxygen PRIVATE doxymain doxycfg qtools @@ -359,5 +365,6 @@ set_project_coverage(doxycfg) set_project_coverage(doxymain) set_project_coverage(doxygen) + install(TARGETS doxygen DESTINATION bin) diff --git a/src/cite.cpp b/src/cite.cpp index dac2bcd..fd6fe3e 100644 --- a/src/cite.cpp +++ b/src/cite.cpp @@ -4,8 +4,8 @@ * Based on a patch by David Munger * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -22,6 +22,7 @@ #include "portable.h" #include "resourcemgr.h" #include "util.h" +#include "debug.h" #include <qfile.h> #include <qfileinfo.h> @@ -30,10 +31,6 @@ #include <map> #include <string> -// Remove the temporary files -#define RM_TMP_FILES (true) -//#define RM_TMP_FILES (false) - const char *bibTmpFile = "bibTmpFile_"; const char *bibTmpDir = "bibTmpDir/"; @@ -94,7 +91,7 @@ void CitationManager::clear() bool CitationManager::isEmpty() const { - uint numFiles = Config_getList(CITE_BIB_FILES).count(); + size_t numFiles = Config_getList(CITE_BIB_FILES).size(); return (numFiles==0 || p->entries.empty()); } @@ -108,72 +105,147 @@ const char *CitationManager::anchorPrefix() const return "CITEREF_"; } -void CitationManager::generatePage() +void CitationManager::insertCrossReferencesForBibFile(const QCString &bibFile) { - //printf("** CitationManager::generatePage() count=%d\n",m_ordering.count()); + // sanity checks + if (bibFile.isEmpty()) + { + return; + } + QFileInfo fi(bibFile); + if (!fi.exists()) + { + err("bib file %s not found!\n",bibFile.data()); + return; + } + QFile f(bibFile); + if (!f.open(IO_ReadOnly)) + { + err("could not open file %s for reading\n",bibFile.data()); + return; + } - // do not generate an empty citations page - if (isEmpty()) return; // nothing to cite + // convert file to string + QCString doc; + QCString input(fi.size()+1); + f.readBlock(input.rawData(),fi.size()); + f.close(); + input.at(fi.size())='\0'; - // 0. add cross references from the bib files to the cite dictionary - QFile f; - const QStrList &citeDataList = Config_getList(CITE_BIB_FILES); - QStrListIterator li(citeDataList); - const char *bibdata = 0; - for (li.toFirst() ; (bibdata = li.current()) ; ++li) + int pos=0; + int s; + + // helper lambda function to get the next line of input and update pos accordingly + auto get_next_line = [&input,&pos,&s]() { - QCString bibFile = bibdata; - if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib"; - QFileInfo fi(bibFile); - if (fi.exists()) + uint prevPos = (uint)pos; + pos=s+1; + return input.mid(prevPos,(uint)(s-prevPos)); + }; + + // helper lambda function to return if the end of the input has reached + auto end_of_input = [&s]() + { + return s==-1; + }; + + // helper lambda function to proceed to the next line in the input, and update s + // to point to the start of the line. Return true as long as there is a new line. + auto has_next_line = [&input,&pos,&s]() + { + s=input.find('\n',pos); + return s!=-1; + }; + + // search for citation cross references + QCString citeName; + while (has_next_line()) + { + QCString line = get_next_line(); + + int i; + if (line.stripWhiteSpace().startsWith("@")) { - if (!bibFile.isEmpty()) + // assumption entry like: "@book { name," or "@book { name" (spaces optional) + int j = line.find('{'); + // when no {, go hunting for it + while (j==-1 && has_next_line()) { - f.setName(bibFile); - if (!f.open(IO_ReadOnly)) - { - err("could not open file %s for reading\n",bibFile.data()); - } - QCString doc; - QCString input(fi.size()+1); - f.readBlock(input.rawData(),fi.size()); - f.close(); - input.at(fi.size())='\0'; - int pos=0; - int s; - while ((s=input.find('\n',pos))!=-1) + line = get_next_line(); + j = line.find('{'); + } + // search for the name + citeName = ""; + if (!end_of_input() && j!=-1) // to prevent something like "@manual ," and no { found + { + int k = line.find(',',j); + j++; + // found a line "@....{.....,...." or "@.....{....." + // ^=j ^=k ^=j k=-1 + while (!end_of_input() && citeName.isEmpty()) { - QCString line = input.mid((uint)pos,(uint)(s-pos)); - pos=s+1; - - int i; - if ((i = line.find("crossref")) != -1) /* assumption cross reference is on one line and the only item */ + if (k!=-1) + { + citeName = line.mid((uint)(j),(uint)(k-j)); + } + else { - int j=line.find("{",i); - int k=line.find("}",i); - if (j!=-1 && k!=-1) - { - QCString label = line.mid((uint)(j+1),(uint)(k-j-1)); - if (p->entries.find(label.data())==p->entries.end()) // not found yet - { - insert(label); - } - } + citeName = line.mid((uint)(j)); + } + citeName = citeName.stripWhiteSpace(); + j = 0; + if (citeName.isEmpty() && has_next_line()) + { + line = get_next_line(); + k = line.find(','); } } } + //printf("citeName = #%s#\n",citeName.data()); } - else if (!fi.exists()) + else if ((i=line.find("crossref"))!=-1 && !citeName.isEmpty()) /* assumption cross reference is on one line and the only item */ { - err("bib file %s not found!\n",bibFile.data()); + int j = line.find('{',i); + int k = line.find('}',i); + if (j>i && k>j) + { + QCString crossrefName = line.mid((uint)(j+1),(uint)(k-j-1)); + // check if the reference with the cross reference is used + // insert cross refererence when cross reference has not yet been added. + if ((p->entries.find(citeName.data())!=p->entries.end()) && + (p->entries.find(crossrefName.data())==p->entries.end())) // not found yet + { + insert(crossrefName); + } + } } } +} + +void CitationManager::generatePage() +{ + //printf("** CitationManager::generatePage() count=%d\n",m_ordering.count()); + + // do not generate an empty citations page + if (isEmpty()) return; // nothing to cite + + bool citeDebug = Debug::isFlagSet(Debug::Cite); + + // 0. add cross references from the bib files to the cite dictionary + QFile f; + const StringVector &citeDataList = Config_getList(CITE_BIB_FILES); + for (const auto &bibdata : citeDataList) + { + QCString bibFile = bibdata.c_str(); + if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib"; + insertCrossReferencesForBibFile(bibFile); + } // 1. generate file with markers and citations to OUTPUT_DIRECTORY QCString outputDir = Config_getString(OUTPUT_DIRECTORY); QCString citeListFile = outputDir+"/citelist.doc"; f.setName(citeListFile); - if (!f.open(IO_WriteOnly)) + if (!f.open(IO_WriteOnly)) { err("could not open file %s for writing\n",citeListFile.data()); } @@ -205,11 +277,15 @@ void CitationManager::generatePage() QCString bibOutputDir = outputDir+"/"+bibTmpDir; QCString bibOutputFiles = ""; QDir thisDir; - thisDir.mkdir(bibOutputDir); + if (!thisDir.exists(bibOutputDir) && !thisDir.mkdir(bibOutputDir)) + { + err("Failed to create temporary output directory '%s', skipping citations\n",bibOutputDir.data()); + return; + } int i = 0; - for (li.toFirst() ; (bibdata = li.current()) ; ++li) + for (const auto &bibdata : citeDataList) { - QCString bibFile = bibdata; + QCString bibFile = bibdata.c_str(); if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib"; QFileInfo fi(bibFile); if (fi.exists()) @@ -231,7 +307,7 @@ void CitationManager::generatePage() int exitCode; Portable::sysTimerStop(); if ((exitCode=Portable::system("perl","\""+bib2xhtmlFile+"\" "+bibOutputFiles+" \""+ - citeListFile+"\"")) != 0) + citeListFile+"\"" + (citeDebug ? " -d" : ""))) != 0) { err("Problems running bibtex. Verify that the command 'perl --version' works from the command line. Exit code: %d\n", exitCode); @@ -242,7 +318,7 @@ void CitationManager::generatePage() // 6. read back the file f.setName(citeListFile); - if (!f.open(IO_ReadOnly)) + if (!f.open(IO_ReadOnly)) { err("could not open file %s for reading\n",citeListFile.data()); } @@ -294,16 +370,16 @@ void CitationManager::generatePage() // 7. add it as a page addRelatedPage(fileName(),theTranslator->trCiteReferences(),doc,fileName(),1); - // 8. for latex we just copy the bib files to the output and let + // 8. for latex we just copy the bib files to the output and let // latex do this work. if (Config_getBool(GENERATE_LATEX)) { // copy bib files to the latex output dir QCString latexOutputDir = Config_getString(LATEX_OUTPUT)+"/"; i = 0; - for (li.toFirst() ; (bibdata = li.current()) ; ++li) + for (const auto &bibdata : citeDataList) { - QCString bibFile = bibdata; + QCString bibFile = bibdata.c_str(); // Note: file can now have multiple dots if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib"; fi.setFile(bibFile); @@ -325,7 +401,7 @@ void CitationManager::generatePage() } // 9. Remove temporary files - if (RM_TMP_FILES) + if (!citeDebug) { thisDir.remove(citeListFile); thisDir.remove(doxygenBstFile); @@ -333,9 +409,9 @@ void CitationManager::generatePage() // we might try to remove too many files as empty files didn't get a corresponding new file // but the remove function does not emit an error for it and we don't catch the error return // so no problem. - for (unsigned int j = 1; j <= citeDataList.count(); j++) + for (size_t j = 1; j <= citeDataList.size(); j++) { - thisDir.remove(bibOutputDir + bibTmpFile + QCString().setNum(j) + ".bib"); + thisDir.remove(bibOutputDir + bibTmpFile + QCString().setNum(static_cast<ulong>(j)) + ".bib"); } thisDir.rmdir(bibOutputDir); } @@ -370,13 +446,11 @@ void CitationManager::writeLatexBibliography(FTextStream &t) const } t << "\\bibliographystyle{" << style << "}\n" "\\bibliography{"; - QStrList &citeDataList = Config_getList(CITE_BIB_FILES); + const StringVector &citeDataList = Config_getList(CITE_BIB_FILES); int i = 0; - QStrListIterator li(citeDataList); - const char *bibdata = 0; - for (li.toFirst() ; (bibdata = li.current()) ; ++li) + for (const auto &bibdata : citeDataList) { - QCString bibFile = bibdata; + QCString bibFile = bibdata.c_str(); // Note: file can now have multiple dots if (!bibFile.isEmpty() && bibFile.right(4)!=".bib") bibFile+=".bib"; QFileInfo fi(bibFile); @@ -4,8 +4,8 @@ * Based on a patch by David Munger * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -70,6 +70,7 @@ class CitationManager private: /** Create the database, with an expected maximum of \a size entries */ CitationManager(); + void insertCrossReferencesForBibFile(const QCString &bibFile); struct Private; std::unique_ptr<Private> p; }; diff --git a/src/clangparser.cpp b/src/clangparser.cpp index 0754888..d0ed573 100644 --- a/src/clangparser.cpp +++ b/src/clangparser.cpp @@ -20,17 +20,22 @@ #include "membername.h" #include "filename.h" #include "tooltip.h" +#if MULTITHREADED_INPUT +#include <mutex> +#endif +#endif -static Definition *g_currentDefinition=0; -static MemberDef *g_currentMemberDef=0; -static uint g_currentLine=0; -static bool g_searchForBody=FALSE; -static bool g_insideBody=FALSE; -static uint g_bracketCount=0; +//-------------------------------------------------------------------------- + +#if MULTITHREADED_INPUT +std::mutex g_clangMutex; #endif ClangParser *ClangParser::instance() { +#if MULTITHREADED_INPUT + std::lock_guard<std::mutex> lock(g_clangMutex); +#endif if (!s_instance) s_instance = new ClangParser; return s_instance; } @@ -40,29 +45,7 @@ ClangParser *ClangParser::s_instance = 0; //-------------------------------------------------------------------------- #if USE_LIBCLANG -class ClangParser::Private -{ - public: - enum DetectedLang { Detected_Cpp, Detected_ObjC, Detected_ObjCpp }; - Private() : tu(0), tokens(0), numTokens(0), cursors(0), - ufs(0), sources(0), numFiles(0), fileMapping(257), - detectedLang(Detected_Cpp) - { fileMapping.setAutoDelete(TRUE); } - int getCurrentTokenLine(); - CXIndex index; - CXTranslationUnit tu; - QCString fileName; - CXToken *tokens; - uint numTokens; - CXCursor *cursors; - uint curLine; - uint curToken; - CXUnsavedFile *ufs; - QCString *sources; - uint numFiles; - QDict<uint> fileMapping; - DetectedLang detectedLang; -}; +enum class DetectedLang { Cpp, ObjC, ObjCpp }; static QCString detab(const QCString &s) { @@ -118,99 +101,110 @@ static QCString detab(const QCString &s) return out.get(); } -/** Callback function called for each include in a translation unit */ -static void inclusionVisitor(CXFile includedFile, - CXSourceLocation* /*inclusionStack*/, - unsigned /*includeLen*/, - CXClientData clientData) +static QCString keywordToType(const char *keyword) { - QDict<void> *fileDict = (QDict<void> *)clientData; - CXString incFileName = clang_getFileName(includedFile); - //printf("--- file %s includes %s\n",fileName,clang_getCString(incFileName)); - fileDict->insert(clang_getCString(incFileName),(void*)0x8); - clang_disposeString(incFileName); + static const StringUnorderedSet flowKeywords({ + "break", "case", "catch", "continue", "default", "do", + "else", "finally", "for", "foreach", "for each", "goto", + "if", "return", "switch", "throw", "throws", "try", + "while", "@try", "@catch", "@finally" }); + static const StringUnorderedSet typeKeywords({ + "bool", "char", "double", "float", "int", "long", "object", + "short", "signed", "unsigned", "void", "wchar_t", "size_t", + "boolean", "id", "SEL", "string", "nullptr" }); + if (flowKeywords.find(keyword)!=flowKeywords.end()) return "keywordflow"; + if (typeKeywords.find(keyword)!=typeKeywords.end()) return "keywordtype"; + return "keyword"; } -/** filter the \a files and only keep those that are found as include files - * within the current translation unit. - * @param[in,out] files The list of files to filter. - */ -void ClangParser::determineInputFilesInSameTu(QStrList &files) + +//-------------------------------------------------------------------------- + +class ClangTUParser::Private +{ + public: + Private(const ClangParser &p,const FileDef *fd) + : parser(p), fileDef(fd) {} + const ClangParser &parser; + const FileDef *fileDef; + CXIndex index; + uint curToken = 0; + DetectedLang detectedLang = DetectedLang::Cpp; + uint numFiles = 0; + std::vector<QCString> sources; + std::vector<CXUnsavedFile> ufs; + std::vector<CXCursor> cursors; + std::unordered_map<std::string,uint> fileMapping; + CXTranslationUnit tu; + CXToken *tokens = 0; + uint numTokens = 0; + StringVector filesInSameTU; + + // state while parsing sources + MemberDef *currentMemberDef=0; + uint currentLine=0; + bool searchForBody=FALSE; + bool insideBody=FALSE; + uint bracketCount=0; +}; + +ClangTUParser::ClangTUParser(const ClangParser &parser,const FileDef *fd) + : p(std::make_unique<Private>(parser,fd)) { - // put the files in this translation unit in a dictionary - QDict<void> incFound(257); - clang_getInclusions(p->tu, - inclusionVisitor, - (CXClientData)&incFound - ); - // create a new filtered file list - QStrList resultIncludes; - QStrListIterator it2(files); - for (it2.toFirst();it2.current();++it2) - { - if (incFound.find(it2.current())) - { - resultIncludes.append(it2.current()); - } - } - // replace the original list - files=resultIncludes; } -void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) +StringVector ClangTUParser::filesInSameTU() const { - static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); - static QStrList &includePath = Config_getList(INCLUDE_PATH); - static QStrList clangOptions = Config_getList(CLANG_OPTIONS); - static QCString clangCompileDatabase = Config_getString(CLANG_DATABASE_PATH); + return p->filesInSameTU; +} + +void ClangTUParser::parse() +{ + QCString fileName = p->fileDef->absFilePath(); + p->fileDef->getAllIncludeFilesRecursively(p->filesInSameTU); + //printf("ClangTUParser::ClangTUParser(fileName=%s,#filesInSameTU=%d)\n", + // qPrint(fileName),(int)p->filesInSameTU.size()); + bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); + bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); + const StringVector &includePath = Config_getList(INCLUDE_PATH); + const StringVector &clangOptions = Config_getList(CLANG_OPTIONS); if (!clangAssistedParsing) return; //printf("ClangParser::start(%s)\n",fileName); - p->fileName = fileName; p->index = clang_createIndex(0, 0); - p->curLine = 1; p->curToken = 0; int argc=0; - std::string error; - // load a clang compilation database (https://clang.llvm.org/docs/JSONCompilationDatabase.html) - // this only needs to be loaded once, and could be refactored to a higher level function - static std::unique_ptr<clang::tooling::CompilationDatabase> db = - clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error); - int clang_option_len = 0; + size_t clang_option_len = 0; std::vector<clang::tooling::CompileCommand> command; - if (qstrcmp(clangCompileDatabase, "0") != 0) + if (p->parser.database()!=nullptr) { - if (db == nullptr) - { - // user specified a path, but DB file was not found - err("%s using clang compilation database path of: \"%s\"\n", error.c_str(), - clangCompileDatabase.data()); - } - else - { - // check if the file we are parsing is in the DB - command = db->getCompileCommands(fileName); - if (!command.empty() ) - { - // it's possible to have multiple entries for the same file, so use the last entry - clang_option_len = command[command.size()-1].CommandLine.size(); - } - } + // check if the file we are parsing is in the DB + command = p->parser.database()->getCompileCommands(fileName.data()); + if (!command.empty() ) + { + // it's possible to have multiple entries for the same file, so use the last entry + clang_option_len = command[command.size()-1].CommandLine.size(); + } } char **argv = (char**)malloc(sizeof(char*)* (4+Doxygen::inputPaths.size()+ - includePath.count()+ - clangOptions.count()+ + includePath.size()+ + clangOptions.size()+ clang_option_len)); if (!command.empty() ) { - std::vector<std::string> options = command[command.size()-1].CommandLine; - // copy each compiler option used from the database. Skip the first which is compiler exe. - for (auto option = options.begin()+1; option != options.end(); option++) - { - argv[argc++] = qstrdup(option->c_str()); - } - // this extra addition to argv is accounted for as we are skipping the first entry in - argv[argc++]=qstrdup("-w"); // finally, turn off warnings. + std::vector<std::string> options = command[command.size()-1].CommandLine; + // copy each compiler option used from the database. Skip the first which is compiler exe. + for (auto option = options.begin()+1; option != options.end(); option++) + { + argv[argc++] = qstrdup(option->c_str()); + } + // user specified options + for (size_t i=0;i<clangOptions.size();i++) + { + argv[argc++]=qstrdup(clangOptions[i].c_str()); + } + // this extra addition to argv is accounted for as we are skipping the first entry in + argv[argc++]=qstrdup("-w"); // finally, turn off warnings. } else { @@ -218,19 +212,19 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) for (const std::string &path : Doxygen::inputPaths) { QCString inc = QCString("-I")+path.data(); - argv[argc]=qstrdup(inc.data()); + argv[argc++]=qstrdup(inc.data()); //printf("argv[%d]=%s\n",argc,argv[argc]); } // add external include paths - for (uint i=0;i<includePath.count();i++) + for (size_t i=0;i<includePath.size();i++) { - QCString inc = QCString("-I")+includePath.at(i); + QCString inc = QCString("-I")+includePath[i].c_str(); argv[argc++]=qstrdup(inc.data()); } // user specified options - for (uint i=0;i<clangOptions.count();i++) + for (size_t i=0;i<clangOptions.size();i++) { - argv[argc++]=qstrdup(clangOptions.at(i)); + argv[argc++]=qstrdup(clangOptions[i].c_str()); } // extra options argv[argc++]=qstrdup("-ferror-limit=0"); @@ -241,67 +235,63 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) // we use the source file to detected the language. Detection will fail if you // pass a bunch of .h files containing ObjC code, and no sources :-( SrcLangExt lang = getLanguageFromFileName(fileName); - if (lang==SrcLangExt_ObjC || p->detectedLang!=ClangParser::Private::Detected_Cpp) + if (lang==SrcLangExt_ObjC || p->detectedLang!=DetectedLang::Cpp) { QCString fn = fileName; - if (p->detectedLang==ClangParser::Private::Detected_Cpp && + if (p->detectedLang!=DetectedLang::Cpp && (fn.right(4).lower()==".cpp" || fn.right(4).lower()==".cxx" || fn.right(3).lower()==".cc" || fn.right(2).lower()==".c")) { // fall back to C/C++ once we see an extension that indicates this - p->detectedLang = ClangParser::Private::Detected_Cpp; + p->detectedLang = DetectedLang::Cpp; } else if (fn.right(3).lower()==".mm") // switch to Objective C++ { - p->detectedLang = ClangParser::Private::Detected_ObjCpp; + p->detectedLang = DetectedLang::ObjCpp; } else if (fn.right(2).lower()==".m") // switch to Objective C { - p->detectedLang = ClangParser::Private::Detected_ObjC; + p->detectedLang = DetectedLang::ObjC; } } - switch(p->detectedLang) + switch (p->detectedLang) { - case ClangParser::Private::Detected_Cpp: - argv[argc++]=qstrdup("c++"); - break; - case ClangParser::Private::Detected_ObjC: - argv[argc++]=qstrdup("objective-c"); - break; - case ClangParser::Private::Detected_ObjCpp: - argv[argc++]=qstrdup("objective-c++"); - break; + case DetectedLang::Cpp: argv[argc++]=qstrdup("c++"); break; + case DetectedLang::ObjC: argv[argc++]=qstrdup("objective-c"); break; + case DetectedLang::ObjCpp: argv[argc++]=qstrdup("objective-c++"); break; } // provide the input and and its dependencies as unsaved files so we can // pass the filtered versions argv[argc++]=qstrdup(fileName); } - static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); //printf("source %s ----------\n%s\n-------------\n\n", // fileName,p->source.data()); - int numUnsavedFiles = filesInTranslationUnit.count()+1; + int numUnsavedFiles = static_cast<int>(p->filesInSameTU.size()+1); p->numFiles = numUnsavedFiles; - p->sources = new QCString[numUnsavedFiles]; - p->ufs = new CXUnsavedFile[numUnsavedFiles]; + p->sources.resize(numUnsavedFiles); + p->ufs.resize(numUnsavedFiles); p->sources[0] = detab(fileToString(fileName,filterSourceFiles,TRUE)); p->ufs[0].Filename = qstrdup(fileName); p->ufs[0].Contents = p->sources[0].data(); p->ufs[0].Length = p->sources[0].length(); - QStrListIterator it(filesInTranslationUnit); + p->fileMapping.insert({fileName.data(),0}); int i=1; - for (it.toFirst();it.current() && i<numUnsavedFiles;++it,i++) + for (auto it = p->filesInSameTU.begin(); + it != p->filesInSameTU.end() && i<numUnsavedFiles; + ++it, i++) { - p->fileMapping.insert(it.current(),new uint(i)); - p->sources[i] = detab(fileToString(it.current(),filterSourceFiles,TRUE)); - p->ufs[i].Filename = qstrdup(it.current()); + p->fileMapping.insert({it->c_str(),static_cast<uint>(i)}); + p->sources[i] = detab(fileToString(it->c_str(),filterSourceFiles,TRUE)); + p->ufs[i].Filename = qstrdup(it->c_str()); p->ufs[i].Contents = p->sources[i].data(); p->ufs[i].Length = p->sources[i].length(); } // let libclang do the actual parsing p->tu = clang_parseTranslationUnit(p->index, 0, - argv, argc, p->ufs, numUnsavedFiles, + argv, argc, p->ufs.data(), numUnsavedFiles, CXTranslationUnit_DetailedPreprocessingRecord); + //printf(" tu=%p\n",p->tu); // free arguments for (i=0;i<argc;++i) { @@ -311,9 +301,6 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) if (p->tu) { - // filter out any includes not found by the clang parser - determineInputFilesInSameTu(filesInTranslationUnit); - // show any warnings that the compiler produced int n=clang_getNumDiagnostics(p->tu); for (i=0; i!=n; ++i) @@ -325,105 +312,74 @@ void ClangParser::start(const char *fileName,QStrList &filesInTranslationUnit) clang_disposeString(string); clang_disposeDiagnostic(diag); } - - // create a source range for the given file - QFileInfo fi(fileName); - CXFile f = clang_getFile(p->tu, fileName); - CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); - CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[0].Length); - CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); - - // produce a token stream for the file - clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); - - // produce cursors for each token in the stream - p->cursors=new CXCursor[p->numTokens]; - clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); } else { p->tokens = 0; p->numTokens = 0; - p->cursors = 0; - err("clang: Failed to parse translation unit %s\n",fileName); - } -} - -void ClangParser::switchToFile(const char *fileName) -{ - if (p->tu) - { - delete[] p->cursors; - clang_disposeTokens(p->tu,p->tokens,p->numTokens); - p->tokens = 0; - p->numTokens = 0; - p->cursors = 0; - - QFileInfo fi(fileName); - CXFile f = clang_getFile(p->tu, fileName); - uint *pIndex=p->fileMapping.find(fileName); - if (pIndex && *pIndex<p->numFiles) - { - uint i=*pIndex; - //printf("switchToFile %s: len=%ld\n",fileName,p->ufs[i].Length); - CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); - CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[i].Length); - CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); - - clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); - p->cursors=new CXCursor[p->numTokens]; - clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors); - - p->curLine = 1; - p->curToken = 0; - } - else - { - err("clang: Failed to find input file %s in mapping\n",fileName); - } + p->cursors.clear(); + err("clang: Failed to parse translation unit %s\n",qPrint(fileName)); } } -void ClangParser::finish() +ClangTUParser::~ClangTUParser() { + //printf("ClangTUParser::~ClangTUParser() tu=%p\n",p->tu); static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); if (!clangAssistedParsing) return; if (p->tu) { - //printf("ClangParser::finish()\n"); - delete[] p->cursors; + p->cursors.clear(); clang_disposeTokens(p->tu,p->tokens,p->numTokens); clang_disposeTranslationUnit(p->tu); clang_disposeIndex(p->index); p->fileMapping.clear(); p->tokens = 0; p->numTokens = 0; - p->cursors = 0; } for (uint i=0;i<p->numFiles;i++) { free((void *)p->ufs[i].Filename); } - delete[] p->ufs; - delete[] p->sources; - p->ufs = 0; - p->sources = 0; + p->ufs.clear(); + p->sources.clear(); p->numFiles = 0; p->tu = 0; } -int ClangParser::Private::getCurrentTokenLine() +void ClangTUParser::switchToFile(FileDef *fd) { - uint l, c; - if (numTokens==0) return 1; - // guard against filters that reduce the number of lines - if (curToken>=numTokens) curToken=numTokens-1; - CXSourceLocation start = clang_getTokenLocation(tu,tokens[curToken]); - clang_getSpellingLocation(start, 0, &l, &c, 0); - return l; + //printf("ClangTUParser::switchToFile(%s)\n",qPrint(fd->absFilePath())); + if (p->tu) + { + p->cursors.clear(); + clang_disposeTokens(p->tu,p->tokens,p->numTokens); + p->tokens = 0; + p->numTokens = 0; + + CXFile f = clang_getFile(p->tu, fd->absFilePath()); + auto it = p->fileMapping.find(fd->absFilePath().data()); + if (it!=p->fileMapping.end() && it->second < p->numFiles) + { + uint i = it->second; + //printf("switchToFile %s: len=%ld\n",fileName,p->ufs[i].Length); + CXSourceLocation fileBegin = clang_getLocationForOffset(p->tu, f, 0); + CXSourceLocation fileEnd = clang_getLocationForOffset(p->tu, f, p->ufs[i].Length); + CXSourceRange fileRange = clang_getRange(fileBegin, fileEnd); + + clang_tokenize(p->tu,fileRange,&p->tokens,&p->numTokens); + p->cursors.resize(p->numTokens); + clang_annotateTokens(p->tu,p->tokens,p->numTokens,p->cursors.data()); + p->curToken = 0; + } + else + { + err("clang: Failed to find input file %s in mapping\n",qPrint(fd->absFilePath())); + } + } } -QCString ClangParser::lookup(uint line,const char *symbol) +QCString ClangTUParser::lookup(uint line,const char *symbol) { //printf("ClangParser::lookup(%d,%s)\n",line,symbol); QCString result; @@ -431,19 +387,30 @@ QCString ClangParser::lookup(uint line,const char *symbol) static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); if (!clangAssistedParsing) return result; + auto getCurrentTokenLine = [=]() -> uint + { + uint l, c; + if (p->numTokens==0) return 1; + // guard against filters that reduce the number of lines + if (p->curToken>=p->numTokens) p->curToken=p->numTokens-1; + CXSourceLocation start = clang_getTokenLocation(p->tu,p->tokens[p->curToken]); + clang_getSpellingLocation(start, 0, &l, &c, 0); + return l; + }; + int sl = strlen(symbol); - uint l = p->getCurrentTokenLine(); + uint l = getCurrentTokenLine(); while (l>=line && p->curToken>0) { if (l==line) // already at the right line { p->curToken--; // linear search to start of the line - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); } else { p->curToken/=2; // binary search backward - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); } } bool found=FALSE; @@ -468,7 +435,7 @@ QCString ClangParser::lookup(uint line,const char *symbol) { break; // end of token stream } - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); clang_disposeString(tokenString); tokenString = clang_getTokenSpelling(p->tu, p->tokens[p->curToken]); ts = clang_getCString(tokenString); @@ -505,7 +472,7 @@ QCString ClangParser::lookup(uint line,const char *symbol) p->curToken++; if (p->curToken<p->numTokens) { - l = p->getCurrentTokenLine(); + l = getCurrentTokenLine(); } } //if (!found) @@ -519,78 +486,23 @@ QCString ClangParser::lookup(uint line,const char *symbol) return result; } -static QCString keywordToType(const char *keyword) -{ - static bool init=TRUE; - static QDict<void> flowKeywords(47); - static QDict<void> typeKeywords(47); - if (init) - { - flowKeywords.insert("break",(void*)0x8); - flowKeywords.insert("case",(void*)0x8); - flowKeywords.insert("catch",(void*)0x8); - flowKeywords.insert("continue",(void*)0x8); - flowKeywords.insert("default",(void*)0x8); - flowKeywords.insert("do",(void*)0x8); - flowKeywords.insert("else",(void*)0x8); - flowKeywords.insert("finally",(void*)0x8); - flowKeywords.insert("for",(void*)0x8); - flowKeywords.insert("foreach",(void*)0x8); - flowKeywords.insert("for each",(void*)0x8); - flowKeywords.insert("goto",(void*)0x8); - flowKeywords.insert("if",(void*)0x8); - flowKeywords.insert("return",(void*)0x8); - flowKeywords.insert("switch",(void*)0x8); - flowKeywords.insert("throw",(void*)0x8); - flowKeywords.insert("throws",(void*)0x8); - flowKeywords.insert("try",(void*)0x8); - flowKeywords.insert("while",(void*)0x8); - flowKeywords.insert("@try",(void*)0x8); - flowKeywords.insert("@catch",(void*)0x8); - flowKeywords.insert("@finally",(void*)0x8); - - typeKeywords.insert("bool",(void*)0x8); - typeKeywords.insert("char",(void*)0x8); - typeKeywords.insert("double",(void*)0x8); - typeKeywords.insert("float",(void*)0x8); - typeKeywords.insert("int",(void*)0x8); - typeKeywords.insert("long",(void*)0x8); - typeKeywords.insert("object",(void*)0x8); - typeKeywords.insert("short",(void*)0x8); - typeKeywords.insert("signed",(void*)0x8); - typeKeywords.insert("unsigned",(void*)0x8); - typeKeywords.insert("void",(void*)0x8); - typeKeywords.insert("wchar_t",(void*)0x8); - typeKeywords.insert("size_t",(void*)0x8); - typeKeywords.insert("boolean",(void*)0x8); - typeKeywords.insert("id",(void*)0x8); - typeKeywords.insert("SEL",(void*)0x8); - typeKeywords.insert("string",(void*)0x8); - typeKeywords.insert("nullptr",(void*)0x8); - init=FALSE; - } - if (flowKeywords[keyword]) return "keywordflow"; - if (typeKeywords[keyword]) return "keywordtype"; - return "keyword"; -} -static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) +void ClangTUParser::writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) { Definition *d = fd ? fd->getSourceDefinition(line) : 0; if (d && d->isLinkable()) { - g_currentDefinition=d; - g_currentLine=line; + p->currentLine=line; MemberDef *md = fd->getSourceMember(line); if (md && md->isLinkable()) // link to member { - if (g_currentMemberDef!=md) // new member, start search for body + if (p->currentMemberDef!=md) // new member, start search for body { - g_searchForBody=TRUE; - g_insideBody=FALSE; - g_bracketCount=0; + p->searchForBody=TRUE; + p->insideBody=FALSE; + p->bracketCount=0; } - g_currentMemberDef=md; + p->currentMemberDef=md; ol.writeLineNumber(md->getReference(), md->getOutputFileBase(), md->anchor(), @@ -598,7 +510,7 @@ static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) } else // link to compound { - g_currentMemberDef=0; + p->currentMemberDef=0; ol.writeLineNumber(d->getReference(), d->getOutputFileBase(), d->anchor(), @@ -621,8 +533,8 @@ static void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line) //printf("writeLineNumber(%d) g_searchForBody=%d\n",line,g_searchForBody); } -static void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, - uint &line,uint &column,const char *fontClass=0) +void ClangTUParser::codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, + uint &line,uint &column,const char *fontClass) { if (fontClass) ol.startFontClass(fontClass); const char *p=text,*sp=p; @@ -657,7 +569,7 @@ static void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, if (fontClass) ol.endFontClass(); } -static void writeMultiLineCodeLink(CodeOutputInterface &ol, +void ClangTUParser::writeMultiLineCodeLink(CodeOutputInterface &ol, FileDef *fd,uint &line,uint &column, Definition *d, const char *text) @@ -698,7 +610,7 @@ static void writeMultiLineCodeLink(CodeOutputInterface &ol, } } -void ClangParser::linkInclude(CodeOutputInterface &ol,FileDef *fd, +void ClangTUParser::linkInclude(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text) { QCString incName = text; @@ -732,7 +644,7 @@ void ClangParser::linkInclude(CodeOutputInterface &ol,FileDef *fd, } } -void ClangParser::linkMacro(CodeOutputInterface &ol,FileDef *fd, +void ClangTUParser::linkMacro(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text) { MemberName *mn=Doxygen::functionNameLinkedMap->find(text); @@ -751,7 +663,7 @@ void ClangParser::linkMacro(CodeOutputInterface &ol,FileDef *fd, } -void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, +void ClangTUParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column,const char *text,int tokenIndex) { CXCursor c = p->cursors[tokenIndex]; @@ -782,11 +694,11 @@ void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, //} if (d && d->isLinkable()) { - if (g_insideBody && - g_currentMemberDef && d->definitionType()==Definition::TypeMember && - (g_currentMemberDef!=d || g_currentLine<line)) // avoid self-reference + if (p->insideBody && + p->currentMemberDef && d->definitionType()==Definition::TypeMember && + (p->currentMemberDef!=d || p->currentLine<line)) // avoid self-reference { - addDocCrossReference(g_currentMemberDef,dynamic_cast<MemberDef *>(d)); + addDocCrossReference(p->currentMemberDef,dynamic_cast<MemberDef *>(d)); } writeMultiLineCodeLink(ol,fd,line,column,d,text); } @@ -797,45 +709,44 @@ void ClangParser::linkIdentifier(CodeOutputInterface &ol,FileDef *fd, clang_disposeString(usr); } -static void detectFunctionBody(const char *s) +void ClangTUParser::detectFunctionBody(const char *s) { //printf("punct=%s g_searchForBody=%d g_insideBody=%d g_bracketCount=%d\n", // s,g_searchForBody,g_insideBody,g_bracketCount); - if (g_searchForBody && (qstrcmp(s,":")==0 || qstrcmp(s,"{")==0)) // start of 'body' (: is for constructor) + if (p->searchForBody && (qstrcmp(s,":")==0 || qstrcmp(s,"{")==0)) // start of 'body' (: is for constructor) { - g_searchForBody=FALSE; - g_insideBody=TRUE; + p->searchForBody=FALSE; + p->insideBody=TRUE; } - else if (g_searchForBody && qstrcmp(s,";")==0) // declaration only + else if (p->searchForBody && qstrcmp(s,";")==0) // declaration only { - g_searchForBody=FALSE; - g_insideBody=FALSE; + p->searchForBody=FALSE; + p->insideBody=FALSE; } - if (g_insideBody && qstrcmp(s,"{")==0) // increase scoping level + if (p->insideBody && qstrcmp(s,"{")==0) // increase scoping level { - g_bracketCount++; + p->bracketCount++; } - if (g_insideBody && qstrcmp(s,"}")==0) // decrease scoping level + if (p->insideBody && qstrcmp(s,"}")==0) // decrease scoping level { - g_bracketCount--; - if (g_bracketCount<=0) // got outside of function body + p->bracketCount--; + if (p->bracketCount<=0) // got outside of function body { - g_insideBody=FALSE; - g_bracketCount=0; + p->insideBody=FALSE; + p->bracketCount=0; } } } -void ClangParser::writeSources(CodeOutputInterface &ol,FileDef *fd) +void ClangTUParser::writeSources(CodeOutputInterface &ol,FileDef *fd) { // (re)set global parser state - g_currentDefinition=0; - g_currentMemberDef=0; - g_currentLine=0; - g_searchForBody=FALSE; - g_insideBody=FALSE; - g_bracketCount=0; + p->currentMemberDef=0; + p->currentLine=0; + p->searchForBody=FALSE; + p->insideBody=FALSE; + p->bracketCount=0; unsigned int line=1,column=1; QCString lineNumber,lineAnchor; @@ -939,49 +850,79 @@ void ClangParser::writeSources(CodeOutputInterface &ol,FileDef *fd) ol.endCodeLine(); } -ClangParser::ClangParser() +//-------------------------------------------------------------------------- + +class ClangParser::Private { - p = new Private; + public: + Private() + { + std::string error; + QCString clangCompileDatabase = Config_getString(CLANG_DATABASE_PATH); + // load a clang compilation database (https://clang.llvm.org/docs/JSONCompilationDatabase.html) + db = clang::tooling::CompilationDatabase::loadFromDirectory(clangCompileDatabase.data(), error); + if (clangCompileDatabase!="0" && db==nullptr) + { + // user specified a path, but DB file was not found + err("%s using clang compilation database path of: \"%s\"\n", error.c_str(), + clangCompileDatabase.data()); + } + } + + std::unique_ptr<clang::tooling::CompilationDatabase> db; +}; + +const clang::tooling::CompilationDatabase *ClangParser::database() const +{ + return p->db.get(); } -ClangParser::~ClangParser() +ClangParser::ClangParser() : p(std::make_unique<Private>()) { - delete p; } -//-------------------------------------------------------------------------- -#else // use stubbed functionality in case libclang support is disabled. +ClangParser::~ClangParser() +{ +} -void ClangParser::start(const char *,QStrList &) +std::unique_ptr<ClangTUParser> ClangParser::createTUParser(const FileDef *fd) const { + return std::make_unique<ClangTUParser>(*this,fd); } -void ClangParser::switchToFile(const char *) + +//-------------------------------------------------------------------------- +#else // use stubbed functionality in case libclang support is disabled. + +void ClangTUParser::switchToFile(FileDef *fd) { } -void ClangParser::finish() +void ClangTUParser::parse() { } -QCString ClangParser::lookup(uint,const char *) +QCString ClangTUParser::lookup(uint,const char *) { return ""; } -void ClangParser::writeSources(CodeOutputInterface &,FileDef *) +class ClangParser::Private { -} +}; -ClangParser::ClangParser() +ClangParser::ClangParser() : p(std::make_unique<Private>()) { - p = NULL; } ClangParser::~ClangParser() { } +std::unique_ptr<ClangTUParser> ClangParser::createTUParser(const FileDef *) const +{ + return nullptr; +} #endif //-------------------------------------------------------------------------- diff --git a/src/clangparser.h b/src/clangparser.h index 8bb9aba..8ee1bdb 100644 --- a/src/clangparser.h +++ b/src/clangparser.h @@ -3,39 +3,41 @@ #include <qcstring.h> #include <qstrlist.h> +#include "containers.h" +#include <memory> class CodeOutputInterface; class FileDef; +class ClangParser; +class Definition; -/** @brief Wrapper for to let libclang assisted parsing. */ -class ClangParser +namespace clang { namespace tooling { + class CompilationDatabase; +} } + +/** @brief Clang parser object for a single translation unit, which consists of a source file + * and the directly or indirectly included headers + */ +class ClangTUParser { public: - /** Returns the one and only instance of the class */ - static ClangParser *instance(); - - /** Start parsing a file. - * @param[in] fileName The name of the file to parse. - * @param[in,out] filesInTranslationUnit Other files that are - * part of the input and included by the file. - * The function will return a subset of the files, - * only including the ones that were actually found - * during parsing. + ClangTUParser(const ClangParser &parser,const FileDef *fd); + virtual ~ClangTUParser(); + + /** Parse the file given at construction time as a translation unit + * This file should already be preprocessed by doxygen preprocessor at the time of calling. */ - void start(const char *fileName,QStrList &filesInTranslationUnit); + void parse(); - /** Switches to another file within the translation unit started - * with start(). + /** Switches to another file within the translation unit started with start(). * @param[in] fileName The name of the file to switch to. */ - void switchToFile(const char *fileName); + void switchToFile(FileDef *fd); - /** Finishes parsing a translation unit. Free any resources that - * were needed for parsing. - */ - void finish(); + /** Returns the list of files for this translation unit */ + StringVector filesInSameTU() const; - /** Looks for \a symbol which should be found at \a line and + /** Looks for \a symbol which should be found at \a line. * returns a clang unique reference to the symbol. */ QCString lookup(uint line,const char *symbol); @@ -47,6 +49,13 @@ class ClangParser void writeSources(CodeOutputInterface &ol,FileDef *fd); private: + void detectFunctionBody(const char *s); + void writeLineNumber(CodeOutputInterface &ol,FileDef *fd,uint line); + void codifyLines(CodeOutputInterface &ol,FileDef *fd,const char *text, + uint &line,uint &column,const char *fontClass=0); + void writeMultiLineCodeLink(CodeOutputInterface &ol, + FileDef *fd,uint &line,uint &column, + Definition *d, const char *text); void linkIdentifier(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column, const char *text,int tokenIndex); @@ -56,9 +65,25 @@ class ClangParser void linkInclude(CodeOutputInterface &ol,FileDef *fd, uint &line,uint &column, const char *text); - void determineInputFilesInSameTu(QStrList &filesInTranslationUnit); + ClangTUParser(const ClangTUParser &) = delete; + ClangTUParser &operator=(const ClangTUParser &) = delete; + class Private; + std::unique_ptr<Private> p; +}; + +/** @brief Wrapper for to let libclang assisted parsing. */ +class ClangParser +{ + friend class ClangTUParser; + public: + /** Returns the one and only instance of the class */ + static ClangParser *instance(); + std::unique_ptr<ClangTUParser> createTUParser(const FileDef *fd) const; + + private: + const clang::tooling::CompilationDatabase *database() const; class Private; - Private *p; + std::unique_ptr<Private> p; ClangParser(); virtual ~ClangParser(); static ClangParser *s_instance; diff --git a/src/classdef.cpp b/src/classdef.cpp index 5e300ce..5dee0dc 100644 --- a/src/classdef.cpp +++ b/src/classdef.cpp @@ -1431,7 +1431,8 @@ void ClassDefImpl::writeBriefDescription(OutputList &ol,bool exampleFlag) const ol.writeString(" - "); ol.popGeneratorState(); ol.generateDoc(briefFile(),briefLine(),this,0, - briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + briefDescription(),TRUE,FALSE,0, + TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.pushGeneratorState(); ol.disable(OutputGenerator::RTF); ol.writeString(" \n"); @@ -1462,7 +1463,8 @@ void ClassDefImpl::writeDetailedDocumentationBody(OutputList &ol) const // repeat brief description if (!briefDescription().isEmpty() && repeatBrief) { - ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } if (!briefDescription().isEmpty() && repeatBrief && !documentation().isEmpty()) @@ -1475,7 +1477,8 @@ void ClassDefImpl::writeDetailedDocumentationBody(OutputList &ol) const // write documentation if (!documentation().isEmpty()) { - ol.generateDoc(docFile(),docLine(),this,0,documentation(),TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,documentation(),TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } // write type constraints writeTypeConstraints(ol,this,m_impl->typeConstraints); @@ -1848,16 +1851,15 @@ void ClassDefImpl::writeIncludeFilesForSlice(OutputList &ol) const if (m_impl->incInfo) { QCString nm; - QStrList paths = Config_getList(STRIP_FROM_PATH); - if (!paths.isEmpty() && m_impl->incInfo->fileDef) + const StringVector &paths = Config_getList(STRIP_FROM_PATH); + if (!paths.empty() && m_impl->incInfo->fileDef) { QCString abs = m_impl->incInfo->fileDef->absFilePath(); - const char *s = paths.first(); QCString potential; unsigned int length = 0; - while (s) + for (const auto &s : paths) { - QFileInfo info(s); + QFileInfo info(s.c_str()); if (info.exists()) { QCString prefix = info.absFilePath().utf8(); @@ -1872,7 +1874,6 @@ void ClassDefImpl::writeIncludeFilesForSlice(OutputList &ol) const length = prefix.length(); potential = abs.right(abs.length() - prefix.length()); } - s = paths.next(); } } @@ -2574,7 +2575,8 @@ void ClassDefImpl::writeDeclarationLink(OutputList &ol,bool &found,const char *h if (!briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC)) { DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(),this,0, - briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + briefDescription(),FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (rootNode && !rootNode->isEmpty()) { ol.startMemberDescription(anchor()); diff --git a/src/commentcnv.l b/src/commentcnv.l index e05634a..a7d74ef 100644 --- a/src/commentcnv.l +++ b/src/commentcnv.l @@ -870,6 +870,9 @@ MAILADR ("mailto:")?[a-z_A-Z0-9.+-]+"@"[a-z_A-Z0-9-]+("."[a-z_A-Z0-9\-]+)+[a-z copyToOutput(yyscanner,yytext,(int)yyleng); } +<*>. { + copyToOutput(yyscanner,yytext,(int)yyleng); + } %% static void replaceCommentMarker(yyscan_t yyscanner,const char *s,int len) diff --git a/src/commentscan.h b/src/commentscan.h index be92920..a111352 100644 --- a/src/commentscan.h +++ b/src/commentscan.h @@ -3,8 +3,8 @@ * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -60,6 +60,7 @@ class CommentScanner * @param[out] newEntryNeeded Boolean that is TRUE if the comment block parser * finds that a the comment block finishes the entry and a new one * needs to be started. + * @param[in] markdownEnabled Indicates if markdown specific processing should be done. * @returns TRUE if the comment requires further processing. The * parameter \a newEntryNeeded will typically be true in this case and * \a position will indicate the offset inside the \a comment string @@ -76,7 +77,8 @@ class CommentScanner bool isInbody, Protection &prot, int &position, - bool &newEntryNeeded + bool &newEntryNeeded, + bool markdownEnabled ); void initGroupInfo(Entry *entry); void enterFile(const char *fileName,int lineNr); diff --git a/src/commentscan.l b/src/commentscan.l index 309a334..a1dd0e1 100644 --- a/src/commentscan.l +++ b/src/commentscan.l @@ -3,8 +3,8 @@ * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -24,12 +24,13 @@ %{ /* - * includes + * includes */ #include <map> #include <stack> #include <string> +#include <mutex> #include <stdio.h> #include <stdlib.h> @@ -118,7 +119,6 @@ static bool handleHideReferencedByRelation(yyscan_t yyscanner,const QCString &, static bool handleReferencesRelation(yyscan_t yyscanner,const QCString &, const QCStringList &); static bool handleHideReferencesRelation(yyscan_t yyscanner,const QCString &, const QCStringList &); static bool handleInternal(yyscan_t yyscanner,const QCString &, const QCStringList &); -static bool handleLineBr(yyscan_t yyscanner,const QCString &, const QCStringList &); static bool handleStatic(yyscan_t yyscanner,const QCString &, const QCStringList &); static bool handlePure(yyscan_t yyscanner,const QCString &, const QCStringList &); static bool handlePrivate(yyscan_t yyscanner,const QCString &, const QCStringList &); @@ -144,156 +144,162 @@ static const char *stateToString(int state); typedef bool (*DocCmdFunc)(yyscan_t yyscanner,const QCString &name, const QCStringList &optList); +enum class CommandSpacing +{ + Invisible, // command sets some property but does not appear in the output. + Inline, // command appears inline in the output which can be a brief description. + Block // command starts a new paragraphs / ends a brief description. +}; + struct DocCmdMap { - DocCmdMap(DocCmdFunc h,bool b) : handler(h), endsBrief(b) {} + DocCmdMap(DocCmdFunc h,CommandSpacing s) : handler(h), spacing(s) {} DocCmdFunc handler; - bool endsBrief; + CommandSpacing spacing; }; // map of command to handler function static const std::map< std::string, DocCmdMap > docCmdMap = { - // command name handler function ends brief description - { "brief", { &handleBrief, FALSE }}, - { "short", { &handleBrief, FALSE }}, - { "fn", { &handleFn, TRUE }}, - { "var", { &handleFn, TRUE }}, - { "typedef", { &handleFn, TRUE }}, - { "property", { &handleFn, TRUE }}, - { "def", { &handleDef, TRUE }}, - { "overload", { &handleOverload, FALSE }}, - { "enum", { &handleEnum, TRUE }}, - { "defgroup", { &handleDefGroup, TRUE }}, - { "addtogroup", { &handleAddToGroup, TRUE }}, - { "weakgroup", { &handleWeakGroup, TRUE }}, - { "namespace", { &handleNamespace, TRUE }}, - { "package", { &handlePackage, TRUE }}, - { "class", { &handleClass, TRUE }}, - { "headerfile", { &handleHeaderFile, FALSE }}, - { "protocol", { &handleProtocol, TRUE }}, - { "category", { &handleCategory, TRUE }}, - { "union", { &handleUnion, TRUE }}, - { "struct", { &handleStruct, TRUE }}, - { "interface", { &handleInterface, TRUE }}, - { "idlexcept", { &handleIdlException, TRUE }}, - { "page", { &handlePage, TRUE }}, - { "mainpage", { &handleMainpage, TRUE }}, - { "file", { &handleFile, TRUE }}, - { "dir", { &handleDir, TRUE }}, - { "example", { &handleExample, FALSE }}, - { "details", { &handleDetails, TRUE }}, - { "name", { &handleName, FALSE }}, - { "todo", { &handleTodo, FALSE }}, // end brief will be done differently - { "test", { &handleTest, FALSE }}, // end brief will be done differently - { "bug", { &handleBug, FALSE }}, // end brief will be done differently - { "deprecated", { &handleDeprecated, FALSE }}, // end brief will be done differently - { "xrefitem", { &handleXRefItem, FALSE }}, // end brief will be done differently - { "related", { &handleRelated, TRUE }}, - { "relates", { &handleRelated, TRUE }}, - { "relatedalso", { &handleRelatedAlso, TRUE }}, - { "relatesalso", { &handleRelatedAlso, TRUE }}, - { "parblock", { &handleParBlock, TRUE }}, - { "endparblock", { &handleEndParBlock, TRUE }}, - { "refitem", { &handleRefItem, TRUE }}, - { "cite", { &handleCite, FALSE }}, - { "subpage", { &handleSubpage, TRUE }}, - { "section", { &handleSection, TRUE }}, - { "subsection", { &handleSection, TRUE }}, - { "subsubsection", { &handleSection, TRUE }}, - { "paragraph", { &handleSection, TRUE }}, - { "anchor", { &handleAnchor, TRUE }}, - { "verbatim", { &handleFormatBlock, TRUE }}, - { "latexonly", { &handleFormatBlock, FALSE }}, - { "htmlonly", { &handleFormatBlock, FALSE }}, - { "xmlonly", { &handleFormatBlock, FALSE }}, - { "docbookonly", { &handleFormatBlock, FALSE }}, - { "rtfonly", { &handleFormatBlock, FALSE }}, - { "manonly", { &handleFormatBlock, FALSE }}, - { "dot", { &handleFormatBlock, TRUE }}, - { "msc", { &handleFormatBlock, TRUE }}, - { "startuml", { &handleFormatBlock, TRUE }}, - { "code", { &handleFormatBlock, TRUE }}, - { "addindex", { &handleAddIndex, FALSE }}, - { "if", { &handleIf, FALSE }}, - { "ifnot", { &handleIfNot, FALSE }}, - { "elseif", { &handleElseIf, FALSE }}, - { "else", { &handleElse, FALSE }}, - { "endif", { &handleEndIf, FALSE }}, - { "ingroup", { &handleIngroup, TRUE }}, - { "nosubgrouping", { &handleNoSubGrouping, FALSE }}, - { "showinitializer", { &handleShowInitializer, FALSE }}, - { "hideinitializer", { &handleHideInitializer, FALSE }}, - { "callgraph", { &handleCallgraph, FALSE }}, - { "hidecallgraph", { &handleHideCallgraph, FALSE }}, - { "callergraph", { &handleCallergraph, FALSE }}, - { "hidecallergraph", { &handleHideCallergraph, FALSE }}, - { "showrefby", { &handleReferencedByRelation, FALSE }}, - { "hiderefby", { &handleHideReferencedByRelation, FALSE }}, - { "showrefs", { &handleReferencesRelation, FALSE }}, - { "hiderefs", { &handleHideReferencesRelation, FALSE }}, - { "internal", { &handleInternal, TRUE }}, - { "_linebr", { &handleLineBr, FALSE }}, - { "static", { &handleStatic, FALSE }}, - { "pure", { &handlePure, FALSE }}, - { "private", { &handlePrivate, FALSE }}, - { "privatesection", { &handlePrivateSection, FALSE }}, - { "protected", { &handleProtected, FALSE }}, - { "protectedsection",{ &handleProtectedSection, FALSE }}, - { "public", { &handlePublic, FALSE }}, - { "publicsection", { &handlePublicSection, FALSE }}, - { "tableofcontents", { &handleToc, FALSE }}, - { "inherit", { &handleInherit, TRUE }}, - { "extends", { &handleExtends, TRUE }}, - { "implements", { &handleExtends, TRUE }}, - { "memberof", { &handleMemberOf, TRUE }}, - { "arg", { 0, TRUE }}, - { "attention", { 0, TRUE }}, - { "author", { 0, TRUE }}, - { "authors", { 0, TRUE }}, - { "copydoc", { &handleCopyDoc, TRUE }}, - { "copybrief", { &handleCopyBrief, FALSE }}, - { "copydetails", { &handleCopyDetails, TRUE }}, - { "copyright", { 0, TRUE }}, - { "date", { 0, TRUE }}, - { "dotfile", { 0, TRUE }}, - { "htmlinclude", { 0, FALSE }}, - { "image", { 0, TRUE }}, - { "include", { 0, TRUE }}, - { "includelineno", { 0, TRUE }}, - { "invariant", { 0, TRUE }}, - { "latexinclude", { 0, FALSE }}, - { "li", { 0, TRUE }}, - { "line", { 0, TRUE }}, - { "note", { 0, TRUE }}, - { "par", { 0, TRUE }}, - { "param", { &handleParam, TRUE }}, - { "tparam", { 0, TRUE }}, - { "post", { 0, TRUE }}, - { "pre", { 0, TRUE }}, - { "remark", { 0, TRUE }}, - { "remarks", { 0, TRUE }}, - { "result", { 0, TRUE }}, - { "return", { 0, TRUE }}, - { "returns", { 0, TRUE }}, - { "exception", { 0, TRUE }}, - { "retval", { &handleRetval, TRUE }}, - { "sa", { 0, TRUE }}, - { "see", { 0, TRUE }}, - { "since", { 0, TRUE }}, - { "throw", { 0, TRUE }}, - { "throws", { 0, TRUE }}, - { "until", { 0, TRUE }}, - { "verbinclude", { 0, FALSE }}, - { "version", { 0, TRUE }}, - { "warning", { 0, TRUE }}, - { "snippet", { 0, TRUE }}, - { "snippetlineno", { 0, TRUE }}, - { "noop", { &handleNoop, TRUE }}, - { "rtfinclude", { 0, FALSE }}, - { "docbookinclude", { 0, FALSE }}, - { "maninclude", { 0, FALSE }}, - { "xmlinclude", { 0, FALSE }} + // command name handler function command spacing + { "addindex", { &handleAddIndex, CommandSpacing::Invisible }}, + { "addtogroup", { &handleAddToGroup, CommandSpacing::Invisible }}, + { "anchor", { &handleAnchor, CommandSpacing::Invisible }}, + { "arg", { 0, CommandSpacing::Block }}, + { "attention", { 0, CommandSpacing::Block }}, + { "author", { 0, CommandSpacing::Block }}, + { "authors", { 0, CommandSpacing::Block }}, + { "brief", { &handleBrief, CommandSpacing::Invisible }}, + { "bug", { &handleBug, CommandSpacing::Block }}, + { "callergraph", { &handleCallergraph, CommandSpacing::Invisible }}, + { "callgraph", { &handleCallgraph, CommandSpacing::Invisible }}, + { "category", { &handleCategory, CommandSpacing::Invisible }}, + { "cite", { &handleCite, CommandSpacing::Inline }}, + { "class", { &handleClass, CommandSpacing::Invisible }}, + { "code", { &handleFormatBlock, CommandSpacing::Block }}, + { "copybrief", { &handleCopyBrief, CommandSpacing::Invisible }}, + { "copydetails", { &handleCopyDetails, CommandSpacing::Block }}, + { "copydoc", { &handleCopyDoc, CommandSpacing::Block }}, + { "copyright", { 0, CommandSpacing::Block }}, + { "date", { 0, CommandSpacing::Block }}, + { "def", { &handleDef, CommandSpacing::Invisible }}, + { "defgroup", { &handleDefGroup, CommandSpacing::Invisible }}, + { "deprecated", { &handleDeprecated, CommandSpacing::Block }}, + { "details", { &handleDetails, CommandSpacing::Block }}, + { "dir", { &handleDir, CommandSpacing::Invisible }}, + { "docbookinclude", { 0, CommandSpacing::Inline }}, + { "docbookonly", { &handleFormatBlock, CommandSpacing::Invisible }}, + { "dot", { &handleFormatBlock, CommandSpacing::Block }}, + { "dotfile", { 0, CommandSpacing::Block }}, + { "else", { &handleElse, CommandSpacing::Inline }}, + { "elseif", { &handleElseIf, CommandSpacing::Inline }}, + { "endif", { &handleEndIf, CommandSpacing::Inline }}, + { "endparblock", { &handleEndParBlock, CommandSpacing::Block }}, + { "enum", { &handleEnum, CommandSpacing::Invisible }}, + { "example", { &handleExample, CommandSpacing::Invisible }}, + { "exception", { 0, CommandSpacing::Block }}, + { "extends", { &handleExtends, CommandSpacing::Invisible }}, + { "file", { &handleFile, CommandSpacing::Invisible }}, + { "fn", { &handleFn, CommandSpacing::Invisible }}, + { "headerfile", { &handleHeaderFile, CommandSpacing::Invisible }}, + { "hidecallergraph", { &handleHideCallergraph, CommandSpacing::Invisible }}, + { "hidecallgraph", { &handleHideCallgraph, CommandSpacing::Invisible }}, + { "hideinitializer", { &handleHideInitializer, CommandSpacing::Invisible }}, + { "hiderefby", { &handleHideReferencedByRelation, CommandSpacing::Invisible }}, + { "hiderefs", { &handleHideReferencesRelation, CommandSpacing::Invisible }}, + { "htmlinclude", { 0, CommandSpacing::Inline }}, + { "htmlonly", { &handleFormatBlock, CommandSpacing::Invisible }}, + { "idlexcept", { &handleIdlException, CommandSpacing::Invisible }}, + { "if", { &handleIf, CommandSpacing::Inline }}, + { "ifnot", { &handleIfNot, CommandSpacing::Inline }}, + { "image", { 0, CommandSpacing::Block }}, + { "implements", { &handleExtends, CommandSpacing::Invisible }}, + { "include", { 0, CommandSpacing::Block }}, + { "includelineno", { 0, CommandSpacing::Block }}, + { "ingroup", { &handleIngroup, CommandSpacing::Invisible }}, + { "inherit", { &handleInherit, CommandSpacing::Invisible }}, + { "interface", { &handleInterface, CommandSpacing::Invisible }}, + { "internal", { &handleInternal, CommandSpacing::Block }}, + { "invariant", { 0, CommandSpacing::Block }}, + { "latexinclude", { 0, CommandSpacing::Inline }}, + { "latexonly", { &handleFormatBlock, CommandSpacing::Invisible }}, + { "li", { 0, CommandSpacing::Block }}, + { "line", { 0, CommandSpacing::Invisible }}, + { "mainpage", { &handleMainpage, CommandSpacing::Invisible }}, + { "maninclude", { 0, CommandSpacing::Inline }}, + { "manonly", { &handleFormatBlock, CommandSpacing::Invisible }}, + { "memberof", { &handleMemberOf, CommandSpacing::Invisible }}, + { "msc", { &handleFormatBlock, CommandSpacing::Block }}, + { "name", { &handleName, CommandSpacing::Invisible }}, + { "namespace", { &handleNamespace, CommandSpacing::Invisible }}, + { "noop", { &handleNoop, CommandSpacing::Invisible }}, + { "nosubgrouping", { &handleNoSubGrouping, CommandSpacing::Invisible }}, + { "note", { 0, CommandSpacing::Block }}, + { "overload", { &handleOverload, CommandSpacing::Invisible }}, + { "package", { &handlePackage, CommandSpacing::Invisible }}, + { "page", { &handlePage, CommandSpacing::Invisible }}, + { "par", { 0, CommandSpacing::Block }}, + { "paragraph", { &handleSection, CommandSpacing::Block }}, + { "param", { &handleParam, CommandSpacing::Block }}, + { "parblock", { &handleParBlock, CommandSpacing::Block }}, + { "post", { 0, CommandSpacing::Block }}, + { "pre", { 0, CommandSpacing::Block }}, + { "private", { &handlePrivate, CommandSpacing::Invisible }}, + { "privatesection", { &handlePrivateSection, CommandSpacing::Invisible }}, + { "property", { &handleFn, CommandSpacing::Invisible }}, + { "protected", { &handleProtected, CommandSpacing::Invisible }}, + { "protectedsection",{ &handleProtectedSection, CommandSpacing::Invisible }}, + { "protocol", { &handleProtocol, CommandSpacing::Invisible }}, + { "public", { &handlePublic, CommandSpacing::Invisible }}, + { "publicsection", { &handlePublicSection, CommandSpacing::Invisible }}, + { "pure", { &handlePure, CommandSpacing::Invisible }}, + { "refitem", { &handleRefItem, CommandSpacing::Inline }}, + { "related", { &handleRelated, CommandSpacing::Invisible }}, + { "relatedalso", { &handleRelatedAlso, CommandSpacing::Invisible }}, + { "relates", { &handleRelated, CommandSpacing::Invisible }}, + { "relatesalso", { &handleRelatedAlso, CommandSpacing::Invisible }}, + { "remark", { 0, CommandSpacing::Block }}, + { "remarks", { 0, CommandSpacing::Block }}, + { "result", { 0, CommandSpacing::Block }}, + { "return", { 0, CommandSpacing::Block }}, + { "returns", { 0, CommandSpacing::Block }}, + { "retval", { &handleRetval, CommandSpacing::Block }}, + { "rtfinclude", { 0, CommandSpacing::Inline }}, + { "rtfonly", { &handleFormatBlock, CommandSpacing::Invisible }}, + { "sa", { 0, CommandSpacing::Block }}, + { "section", { &handleSection, CommandSpacing::Block }}, + { "see", { 0, CommandSpacing::Block }}, + { "short", { &handleBrief, CommandSpacing::Invisible }}, + { "showinitializer", { &handleShowInitializer, CommandSpacing::Invisible }}, + { "showrefby", { &handleReferencedByRelation, CommandSpacing::Invisible }}, + { "showrefs", { &handleReferencesRelation, CommandSpacing::Invisible }}, + { "since", { 0, CommandSpacing::Block }}, + { "snippet", { 0, CommandSpacing::Block }}, + { "snippetlineno", { 0, CommandSpacing::Block }}, + { "startuml", { &handleFormatBlock, CommandSpacing::Block }}, + { "static", { &handleStatic, CommandSpacing::Invisible }}, + { "struct", { &handleStruct, CommandSpacing::Invisible }}, + { "subpage", { &handleSubpage, CommandSpacing::Inline }}, + { "subsection", { &handleSection, CommandSpacing::Block }}, + { "subsubsection", { &handleSection, CommandSpacing::Block }}, + { "tableofcontents", { &handleToc, CommandSpacing::Invisible }}, + { "test", { &handleTest, CommandSpacing::Block }}, + { "throw", { 0, CommandSpacing::Block }}, + { "throws", { 0, CommandSpacing::Block }}, + { "todo", { &handleTodo, CommandSpacing::Block }}, + { "tparam", { 0, CommandSpacing::Block }}, + { "typedef", { &handleFn, CommandSpacing::Invisible }}, + { "union", { &handleUnion, CommandSpacing::Invisible }}, + { "until", { 0, CommandSpacing::Block }}, + { "var", { &handleFn, CommandSpacing::Invisible }}, + { "verbatim", { &handleFormatBlock, CommandSpacing::Block }}, + { "verbinclude", { 0, CommandSpacing::Inline }}, + { "version", { 0, CommandSpacing::Block }}, + { "warning", { 0, CommandSpacing::Block }}, + { "weakgroup", { &handleWeakGroup, CommandSpacing::Invisible }}, + { "xmlinclude", { 0, CommandSpacing::Inline }}, + { "xmlonly", { &handleFormatBlock, CommandSpacing::Invisible }}, + { "xrefitem", { &handleXRefItem, CommandSpacing::Block }} }; #define YY_NO_INPUT 1 @@ -329,11 +335,11 @@ enum GuardType class GuardedSection { public: - GuardedSection(bool enabled,bool parentVisible) + GuardedSection(bool enabled,bool parentVisible) : m_enabled(enabled),m_parentVisible(parentVisible) {} bool isEnabled() const { return m_enabled; } bool parentVisible() const { return m_parentVisible; } - + private: bool m_enabled; bool m_parentVisible; @@ -341,13 +347,14 @@ class GuardedSection /* ----------------------------------------------------------------- * - * statics + * statics */ struct commentscanYY_state { OutlineParserInterface *langParser = 0; // the language parser that is calling us QCString inputString; // input string + QCString currentCmd; // the command used int inputPosition = 0; // read pointer QCString fileName; // file name that is read from int lineNr = 0; // line number in the input @@ -398,8 +405,16 @@ struct commentscanYY_state bool inInternalDocs = FALSE; int prevPosition = 0; DocGroup docGroup; + bool markdownSupport = TRUE; }; + +#if MULTITHREADED_INPUT +static std::mutex g_sectionMutex; +static std::mutex g_formulaMutex; +static std::mutex g_citeMutex; +#endif + //----------------------------------------------------------------------------- static QCString stripQuotes(const char *s); @@ -428,20 +443,20 @@ static void addCite(yyscan_t yyscanner); //----------------------------------------------------------------------------- -#undef YY_INPUT -#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size); +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) result=yyread(yyscanner,buf,max_size); %} /* start command character */ -CMD ("\\"|"@") -XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem") +CMD ("\\"|"@") +XREFCMD {CMD}("bug"|"deprecated"|"test"|"todo"|"xrefitem") PRE [pP][rR][eE] -TABLE [tT][aA][bB][lL][eE] -P [pP] +TABLE [tT][aA][bB][lL][eE] +P [pP] UL [uU][lL] -OL [oO][lL] -DL [dD][lL] +OL [oO][lL] +DL [dD][lL] IMG [iI][mM][gG] HR [hH][rR] PARA [pP][aA][rR][aA] @@ -452,13 +467,13 @@ DIV [dD][iI][vV] DETAILEDHTML {CENTER}|{DIV}|{PRE}|{UL}|{TABLE}|{OL}|{DL}|{P}|[Hh][1-6]|{IMG}|{HR}|{PARA} DETAILEDHTMLOPT {CODE} BN [ \t\n\r] -BL [ \t\r]*"\n" +BL [ \t\r]*"\n" B [ \t] BS ^(({B}*"//")?)(({B}*"*"+)?){B}* ATTR ({B}+[^>\n]*)? -DOCNL "\n"|"\\_linebr" +DOCNL "\n"|"\\ilinebr" LC "\\"{B}*"\n" -NW [^a-z_A-Z0-9] +NW [^a-z_A-Z0-9] FILESCHAR [a-z_A-Z0-9\x80-\xFF\\:\\\/\-\+@&#] FILEECHAR [a-z_A-Z0-9\x80-\xFF\-\+@&#] FILE ({FILESCHAR}*{FILEECHAR}+("."{FILESCHAR}*{FILEECHAR}+)*)|("\""[^\n\"]*"\"") @@ -470,7 +485,7 @@ CITEID {CITESCHAR}{CITEECHAR}*("."{CITESCHAR}{CITEECHAR}*)*|"\""{CITESCHAR}{C SCOPEID {ID}({ID}*{BN}*"::"{BN}*)*({ID}?) SCOPENAME "$"?(({ID}?{BN}*("::"|"."){BN}*)*)((~{BN}*)?{ID}) TMPLSPEC "<"{BN}*[^>]+{BN}*">" -MAILADDR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+ +MAILADDR [a-z_A-Z0-9.+\-]+"@"[a-z_A-Z0-9\-]+("."[a-z_A-Z0-9\-]+)+[a-z_A-Z0-9\-]+ RCSTAG "$"{ID}":"[^\n$]+"$" %option noyywrap @@ -489,34 +504,34 @@ RCSTAG "$"{ID}":"[^\n$]+"$" %x XRefItemParam3 %x FileDocArg1 %x ParamArg1 -%x EnumDocArg1 -%x NameSpaceDocArg1 -%x PackageDocArg1 -%x GroupDocArg1 -%x GroupDocArg2 -%x SectionLabel -%x SectionTitle -%x SubpageLabel -%x SubpageTitle -%x FormatBlock -%x LineParam -%x GuardParam -%x GuardParamEnd -%x SkipGuardedSection -%x SkipInternal +%x EnumDocArg1 +%x NameSpaceDocArg1 +%x PackageDocArg1 +%x GroupDocArg1 +%x GroupDocArg2 +%x SectionLabel +%x SectionTitle +%x SubpageLabel +%x SubpageTitle +%x FormatBlock +%x LineParam +%x GuardParam +%x GuardParamEnd +%x SkipGuardedSection +%x SkipInternal %x NameParam -%x InGroupParam -%x FnParam -%x OverloadParam -%x InheritParam -%x ExtendsParam +%x InGroupParam +%x FnParam +%x OverloadParam +%x InheritParam +%x ExtendsParam %x ReadFormulaShort -%x ReadFormulaLong -%x AnchorLabel +%x ReadFormulaLong +%x AnchorLabel %x HtmlComment %x SkipLang -%x CiteLabel -%x CopyDoc +%x CiteLabel +%x CopyDoc %x GuardExpr %x CdataSection %x Noop @@ -540,52 +555,52 @@ RCSTAG "$"{ID}":"[^\n$]+"$" * XML commands, <summary></summary><remarks></remarks> */ -<Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command - addOutput(yyscanner,yytext); - } -<Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command - addOutput(yyscanner,yytext); - } -<Comment>{MAILADDR} { // mail address - addOutput(yyscanner,yytext); - } -<Comment>"\""[^"\n]*"\"" { // quoted text +<Comment>{CMD}{CMD}[a-z_A-Z]+{B}* { // escaped command + addOutput(yyscanner,yytext); + } +<Comment>{CMD}{CMD}"~"[a-z_A-Z]* { // escaped command + addOutput(yyscanner,yytext); + } +<Comment>{MAILADDR} { // mail address + addOutput(yyscanner,yytext); + } +<Comment>"\""[^"\n]*"\"" { // quoted text + addOutput(yyscanner,yytext); + } +<Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!) addOutput(yyscanner,yytext); - } -<Comment>("\\"[a-z_A-Z]+)+"\\" { // directory (or chain of commands!) - addOutput(yyscanner,yytext); - } -<Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description - setOutput(yyscanner,OutputDoc); - // continue with the same input + } +<Comment>"<"{DETAILEDHTML}{ATTR}">" { // HTML command that ends a brief description + setOutput(yyscanner,OutputDoc); + // continue with the same input REJECT; - } -<Comment>"<"{DETAILEDHTMLOPT}{ATTR}">" { // HTML command that ends a brief description - if (yyextra->current->lang==SrcLangExt_CSharp) + } +<Comment>"<"{DETAILEDHTMLOPT}{ATTR}">" { // HTML command that ends a brief description + if (yyextra->current->lang==SrcLangExt_CSharp) { setOutput(yyscanner,OutputDoc); } - // continue with the same input + // continue with the same input REJECT; - } -<Comment>"<summary>" { // start of a .NET XML style brief description - setOutput(yyscanner,OutputBrief); + } +<Comment>"<summary>" { // start of a .NET XML style brief description + setOutput(yyscanner,OutputBrief); addOutput(yyscanner,yytext); - } -<Comment>"<remarks>" { // start of a .NET XML style detailed description - setOutput(yyscanner,OutputDoc); + } +<Comment>"<remarks>" { // start of a .NET XML style detailed description + setOutput(yyscanner,OutputDoc); addOutput(yyscanner,yytext); - } -<Comment>"</summary>" { // start of a .NET XML style detailed description - setOutput(yyscanner,OutputBrief); + } +<Comment>"</summary>" { // start of a .NET XML style detailed description + setOutput(yyscanner,OutputBrief); addOutput(yyscanner,yytext); - setOutput(yyscanner,OutputDoc); - } -<Comment>"</remarks>" { // end of a brief or detailed description - - setOutput(yyscanner,OutputDoc); + setOutput(yyscanner,OutputDoc); + } +<Comment>"</remarks>" { // end of a brief or detailed description + + setOutput(yyscanner,OutputDoc); addOutput(yyscanner,yytext); - } + } <Comment>"<"{CAPTION}{ATTR}">" { QCString tag=yytext; int s=tag.find("id="); @@ -616,22 +631,25 @@ RCSTAG "$"{ID}":"[^\n$]+"$" setOutput(yyscanner,OutputDoc); REJECT; } -<Comment>"<!--" { +<Comment>"<!--" { BEGIN(HtmlComment); } <Comment>"<!\[CDATA\[" { BEGIN(CdataSection); } -<Comment>{B}*{CMD}"endinternal"{B}* { - addOutput(yyscanner," \\endinternal "); +<Comment>{B}*{CMD}"endinternal"{B}* { + addOutput(yyscanner," \\endinternal "); if (!yyextra->inInternalDocs) - warn(yyextra->fileName,yyextra->lineNr, + warn(yyextra->fileName,yyextra->lineNr, "found \\endinternal without matching \\internal" ); yyextra->inInternalDocs = FALSE; - } + } +<Comment>{B}*"\\ilinebr"{B}* { // preserve spacing around \\ilinebr + addOutput(yyscanner,yytext); + } <Comment>{B}*{CMD}[a-z_A-Z]+"{"[a-zA-Z_,:0-9\. ]*"}"{B}* | -<Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command +<Comment>{B}*{CMD}[a-z_A-Z]+{B}* { // potentially interesting command // the {B}* in the front was added for bug620924 QCString fullMatch = QCString(yytext); int idx = fullMatch.find('{'); @@ -650,84 +668,84 @@ RCSTAG "$"{ID}":"[^\n$]+"$" QCString optStr = fullMatch.mid(idx+1,idxEnd-idx-1).stripWhiteSpace(); optList = QCStringList::split(',',optStr); } - auto it = docCmdMap.find(cmdName.data()); - if (it!=docCmdMap.end()) // special action is required - { + auto it = docCmdMap.find(cmdName.data()); + if (it!=docCmdMap.end()) // special action is required + { int i=0; while (yytext[i]==' ' || yytext[i]=='\t') i++; - yyextra->spaceBeforeCmd = QCString(yytext).left(i); - if (it->second.endsBrief && !(yyextra->inContext==OutputXRef && cmdName=="parblock")) - { - yyextra->briefEndsAtDot=FALSE; - // this command forces the end of brief description - setOutput(yyscanner,OutputDoc); - } + yyextra->spaceBeforeCmd = QCString(yytext).left(i); + if (it->second.spacing==CommandSpacing::Block && !(yyextra->inContext==OutputXRef && cmdName=="parblock")) + { + yyextra->briefEndsAtDot=FALSE; + // this command forces the end of brief description + setOutput(yyscanner,OutputDoc); + } //if (i>0) addOutput(yyscanner,QCString(yytext).left(i)); // removed for bug 689341 - if (it->second.handler && it->second.handler(yyscanner, cmdName, optList)) - { - // implicit split of the comment block into two - // entries. Restart the next block at the start - // of this command. - yyextra->parseMore=TRUE; - - // yuk, this is probably not very portable across lex implementations, - // but we need to know the position in the input buffer where this - // rule matched. - // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE + if (it->second.handler && it->second.handler(yyscanner, cmdName, optList)) + { + // implicit split of the comment block into two + // entries. Restart the next block at the start + // of this command. + yyextra->parseMore=TRUE; + + // yuk, this is probably not very portable across lex implementations, + // but we need to know the position in the input buffer where this + // rule matched. + // for flex 2.5.33+ we should use YY_CURRENT_BUFFER_LVALUE #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33)) - yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); + yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf); #else - yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf); + yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf); #endif - yyterminate(); - } - else if (it->second.handler==0) - { - // command without handler, to be processed - // later by parsedoc.cpp - addOutput(yyscanner,yytext); - } - } - else // command not relevant - { - addOutput(yyscanner,yytext); - } - } -<Comment>{B}*({CMD}{CMD})"f"[$\[{] { // escaped formula command - addOutput(yyscanner,yytext); - } -<Comment>{B}*{CMD}"~"[a-z_A-Z-]* { // language switch command + yyterminate(); + } + else if (it->second.handler==0) + { + // command without handler, to be processed + // later by parsedoc.cpp + addOutput(yyscanner,yytext); + } + } + else // command not relevant + { + addOutput(yyscanner,yytext); + } + } +<Comment>{B}*({CMD}{CMD})"f"[$\[{] { // escaped formula command + addOutput(yyscanner,yytext); + } +<Comment>{B}*{CMD}"~"[a-z_A-Z-]* { // language switch command QCString langId = QCString(yytext).stripWhiteSpace().data()+2; - if (!langId.isEmpty() && - qstricmp(Config_getEnum(OUTPUT_LANGUAGE),langId)!=0) - { // enable language specific section - BEGIN(SkipLang); - } - } + if (!langId.isEmpty() && + qstricmp(Config_getEnum(OUTPUT_LANGUAGE),langId)!=0) + { // enable language specific section + BEGIN(SkipLang); + } + } <Comment>{B}*{CMD}"f{"[^}\n]+"}"("{"?) { // start of a formula with custom environment - setOutput(yyscanner,OutputDoc); - yyextra->formulaText="\\begin"; - yyextra->formulaEnv=QCString(yytext).stripWhiteSpace().data()+2; - if (yyextra->formulaEnv.at(yyextra->formulaEnv.length()-1)=='{') - { - // remove trailing open brace - yyextra->formulaEnv=yyextra->formulaEnv.left(yyextra->formulaEnv.length()-1); - } - yyextra->formulaText+=yyextra->formulaEnv; - yyextra->formulaNewLines=0; - BEGIN(ReadFormulaLong); - } -<Comment>{B}*{CMD}"f$" { // start of a inline formula - yyextra->formulaText="$"; - yyextra->formulaNewLines=0; - BEGIN(ReadFormulaShort); - } -<Comment>{B}*{CMD}"f[" { // start of a block formula - setOutput(yyscanner,OutputDoc); - yyextra->formulaText="\\["; - yyextra->formulaNewLines=0; - BEGIN(ReadFormulaLong); - } + setOutput(yyscanner,OutputDoc); + yyextra->formulaText="\\begin"; + yyextra->formulaEnv=QCString(yytext).stripWhiteSpace().data()+2; + if (yyextra->formulaEnv.at(yyextra->formulaEnv.length()-1)=='{') + { + // remove trailing open brace + yyextra->formulaEnv=yyextra->formulaEnv.left(yyextra->formulaEnv.length()-1); + } + yyextra->formulaText+=yyextra->formulaEnv; + yyextra->formulaNewLines=0; + BEGIN(ReadFormulaLong); + } +<Comment>{B}*{CMD}"f$" { // start of a inline formula + yyextra->formulaText="$"; + yyextra->formulaNewLines=0; + BEGIN(ReadFormulaShort); + } +<Comment>{B}*{CMD}"f[" { // start of a block formula + setOutput(yyscanner,OutputDoc); + yyextra->formulaText="\\["; + yyextra->formulaNewLines=0; + BEGIN(ReadFormulaLong); + } <Comment>{B}*{CMD}"{" { // begin of a group //yyextra->langParser->handleGroupStartCommand(yyextra->memberGroupHeader); yyextra->docGroup.open(yyextra->current,yyextra->fileName,yyextra->lineNr); @@ -735,51 +753,51 @@ RCSTAG "$"{ID}":"[^\n$]+"$" <Comment>{B}*{CMD}"}" { // end of a group //yyextra->langParser->handleGroupEndCommand(); yyextra->docGroup.close(yyextra->current,yyextra->fileName,yyextra->lineNr,TRUE); - yyextra->docGroup.clearHeader(); - yyextra->parseMore=TRUE; + yyextra->docGroup.clearHeader(); + yyextra->parseMore=TRUE; yyextra->needNewEntry = TRUE; #if YY_FLEX_MAJOR_VERSION>=2 && (YY_FLEX_MINOR_VERSION>5 || (YY_FLEX_MINOR_VERSION==5 && YY_FLEX_SUBMINOR_VERSION>=33)) - yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + (int)strlen(yytext); + yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf) + (int)strlen(yytext); #else - yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf) + (int)strlen(yytext); + yyextra->inputPosition=yyextra->prevPosition + (int)(yy_bp - yy_current_buffer->yy_ch_buf) + (int)strlen(yytext); #endif - yyterminate(); - } -<Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character - addOutput(yyscanner,yytext); - } -<Comment>[a-z_A-Z]+ { // normal word - addOutput(yyscanner,yytext); - } + yyterminate(); + } +<Comment>{B}*{CMD}[$@\\&~<>#%] { // escaped character + addOutput(yyscanner,yytext); + } +<Comment>[a-z_A-Z]+ { // normal word + addOutput(yyscanner,yytext); + } <Comment>^{B}*"."{B}*/\n { // explicit end autolist: e.g " ." - addOutput(yyscanner,yytext); - } + addOutput(yyscanner,yytext); + } <Comment>^{B}*[1-9][0-9]*"."{B}+ | -<Comment>^{B}*[*+]{B}+ { // start of autolist - if (!Doxygen::markdownSupport) +<Comment>^{B}*[*+]{B}+ { // start of autolist + if (!yyextra->markdownSupport) { REJECT; } else { - if (yyextra->inContext!=OutputXRef) + if (yyextra->inContext!=OutputXRef) { yyextra->briefEndsAtDot=FALSE; setOutput(yyscanner,OutputDoc); } - addOutput(yyscanner,yytext); + addOutput(yyscanner,yytext); } - } -<Comment>^{B}*"-"{B}+ { // start of autolist - if (yyextra->inContext!=OutputXRef) - { - yyextra->briefEndsAtDot=FALSE; - setOutput(yyscanner,OutputDoc); - } - addOutput(yyscanner,yytext); - } + } +<Comment>^{B}*"-"{B}+ { // start of autolist + if (yyextra->inContext!=OutputXRef) + { + yyextra->briefEndsAtDot=FALSE; + setOutput(yyscanner,OutputDoc); + } + addOutput(yyscanner,yytext); + } <Comment>^{B}*([\-:|]{B}*)*("--"|"---")({B}*[\-:|])*{B}*/\n { // horizontal line (dashed) - addOutput(yyscanner,yytext); + addOutput(yyscanner,yytext); } <Comment>{CMD}"---" { // escaped mdash addOutput(yyscanner,yytext); @@ -788,10 +806,10 @@ RCSTAG "$"{ID}":"[^\n$]+"$" addOutput(yyscanner,yytext); } <Comment>"---" { // mdash - addOutput(yyscanner,yyextra->insidePre || Doxygen::markdownSupport ? yytext : "—"); + addOutput(yyscanner,yyextra->insidePre || yyextra->markdownSupport ? yytext : "—"); } <Comment>"--" { // ndash - addOutput(yyscanner,yyextra->insidePre || Doxygen::markdownSupport ? yytext : "–"); + addOutput(yyscanner,yyextra->insidePre || yyextra->markdownSupport ? yytext : "–"); } <Comment>"-#"{B}+ { // numbered item if (yyextra->inContext!=OutputXRef) @@ -801,85 +819,85 @@ RCSTAG "$"{ID}":"[^\n$]+"$" } addOutput(yyscanner,yytext); } -<Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis - addOutput(yyscanner,yytext); - } -<Comment>".\\"[ \t] { // . with escaped space. - addOutput(yyscanner,yytext[0]); - addOutput(yyscanner,yytext[2]); - } -<Comment>".," { // . with comma such as "e.g.," - addOutput(yyscanner,yytext); - } -<Comment>"...\\"[ \t] { // ellipsis with escaped space. - addOutput(yyscanner,"... "); - } -<Comment>".."[\.]?/[^ \t\n] { // internal ellipsis - addOutput(yyscanner,yytext); - } -<Comment>(\n|\\_linebr)({B}*(\n|\\_linebr))+ { // at least one blank line (or blank line command) - if (yyextra->inContext==OutputXRef) - { - // see bug 613024, we need to put the newlines after ending the XRef section. - if (!yyextra->insideParBlock) setOutput(yyscanner,OutputDoc); +<Comment>("."+)[a-z_A-Z0-9\)] { // . at start or in the middle of a word, or ellipsis + addOutput(yyscanner,yytext); + } +<Comment>".\\"[ \t] { // . with escaped space. + addOutput(yyscanner,yytext[0]); + addOutput(yyscanner,yytext[2]); + } +<Comment>".," { // . with comma such as "e.g.," + addOutput(yyscanner,yytext); + } +<Comment>"...\\"[ \t] { // ellipsis with escaped space. + addOutput(yyscanner,"... "); + } +<Comment>".."[\.]?/[^ \t\n] { // internal ellipsis + addOutput(yyscanner,yytext); + } +<Comment>(\n|\\ilinebr)({B}*(\n|\\ilinebr))+ { // at least one blank line (or blank line command) + if (yyextra->inContext==OutputXRef) + { + // see bug 613024, we need to put the newlines after ending the XRef section. + if (!yyextra->insideParBlock) setOutput(yyscanner,OutputDoc); yy_size_t i; for (i=0;i<(yy_size_t)yyleng;) { if (yytext[i]=='\n') addOutput(yyscanner,'\n'),i++; - else if (strcmp(yytext+i,"\\_linebr")==0) addOutput(yyscanner,'\n'),i+=8; + else if (strcmp(yytext+i,"\\ilinebr")==0) addOutput(yyscanner,"\\ilinebr"),i+=8; else i++; } - } - else if (yyextra->inContext!=OutputBrief) - { + } + else if (yyextra->inContext!=OutputBrief) + { yy_size_t i; for (i=0;i<(yy_size_t)yyleng;) { if (yytext[i]=='\n') addOutput(yyscanner,'\n'),i++; - else if (strcmp(yytext+i,"\\_linebr")==0) addOutput(yyscanner,'\n'),i+=8; + else if (strcmp(yytext+i,"\\ilinebr")==0) addOutput(yyscanner,"\\ilinebr"),i+=8; else i++; } - setOutput(yyscanner,OutputDoc); - } - else // yyextra->inContext==OutputBrief - { // only go to the detailed description if we have - // found some brief description and not just whitespace - endBrief(yyscanner,FALSE); - } - lineCount(yyscanner); - } -<Comment>"." { // potential end of a JavaDoc style comment - addOutput(yyscanner,*yytext); - if (yyextra->briefEndsAtDot) - { - setOutput(yyscanner,OutputDoc); - yyextra->briefEndsAtDot=FALSE; - } - } -<Comment>\n { // newline - addOutput(yyscanner,*yytext); - yyextra->lineNr++; - } -<Comment>. { // catch-all for anything else - addOutput(yyscanner,*yytext); - } + setOutput(yyscanner,OutputDoc); + } + else // yyextra->inContext==OutputBrief + { // only go to the detailed description if we have + // found some brief description and not just whitespace + endBrief(yyscanner,FALSE); + } + lineCount(yyscanner); + } +<Comment>"." { // potential end of a JavaDoc style comment + addOutput(yyscanner,*yytext); + if (yyextra->briefEndsAtDot) + { + setOutput(yyscanner,OutputDoc); + yyextra->briefEndsAtDot=FALSE; + } + } +<Comment>\n { // newline + addOutput(yyscanner,*yytext); + yyextra->lineNr++; + } +<Comment>. { // catch-all for anything else + addOutput(yyscanner,*yytext); + } /* -------------- Rules for handling HTML comments ----------- */ -<HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); } -<HtmlComment>{DOCNL} { - if (*yytext=='\n') yyextra->lineNr++; - } -<HtmlComment>[^\\\n\-]+ { // ignore unimportant characters - } -<HtmlComment>. { // ignore every else - } +<HtmlComment>"--"[!]?">"{B}* { BEGIN( Comment ); } +<HtmlComment>{DOCNL} { + if (*yytext=='\n') yyextra->lineNr++; + } +<HtmlComment>[^\\\n\-]+ { // ignore unimportant characters + } +<HtmlComment>. { // ignore every else + } <CdataSection>"\]\]>" { BEGIN( Comment ); } -<CdataSection>{DOCNL} { +<CdataSection>{DOCNL} { addOutput(yyscanner,'\n'); if (*yytext=='\n') yyextra->lineNr++; } @@ -890,262 +908,272 @@ RCSTAG "$"{ID}":"[^\n$]+"$" <CdataSection>[^\\\n\]<>&]+ { addOutput(yyscanner,yytext); } -<CdataSection>. { +<CdataSection>. { addOutput(yyscanner,*yytext); } /* -------------- Rules for handling formulas ---------------- */ - -<ReadFormulaShort>{CMD}"f$" { // end of inline formula - yyextra->formulaText+="$"; - addOutput(yyscanner," "+addFormula(yyscanner)); - BEGIN(Comment); - } -<ReadFormulaLong>{CMD}"f]" { // end of block formula - yyextra->formulaText+="\\]"; - addOutput(yyscanner," "+addFormula(yyscanner)); - BEGIN(Comment); - } -<ReadFormulaLong>{CMD}"f}" { // end of custom env formula - yyextra->formulaText+="\\end"; - yyextra->formulaText+=yyextra->formulaEnv; - addOutput(yyscanner," "+addFormula(yyscanner)); - BEGIN(Comment); - } + +<ReadFormulaShort>{CMD}"f$" { // end of inline formula + yyextra->formulaText+="$"; + addOutput(yyscanner," "+addFormula(yyscanner)); + BEGIN(Comment); + } +<ReadFormulaLong>{CMD}"f]" { // end of block formula + yyextra->formulaText+="\\]"; + addOutput(yyscanner," "+addFormula(yyscanner)); + BEGIN(Comment); + } +<ReadFormulaLong>{CMD}"f}" { // end of custom env formula + yyextra->formulaText+="\\end"; + yyextra->formulaText+=yyextra->formulaEnv; + addOutput(yyscanner," "+addFormula(yyscanner)); + BEGIN(Comment); + } <ReadFormulaLong,ReadFormulaShort>[^\\@\n]+ { // any non-special character - yyextra->formulaText+=yytext; - } -<ReadFormulaLong,ReadFormulaShort>\n { // new line + yyextra->formulaText+=yytext; + } +<ReadFormulaLong,ReadFormulaShort>\n { // new line yyextra->formulaNewLines++; - yyextra->formulaText+=*yytext; - yyextra->lineNr++; - } + yyextra->formulaText+=*yytext; + yyextra->lineNr++; + } <ReadFormulaLong,ReadFormulaShort>. { // any other character - yyextra->formulaText+=*yytext; - } + yyextra->formulaText+=*yytext; + } /* ------------ handle argument of enum command --------------- */ -<EnumDocArg1>{SCOPEID} { // handle argument - yyextra->current->name = yytext; - BEGIN( Comment ); - } -<EnumDocArg1>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); +<EnumDocArg1>{SCOPEID} { // handle argument + yyextra->current->name = yytext; + BEGIN( Comment ); + } +<EnumDocArg1>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); } -<EnumDocArg1>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, +<EnumDocArg1>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, "missing argument after \\enum." ); - addOutput(yyscanner,'\n'); - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<EnumDocArg1>. { // ignore other stuff - } + unput('\n'); + //addOutput(yyscanner,'\n'); + //if (*yytext=='\n') yyextra->lineNr++; + BEGIN( Comment ); + } +<EnumDocArg1>. { // ignore other stuff + } /* ------------ handle argument of namespace command --------------- */ -<NameSpaceDocArg1>{SCOPENAME} { // handle argument - yyextra->current->name = substitute(yytext,".","::"); - BEGIN( Comment ); - } -<NameSpaceDocArg1>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); +<NameSpaceDocArg1>{SCOPENAME} { // handle argument + yyextra->current->name = substitute(yytext,".","::"); + BEGIN( Comment ); + } +<NameSpaceDocArg1>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); } -<NameSpaceDocArg1>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, +<NameSpaceDocArg1>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, "missing argument after " - "\\namespace." + "\\namespace." ); - addOutput(yyscanner,'\n'); - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<NameSpaceDocArg1>. { // ignore other stuff - } + unput('\n'); + //addOutput(yyscanner,'\n'); + //if (*yytext=='\n') yyextra->lineNr++; + BEGIN( Comment ); + } +<NameSpaceDocArg1>. { // ignore other stuff + } /* ------------ handle argument of package command --------------- */ -<PackageDocArg1>{ID}("."{ID})* { // handle argument - yyextra->current->name = yytext; - BEGIN( Comment ); - } -<PackageDocArg1>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); +<PackageDocArg1>{ID}("."{ID})* { // handle argument + yyextra->current->name = yytext; + BEGIN( Comment ); } -<PackageDocArg1>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, +<PackageDocArg1>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<PackageDocArg1>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, "missing argument after " - "\\package." + "\\package." ); - addOutput(yyscanner,'\n'); - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<PackageDocArg1>. { // ignore other stuff - } + unput('\n'); + //addOutput(yyscanner,'\n'); + //if (*yytext=='\n') yyextra->lineNr++; + BEGIN( Comment ); + } +<PackageDocArg1>. { // ignore other stuff + } /* ------ handle argument of class/struct/union command --------------- */ -<ClassDocArg1>{SCOPENAME}{TMPLSPEC} { - yyextra->current->name = substitute(removeRedundantWhiteSpace(yytext),".","::"); - BEGIN( ClassDocArg2 ); - } -<ClassDocArg1>{SCOPENAME} { // first argument - yyextra->current->name = substitute(yytext,".","::"); - if (yyextra->current->section==Entry::PROTOCOLDOC_SEC) - { - yyextra->current->name+="-p"; - } - // prepend outer scope name - BEGIN( ClassDocArg2 ); - } +<ClassDocArg1>{SCOPENAME}{TMPLSPEC} { + yyextra->current->name = substitute(removeRedundantWhiteSpace(yytext),".","::"); + BEGIN( ClassDocArg2 ); + } +<ClassDocArg1>{SCOPENAME} { // first argument + yyextra->current->name = substitute(yytext,".","::"); + if (yyextra->current->section==Entry::PROTOCOLDOC_SEC) + { + yyextra->current->name+="-p"; + } + // prepend outer scope name + BEGIN( ClassDocArg2 ); + } <CategoryDocArg1>{SCOPENAME}{B}*"("[^\)]+")" { - yyextra->current->name = substitute(yytext,".","::"); - BEGIN( ClassDocArg2 ); - } + yyextra->current->name = substitute(yytext,".","::"); + BEGIN( ClassDocArg2 ); + } <ClassDocArg1,CategoryDocArg1>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); + yyextra->lineNr++; + addOutput(yyscanner,'\n'); } -<ClassDocArg1,CategoryDocArg1>{DOCNL} { - warn(yyextra->fileName,yyextra->lineNr, +<ClassDocArg1,CategoryDocArg1>{DOCNL} { + warn(yyextra->fileName,yyextra->lineNr, "missing argument after " - "\\%s.",YY_START==ClassDocArg1?"class":"category" + "'\\%s'.",yyextra->currentCmd.data() ); - addOutput(yyscanner,'\n'); - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<ClassDocArg1,CategoryDocArg1>. { // ignore other stuff - } - -<ClassDocArg2>{FILE}|"<>" { // second argument; include file - yyextra->current->includeFile = yytext; - BEGIN( ClassDocArg3 ); - } -<ClassDocArg2>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<ClassDocArg2>{DOCNL} { - addOutput(yyscanner,'\n'); - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<ClassDocArg2>. { // ignore other stuff - } - -<ClassDocArg3>[<"]?{FILE}?[">]? { // third argument; include file name - yyextra->current->includeName = yytext; - BEGIN( Comment ); - } -<ClassDocArg3>{LC} { // line continuation + //addOutput(yyscanner,'\n'); + //if (*yytext=='\n') yyextra->lineNr++; + unput('\n'); + BEGIN( Comment ); + } +<ClassDocArg1,CategoryDocArg1>. { // ignore other stuff + } + +<ClassDocArg2>{FILE}|"<>" { // second argument; include file + yyextra->current->includeFile = yytext; + BEGIN( ClassDocArg3 ); + } +<ClassDocArg2>{LC} { // line continuation yyextra->lineNr++; - addOutput(yyscanner,'\n'); + addOutput(yyscanner,'\n'); + } +<ClassDocArg2>{DOCNL} { + //addOutput(yyscanner,'\n'); + //if (*yytext=='\n') yyextra->lineNr++; + unput('\n'); + BEGIN( Comment ); + } +<ClassDocArg2>. { // ignore other stuff + } + +<ClassDocArg3>[<"]?{FILE}?[">]? { // third argument; include file name + yyextra->current->includeName = yytext; + BEGIN( Comment ); + } +<ClassDocArg3>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<ClassDocArg3>{DOCNL} { + //if (*yytext=='\n') yyextra->lineNr++; + unput('\n'); + BEGIN( Comment ); + } +<ClassDocArg3>. { // ignore other stuff } -<ClassDocArg3>{DOCNL} { - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<ClassDocArg3>. { // ignore other stuff - } /* --------- handle arguments of {def,add,weak}group commands --------- */ -<GroupDocArg1>{LABELID}(".html"?) { // group name - yyextra->current->name = yytext; - //lastDefGroup.groupname = yytext; - //lastDefGroup.pri = yyextra->current->groupingPri(); - // the .html stuff is for Qt compatibility - if (yyextra->current->name.right(5)==".html") - { - yyextra->current->name=yyextra->current->name.left(yyextra->current->name.length()-5); - } - yyextra->current->type.resize(0); - BEGIN(GroupDocArg2); - } -<GroupDocArg1>"\\"{B}*"\n" { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<GroupDocArg1>{DOCNL} { // missing argument! - warn(yyextra->fileName,yyextra->lineNr, +<GroupDocArg1>{LABELID}(".html"?) { // group name + yyextra->current->name = yytext; + //lastDefGroup.groupname = yytext; + //lastDefGroup.pri = yyextra->current->groupingPri(); + // the .html stuff is for Qt compatibility + if (yyextra->current->name.right(5)==".html") + { + yyextra->current->name=yyextra->current->name.left(yyextra->current->name.length()-5); + } + yyextra->current->type.resize(0); + BEGIN(GroupDocArg2); + } +<GroupDocArg1>"\\"{B}*"\n" { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<GroupDocArg1>{DOCNL} { // missing argument! + warn(yyextra->fileName,yyextra->lineNr, "missing group name after %s", - yyextra->current->groupDocCmd() + yyextra->current->groupDocCmd() ); - addOutput(yyscanner,'\n'); - if (*yytext=='\n') yyextra->lineNr++; - BEGIN( Comment ); - } -<GroupDocArg1>. { // ignore other stuff - } -<GroupDocArg2>"\\"{B}*"\n" { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<GroupDocArg2>[^\n\\]+ { // title (stored in type) - yyextra->current->type += yytext; - yyextra->current->type = yyextra->current->type.stripWhiteSpace(); - } -<GroupDocArg2>{DOCNL} { + //addOutput(yyscanner,'\n'); + //if (*yytext=='\n') yyextra->lineNr++; + unput('\n'); + BEGIN( Comment ); + } +<GroupDocArg1>. { // ignore other stuff + } +<GroupDocArg2>"\\"{B}*"\n" { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<GroupDocArg2>[^\n\\]+ { // title (stored in type) + yyextra->current->type += yytext; + yyextra->current->type = yyextra->current->type.stripWhiteSpace(); + } +<GroupDocArg2>{DOCNL} { if ( yyextra->current->groupDocType==Entry::GROUPDOC_NORMAL && - yyextra->current->type.isEmpty() - ) // defgroup requires second argument - { - warn(yyextra->fileName,yyextra->lineNr, + yyextra->current->type.isEmpty() + ) // defgroup requires second argument + { + warn(yyextra->fileName,yyextra->lineNr, "missing title after " - "\\defgroup %s", yyextra->current->name.data() + "\\defgroup %s", yyextra->current->name.data() ); - } - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } + } + unput('\n'); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } <GroupDocArg2>. { // title (stored in type) - yyextra->current->type += yytext; - yyextra->current->type = yyextra->current->type.stripWhiteSpace(); + yyextra->current->type += yytext; + yyextra->current->type = yyextra->current->type.stripWhiteSpace(); } /* --------- handle arguments of page/mainpage command ------------------- */ -<PageDocArg1>{FILE} { // first argument; page name - yyextra->current->name = stripQuotes(yytext); - yyextra->current->args = ""; - BEGIN( PageDocArg2 ); - } -<PageDocArg1>{LC} { yyextra->lineNr++; - addOutput(yyscanner,'\n'); +<PageDocArg1>{FILE} { // first argument; page name + yyextra->current->name = stripQuotes(yytext); + yyextra->current->args = ""; + BEGIN( PageDocArg2 ); + } +<PageDocArg1>{LC} { yyextra->lineNr++; + addOutput(yyscanner,'\n'); } -<PageDocArg1>{DOCNL} { - warn(yyextra->fileName,yyextra->lineNr, +<PageDocArg1>{DOCNL} { + warn(yyextra->fileName,yyextra->lineNr, "missing argument after " - "\\page." + "\\page." ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<PageDocArg1>. { // ignore other stuff - } -<PageDocArg2>{DOCNL} { // second argument; page title - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<PageDocArg2>{CMD}[<>] { - // bug 748927 - QCString tmp = yytext; - tmp = substitute(substitute(tmp,"@<","<"),"@>",">"); - tmp = substitute(substitute(tmp,"\\<","<"),"\\>",">"); - yyextra->current->args += tmp; - } -<PageDocArg2>. { - yyextra->current->args += yytext; + unput('\n'); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<PageDocArg1>. { // ignore other stuff + } +<PageDocArg2>{DOCNL} { // second argument; page title + unput('\n'); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<PageDocArg2>{CMD}[<>] { + // bug 748927 + QCString tmp = yytext; + tmp = substitute(substitute(tmp,"@<","<"),"@>",">"); + tmp = substitute(substitute(tmp,"\\<","<"),"\\>",">"); + yyextra->current->args += tmp; + } +<PageDocArg2>. { + yyextra->current->args += yytext; } /* --------- handle arguments of the param command ------------ */ <ParamArg1>{ID}/{B}*"," { @@ -1165,288 +1193,291 @@ RCSTAG "$"{ID}":"[^\n$]+"$" /* --------- handle arguments of the file/dir/example command ------------ */ -<FileDocArg1>{DOCNL} { // no file name specified - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<FileDocArg1>{FILE} { // first argument; name - yyextra->current->name = stripQuotes(yytext); - BEGIN( Comment ); - } -<FileDocArg1>{LC} { yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<FileDocArg1>. { // ignore other stuff - } +<FileDocArg1>{DOCNL} { // no file name specified + unput('\n'); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<FileDocArg1>{FILE} { // first argument; name + yyextra->current->name = stripQuotes(yytext); + BEGIN( Comment ); + } +<FileDocArg1>{LC} { yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<FileDocArg1>. { // ignore other stuff + } /* --------- handle arguments of the xrefitem command ------------ */ -<XRefItemParam1>{LABELID} { // first argument - yyextra->newXRefItemKey=yytext; +<XRefItemParam1>{LABELID} { // first argument + yyextra->newXRefItemKey=yytext; setOutput(yyscanner,OutputXRef); - BEGIN(XRefItemParam2); - } -<XRefItemParam1>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<XRefItemParam1>{DOCNL} { // missing arguments - warn(yyextra->fileName,yyextra->lineNr, - "Missing first argument of \\xrefitem" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - yyextra->inContext = OutputDoc; - BEGIN( Comment ); - } -<XRefItemParam1>. { // ignore other stuff - } - -<XRefItemParam2>"\""[^\n\"]*"\"" { // second argument - yyextra->xrefItemTitle = stripQuotes(yytext); - BEGIN(XRefItemParam3); - } -<XRefItemParam2>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<XRefItemParam2>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "Missing second argument of \\xrefitem" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - yyextra->inContext = OutputDoc; - BEGIN( Comment ); - } -<XRefItemParam2>. { // ignore other stuff - } - -<XRefItemParam3>"\""[^\n\"]*"\"" { // third argument - yyextra->xrefListTitle = stripQuotes(yytext); + BEGIN(XRefItemParam2); + } +<XRefItemParam1>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<XRefItemParam1>{DOCNL} { // missing arguments + warn(yyextra->fileName,yyextra->lineNr, + "Missing first argument of \\xrefitem" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + yyextra->inContext = OutputDoc; + BEGIN( Comment ); + } +<XRefItemParam1>. { // ignore other stuff + } + +<XRefItemParam2>"\""[^\n\"]*"\"" { // second argument + yyextra->xrefItemTitle = stripQuotes(yytext); + BEGIN(XRefItemParam3); + } +<XRefItemParam2>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<XRefItemParam2>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "Missing second argument of \\xrefitem" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + yyextra->inContext = OutputDoc; + BEGIN( Comment ); + } +<XRefItemParam2>. { // ignore other stuff + } + +<XRefItemParam3>"\""[^\n\"]*"\"" { // third argument + yyextra->xrefListTitle = stripQuotes(yytext); yyextra->xrefKind = XRef_Item; - BEGIN( Comment ); - } -<XRefItemParam2,XRefItemParam3>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<XRefItemParam3>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "Missing third argument of \\xrefitem" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - yyextra->inContext = OutputDoc; - BEGIN( Comment ); - } -<XRefItemParam3>. { // ignore other stuff - } + BEGIN( Comment ); + } +<XRefItemParam2,XRefItemParam3>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<XRefItemParam3>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "Missing third argument of \\xrefitem" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + yyextra->inContext = OutputDoc; + BEGIN( Comment ); + } +<XRefItemParam3>. { // ignore other stuff + } /* ----- handle arguments of the relates(also)/memberof command ------- */ -<RelatesParam1>({ID}("::"|"."))*{ID} { // argument - yyextra->current->relates = yytext; - //if (yyextra->current->mGrpId!=DOX_NOGROUP) +<RelatesParam1>({ID}("::"|"."))*{ID} { // argument + yyextra->current->relates = yytext; + //if (yyextra->current->mGrpId!=DOX_NOGROUP) //{ // memberGroupRelates = yytext; //} - BEGIN( Comment ); - } -<RelatesParam1>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<RelatesParam1>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "Missing argument of \\relates or \\memberof command" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<RelatesParam1>. { // ignore other stuff - } + BEGIN( Comment ); + } +<RelatesParam1>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<RelatesParam1>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "Missing argument of '\\%s' command",yyextra->currentCmd.data() + ); + unput('\n'); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<RelatesParam1>. { // ignore other stuff + } /* ----- handle arguments of the relates(also)/addindex commands ----- */ -<LineParam>{DOCNL} { // end of argument - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<LineParam>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<LineParam>. { // ignore other stuff - addOutput(yyscanner,*yytext); - } +<LineParam>{DOCNL} { // end of argument + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + unput('\n'); + BEGIN( Comment ); + } +<LineParam>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<LineParam>. { // ignore other stuff + addOutput(yyscanner,*yytext); + } /* ----- handle arguments of the section/subsection/.. commands ------- */ -<SectionLabel>{LABELID} { // first argument - yyextra->sectionLabel=yytext; +<SectionLabel>{LABELID} { // first argument + yyextra->sectionLabel=yytext; addOutput(yyscanner,yytext); - yyextra->sectionTitle.resize(0); - BEGIN(SectionTitle); - } -<SectionLabel>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "\\section command has no label" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<SectionLabel>. { // invalid character for section label - warn(yyextra->fileName,yyextra->lineNr, - "Invalid or missing section label" - ); - BEGIN(Comment); - } + yyextra->sectionTitle.resize(0); + BEGIN(SectionTitle); + } +<SectionLabel>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "\\section command has no label" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<SectionLabel>. { // invalid character for section label + warn(yyextra->fileName,yyextra->lineNr, + "Invalid or missing section label" + ); + BEGIN(Comment); + } <SectionTitle>[^\n@\\*]*/"\n" { // end of section title - addSection(yyscanner); + addSection(yyscanner); + addOutput(yyscanner,yytext); + BEGIN( Comment ); + } +<SectionTitle>[^\n@\\]*/"\\ilinebr" { // end of section title + addSection(yyscanner); + addOutput(yyscanner,yytext); + BEGIN( Comment ); + } +<SectionTitle>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<SectionTitle>[^\n@\\]* { // any character without special meaning + yyextra->sectionTitle+=yytext; addOutput(yyscanner,yytext); - BEGIN( Comment ); - } -<SectionTitle>[^\n@\\]*/"\\_linebr" { // end of section title - addSection(yyscanner); + } +<SectionTitle>({CMD}{CMD}){ID} { // unescape escaped command + yyextra->sectionTitle+=&yytext[1]; + addOutput(yyscanner,yytext); + } +<SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character + yyextra->sectionTitle+=yytext[1]; addOutput(yyscanner,yytext); - BEGIN( Comment ); - } -<SectionTitle>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<SectionTitle>[^\n@\\]* { // any character without special meaning - yyextra->sectionTitle+=yytext; - addOutput(yyscanner,yytext); - } -<SectionTitle>({CMD}{CMD}){ID} { // unescape escaped command - yyextra->sectionTitle+=&yytext[1]; - addOutput(yyscanner,yytext); - } -<SectionTitle>{CMD}[$@\\&~<>#%] { // unescape escaped character - yyextra->sectionTitle+=yytext[1]; - addOutput(yyscanner,yytext); - } -<SectionTitle>. { // anything else - yyextra->sectionTitle+=yytext; - addOutput(yyscanner,*yytext); - } + } +<SectionTitle>. { // anything else + yyextra->sectionTitle+=yytext; + addOutput(yyscanner,*yytext); + } /* ----- handle arguments of the subpage command ------- */ -<SubpageLabel>{LABELID} { // first argument +<SubpageLabel>{LABELID} { // first argument + addOutput(yyscanner,yytext); + // we add subpage labels as a kind of "inheritance" relation to prevent + // needing to add another list to the Entry class. + yyextra->current->extends.push_back(BaseInfo(yytext,Public,Normal)); + BEGIN(SubpageTitle); + } +<SubpageLabel>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "\\subpage command has no label" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<SubpageTitle>{DOCNL} { // no title, end command + addOutput(yyscanner,yytext); + BEGIN( Comment ); + } +<SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command addOutput(yyscanner,yytext); - // we add subpage labels as a kind of "inheritance" relation to prevent - // needing to add another list to the Entry class. - yyextra->current->extends.push_back(BaseInfo(yytext,Public,Normal)); - BEGIN(SubpageTitle); - } -<SubpageLabel>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "\\subpage command has no label" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<SubpageTitle>{DOCNL} { // no title, end command - addOutput(yyscanner,yytext); - BEGIN( Comment ); - } -<SubpageTitle>[ \t]*"\""[^\"\n]*"\"" { // add title, end of command - addOutput(yyscanner,yytext); - BEGIN( Comment ); - } -<SubpageTitle>. { // no title, end of command - unput(*yytext); - BEGIN( Comment ); - } + BEGIN( Comment ); + } +<SubpageTitle>. { // no title, end of command + unput(*yytext); + BEGIN( Comment ); + } /* ----- handle arguments of the anchor command ------- */ -<AnchorLabel>{LABELID} { // found argument +<AnchorLabel>{LABELID} { // found argument addAnchor(yyscanner,yytext); - addOutput(yyscanner,yytext); - BEGIN( Comment ); - } -<AnchorLabel>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "\\anchor command has no label" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<AnchorLabel>. { // invalid character for anchor label - warn(yyextra->fileName,yyextra->lineNr, - "Invalid or missing anchor label" - ); - BEGIN(Comment); - } + addOutput(yyscanner,yytext); + BEGIN( Comment ); + } +<AnchorLabel>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "\\anchor command has no label" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<AnchorLabel>. { // invalid character for anchor label + warn(yyextra->fileName,yyextra->lineNr, + "Invalid or missing anchor label" + ); + BEGIN(Comment); + } /* ----- handle arguments of the preformatted block commands ------- */ <FormatBlock>{CMD}("endverbatim"|"endlatexonly"|"endhtmlonly"|"endxmlonly"|"enddocbookonly"|"endrtfonly"|"endmanonly"|"enddot"|"endcode"|"endmsc"|"endvhdlflow")/{NW} { // possible ends - addOutput(yyscanner,yytext); - if (&yytext[4]==yyextra->blockName) // found end of the block - { - BEGIN(Comment); - } - } + addOutput(yyscanner,yytext); + if (&yytext[4]==yyextra->blockName) // found end of the block + { + BEGIN(Comment); + } + } <FormatBlock>{CMD}"enduml" { - addOutput(yyscanner,yytext); - if (yyextra->blockName=="startuml") // found end of the block - { - BEGIN(Comment); - } - } -<FormatBlock>[^ \@\*\/\\\n]* { // some word - addOutput(yyscanner,yytext); - } -<FormatBlock>{DOCNL} { // new line - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<FormatBlock>"/*" { // start of a C-comment - if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim")) yyextra->commentCount++; - addOutput(yyscanner,yytext); - } -<FormatBlock>"*/" { // end of a C-comment - addOutput(yyscanner,yytext); - if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim")) + addOutput(yyscanner,yytext); + if (yyextra->blockName=="startuml") // found end of the block + { + BEGIN(Comment); + } + } +<FormatBlock>[^ \@\*\/\\\n]* { // some word + addOutput(yyscanner,yytext); + } +<FormatBlock>{DOCNL} { // new line + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<FormatBlock>"/*" { // start of a C-comment + if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim")) yyextra->commentCount++; + addOutput(yyscanner,yytext); + } +<FormatBlock>"*/" { // end of a C-comment + addOutput(yyscanner,yytext); + if (!(yyextra->blockName=="code" || yyextra->blockName=="verbatim")) { yyextra->commentCount--; - if (yyextra->commentCount<0) - { - warn(yyextra->fileName,yyextra->lineNr, - "found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",yyextra->blockName.data(),yyextra->blockName.data()); - } - } - } -<FormatBlock>. { - addOutput(yyscanner,*yytext); - } -<FormatBlock><<EOF>> { + if (yyextra->commentCount<0) + { + warn(yyextra->fileName,yyextra->lineNr, + "found */ without matching /* while inside a \\%s block! Perhaps a missing \\end%s?\n",yyextra->blockName.data(),yyextra->blockName.data()); + } + } + } +<FormatBlock>. { + addOutput(yyscanner,*yytext); + } +<FormatBlock><<EOF>> { QCString endTag = "end"+yyextra->blockName; if (yyextra->blockName=="startuml") endTag="enduml"; warn(yyextra->fileName,yyextra->lineNr, - "reached end of comment while inside a \\%s block; check for missing \\%s tag!", - yyextra->blockName.data(),endTag.data() - ); - yyterminate(); - } + "reached end of comment while inside a \\%s block; check for missing \\%s tag!", + yyextra->blockName.data(),endTag.data() + ); + yyterminate(); + } /* ----- handle arguments of if/ifnot commands ------- */ -<GuardParam>{B}*"(" { +<GuardParam>{B}*"(" { yyextra->guardExpr=yytext; yyextra->roundCount=1; BEGIN(GuardExpr); @@ -1467,383 +1498,388 @@ RCSTAG "$"{ID}":"[^\n$]+"$" } } <GuardExpr>\n { - warn(yyextra->fileName,yyextra->lineNr, - "invalid expression '%s' for yyextra->guards",yyextra->guardExpr.data()); + warn(yyextra->fileName,yyextra->lineNr, + "invalid expression '%s' for yyextra->guards",yyextra->guardExpr.data()); unput(*yytext); BEGIN(GuardParam); } -<GuardParam>{B}*[a-z_A-Z0-9.\-]+ { // parameter of if/ifnot yyextra->guards +<GuardParam>{B}*[a-z_A-Z0-9.\-]+ { // parameter of if/ifnot yyextra->guards handleGuard(yyscanner,yytext); - } -<GuardParam>{DOCNL} { // end of argument - if (*yytext=='\n') yyextra->lineNr++; - //next line is commented out due to bug620924 - //addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<GuardParam>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<GuardParam>. { // ignore other stuff - addOutput(yyscanner,*yytext); - } -<GuardParamEnd>{B}*{DOCNL} { - lineCount(yyscanner); - yyextra->spaceBeforeIf.resize(0); - BEGIN(Comment); - } -<GuardParamEnd>{B}* { - if (!yyextra->spaceBeforeIf.isEmpty()) // needed for 665313 in combination with bug620924 - { - addOutput(yyscanner,yyextra->spaceBeforeIf); - } - yyextra->spaceBeforeIf.resize(0); - BEGIN(Comment); - } -<GuardParamEnd>. { - unput(*yytext); - BEGIN(Comment); - } + } +<GuardParam>{DOCNL} { // end of argument + if (*yytext=='\n') yyextra->lineNr++; + //next line is commented out due to bug620924 + //addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<GuardParam>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<GuardParam>. { // ignore other stuff + addOutput(yyscanner,*yytext); + } +<GuardParamEnd>{B}*{DOCNL} { + lineCount(yyscanner); + yyextra->spaceBeforeIf.resize(0); + BEGIN(Comment); + } +<GuardParamEnd>{B}* { + if (!yyextra->spaceBeforeIf.isEmpty()) // needed for 665313 in combination with bug620924 + { + addOutput(yyscanner,yyextra->spaceBeforeIf); + } + yyextra->spaceBeforeIf.resize(0); + BEGIN(Comment); + } +<GuardParamEnd>. { + unput(*yytext); + BEGIN(Comment); + } /* ----- handle skipping of conditional sections ------- */ -<SkipGuardedSection>{CMD}"ifnot"/{NW} { +<SkipGuardedSection>{CMD}"ifnot"/{NW} { yyextra->guardType = Guard_IfNot; - BEGIN( GuardParam ); - } -<SkipGuardedSection>{CMD}"if"/{NW} { + BEGIN( GuardParam ); + } +<SkipGuardedSection>{CMD}"if"/{NW} { yyextra->guardType = Guard_If; - BEGIN( GuardParam ); - } -<SkipGuardedSection>{CMD}"endif"/{NW} { - if (yyextra->guards.empty()) - { - warn(yyextra->fileName,yyextra->lineNr, - "found \\endif without matching start command"); - } - else - { - GuardedSection s = yyextra->guards.top(); + BEGIN( GuardParam ); + } +<SkipGuardedSection>{CMD}"endif"/{NW} { + if (yyextra->guards.empty()) + { + warn(yyextra->fileName,yyextra->lineNr, + "found \\endif without matching start command"); + } + else + { + GuardedSection s = yyextra->guards.top(); yyextra->guards.pop(); bool parentVisible = s.parentVisible(); if (parentVisible) { - yyextra->enabledSectionFound=TRUE; - BEGIN( GuardParamEnd ); + yyextra->enabledSectionFound=TRUE; + BEGIN( GuardParamEnd ); + } + } + } +<SkipGuardedSection>{CMD}"else"/{NW} { + if (yyextra->guards.empty()) + { + warn(yyextra->fileName,yyextra->lineNr, + "found \\else without matching start command"); + } + else + { + if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible()) + { + yyextra->guards.pop(); + yyextra->guards.push(GuardedSection(TRUE,TRUE)); + yyextra->enabledSectionFound=TRUE; + BEGIN( GuardParamEnd ); } - } - } -<SkipGuardedSection>{CMD}"else"/{NW} { - if (yyextra->guards.empty()) - { - warn(yyextra->fileName,yyextra->lineNr, - "found \\else without matching start command"); - } - else - { - if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible()) - { - yyextra->guards.pop(); - yyextra->guards.push(GuardedSection(TRUE,TRUE)); - yyextra->enabledSectionFound=TRUE; - BEGIN( GuardParamEnd ); - } - } - } + } + } <SkipGuardedSection>{CMD}"elseif"/{NW} { - if (yyextra->guards.empty()) - { - warn(yyextra->fileName,yyextra->lineNr, - "found \\elseif without matching start command"); - } - else - { - if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible()) - { + if (yyextra->guards.empty()) + { + warn(yyextra->fileName,yyextra->lineNr, + "found \\elseif without matching start command"); + } + else + { + if (!yyextra->enabledSectionFound && yyextra->guards.top().parentVisible()) + { yyextra->guardType=Guard_If; - yyextra->guards.pop(); - BEGIN( GuardParam ); - } - } - } -<SkipGuardedSection>{DOCNL} { // skip line - if (*yytext=='\n') yyextra->lineNr++; - //addOutput(yyscanner,'\n'); - } -<SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters - } -<SkipGuardedSection>. { // any other character - } + yyextra->guards.pop(); + BEGIN( GuardParam ); + } + } + } +<SkipGuardedSection>{DOCNL} { // skip line + if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + } +<SkipGuardedSection>[^ \\@\n]+ { // skip non-special characters + } +<SkipGuardedSection>. { // any other character + } /* ----- handle skipping of internal section ------- */ -<SkipInternal>{DOCNL} { // skip line - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<SkipInternal>[@\\]"if"/[ \t] { +<SkipInternal>{DOCNL} { // skip line + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<SkipInternal>[@\\]"if"/[ \t] { yyextra->condCount++; - } -<SkipInternal>[@\\]"ifnot"/[ \t] { + } +<SkipInternal>[@\\]"ifnot"/[ \t] { yyextra->condCount++; - } -<SkipInternal>[@\\]/"endif" { + } +<SkipInternal>[@\\]/"endif" { yyextra->condCount--; - if (yyextra->condCount<0) // handle conditional section around of \internal, see bug607743 - { - unput('\\'); - BEGIN(Comment); - } - } -<SkipInternal>[@\\]/"section"[ \t] { - if (yyextra->sectionLevel>0) - { - unput('\\'); - BEGIN(Comment); - } - } -<SkipInternal>[@\\]/"subsection"[ \t] { - if (yyextra->sectionLevel>1) - { - unput('\\'); - BEGIN(Comment); - } - } -<SkipInternal>[@\\]/"subsubsection"[ \t] { - if (yyextra->sectionLevel>2) - { - unput('\\'); - BEGIN(Comment); - } - } -<SkipInternal>[@\\]/"paragraph"[ \t] { - if (yyextra->sectionLevel>3) - { - unput('\\'); - BEGIN(Comment); - } - } + if (yyextra->condCount<0) // handle conditional section around of \internal, see bug607743 + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"section"[ \t] { + if (yyextra->sectionLevel>0) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"subsection"[ \t] { + if (yyextra->sectionLevel>1) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"subsubsection"[ \t] { + if (yyextra->sectionLevel>2) + { + unput('\\'); + BEGIN(Comment); + } + } +<SkipInternal>[@\\]/"paragraph"[ \t] { + if (yyextra->sectionLevel>3) + { + unput('\\'); + BEGIN(Comment); + } + } <SkipInternal>[@\\]"endinternal"[ \t]* { - BEGIN(Comment); - } -<SkipInternal>[^ \\@\n]+ { // skip non-special characters - } -<SkipInternal>. { // any other character - } + BEGIN(Comment); + } +<SkipInternal>[^ \\@\n]+ { // skip non-special characters + } +<SkipInternal>. { // any other character + } /* ----- handle argument of name command ------- */ -<NameParam>{DOCNL} { // end of argument - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<NameParam>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - yyextra->docGroup.appendHeader(' '); - } -<NameParam>. { // ignore other stuff - yyextra->docGroup.appendHeader(*yytext); - yyextra->current->name+=*yytext; - } +<NameParam>{DOCNL} { // end of argument + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + unput('\n'); + BEGIN( Comment ); + } +<NameParam>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + yyextra->docGroup.appendHeader(' '); + } +<NameParam>. { // ignore other stuff + yyextra->docGroup.appendHeader(*yytext); + yyextra->current->name+=*yytext; + } /* ----- handle argument of noop command ------- */ -<Noop>{DOCNL} { // end of argument - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<Noop>. { // ignore other stuff - } +<Noop>{DOCNL} { // end of argument + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<Noop>. { // ignore other stuff + } /* ----- handle argument of ingroup command ------- */ -<InGroupParam>{LABELID} { // group id - yyextra->current->groups.push_back( - Grouping(yytext, Grouping::GROUPING_INGROUP) - ); - yyextra->inGroupParamFound=TRUE; - } -<InGroupParam>{DOCNL} { // missing argument - if (!yyextra->inGroupParamFound) - { - warn(yyextra->fileName,yyextra->lineNr, - "Missing group name for \\ingroup command" - ); - } - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<InGroupParam>{LC} { // line continuation - yyextra->lineNr++; - addOutput(yyscanner,'\n'); - } -<InGroupParam>. { // ignore other stuff - addOutput(yyscanner,*yytext); - } +<InGroupParam>{LABELID} { // group id + yyextra->current->groups.push_back( + Grouping(yytext, Grouping::GROUPING_INGROUP) + ); + yyextra->inGroupParamFound=TRUE; + } +<InGroupParam>{DOCNL} { // missing argument + if (!yyextra->inGroupParamFound) + { + warn(yyextra->fileName,yyextra->lineNr, + "Missing group name for \\ingroup command" + ); + } + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + unput('\n'); + BEGIN( Comment ); + } +<InGroupParam>{LC} { // line continuation + yyextra->lineNr++; + addOutput(yyscanner,'\n'); + } +<InGroupParam>. { // ignore other stuff + addOutput(yyscanner,*yytext); + } /* ----- handle argument of fn command ------- */ -<FnParam>{DOCNL} { // end of argument - if (yyextra->braceCount==0) - { - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - yyextra->langParser->parsePrototype(yyextra->functionProto); - BEGIN( Comment ); - } - } -<FnParam>{LC} { // line continuation - yyextra->lineNr++; - yyextra->functionProto+=' '; - } -<FnParam>[^@\\\n()]+ { // non-special characters +<FnParam>{DOCNL} { // end of argument + if (yyextra->braceCount==0) + { + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + unput('\n'); + yyextra->langParser->parsePrototype(yyextra->functionProto); + BEGIN( Comment ); + } + } +<FnParam>{LC} { // line continuation + yyextra->lineNr++; + yyextra->functionProto+=' '; + } +<FnParam>[^@\\\n()]+ { // non-special characters yyextra->functionProto+=yytext; - } -<FnParam>"(" { + } +<FnParam>"(" { yyextra->functionProto+=yytext; - yyextra->braceCount++; - } -<FnParam>")" { + yyextra->braceCount++; + } +<FnParam>")" { yyextra->functionProto+=yytext; - yyextra->braceCount--; - } -<FnParam>. { // add other stuff + yyextra->braceCount--; + } +<FnParam>. { // add other stuff yyextra->functionProto+=*yytext; - } + } /* ----- handle argument of overload command ------- */ -<OverloadParam>{DOCNL} { // end of argument - if (*yytext=='\n') yyextra->lineNr++; - if (yyextra->functionProto.stripWhiteSpace().isEmpty()) - { // plain overload command - addOutput(yyscanner,getOverloadDocs()); - addOutput(yyscanner,'\n'); - } - else // overload declaration - { +<OverloadParam>{DOCNL} { // end of argument + if (*yytext=='\n') yyextra->lineNr++; + if (yyextra->functionProto.stripWhiteSpace().isEmpty()) + { // plain overload command + addOutput(yyscanner,getOverloadDocs()); + addOutput(yyscanner,'\n'); + } + else // overload declaration + { makeStructuralIndicator(yyscanner,Entry::OVERLOADDOC_SEC); - yyextra->langParser->parsePrototype(yyextra->functionProto); - } - BEGIN( Comment ); - } -<OverloadParam>{LC} { // line continuation - yyextra->lineNr++; - yyextra->functionProto+=' '; - } -<OverloadParam>. { // add other stuff + yyextra->langParser->parsePrototype(yyextra->functionProto); + } + BEGIN( Comment ); + } +<OverloadParam>{LC} { // line continuation + yyextra->lineNr++; + yyextra->functionProto+=' '; + } +<OverloadParam>. { // add other stuff yyextra->functionProto+=*yytext; - } + } /* ----- handle argument of inherit command ------- */ -<InheritParam>({ID}("::"|"."))*{ID} { // found argument - yyextra->current->extends.push_back( - BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) - ); - BEGIN( Comment ); - } -<InheritParam>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "\\inherit command has no argument" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<InheritParam>. { // invalid character for anchor label - warn(yyextra->fileName,yyextra->lineNr, - "Invalid or missing name for \\inherit command" - ); - BEGIN(Comment); - } +<InheritParam>({ID}("::"|"."))*{ID} { // found argument + yyextra->current->extends.push_back( + BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) + ); + BEGIN( Comment ); + } +<InheritParam>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "\\inherit command has no argument" + ); + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + BEGIN( Comment ); + } +<InheritParam>. { // invalid character for anchor label + warn(yyextra->fileName,yyextra->lineNr, + "Invalid or missing name for \\inherit command" + ); + BEGIN(Comment); + } /* ----- handle argument of extends and implements commands ------- */ -<ExtendsParam>({ID}("::"|"."))*{ID} { // found argument - yyextra->current->extends.push_back( - BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) - ); - BEGIN( Comment ); - } -<ExtendsParam>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "\\extends or \\implements command has no argument" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<ExtendsParam>. { // ignore other stuff - } +<ExtendsParam>({ID}("::"|"."))*{ID} { // found argument + yyextra->current->extends.push_back( + BaseInfo(removeRedundantWhiteSpace(yytext),Public,Normal) + ); + BEGIN( Comment ); + } +<ExtendsParam>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "'\\%s' command has no argument",yyextra->currentCmd.data() + ); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + unput('\n'); + BEGIN( Comment ); + } +<ExtendsParam>. { // ignore other stuff + } /* ----- handle language specific sections ------- */ -<SkipLang>[\\@]"~"[a-zA-Z-]* { /* language switch */ - QCString langId = &yytext[2]; - if (langId.isEmpty() || - qstricmp(Config_getEnum(OUTPUT_LANGUAGE),langId)==0) - { // enable language specific section - BEGIN(Comment); - } - } -<SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */ - } -<SkipLang>{DOCNL} { /* new line in verbatim block */ - if (*yytext=='\n') yyextra->lineNr++; - } -<SkipLang>. { /* any other character */ - } +<SkipLang>[\\@]"~"[a-zA-Z-]* { /* language switch */ + QCString langId = &yytext[2]; + if (langId.isEmpty() || + qstricmp(Config_getEnum(OUTPUT_LANGUAGE),langId)==0) + { // enable language specific section + BEGIN(Comment); + } + } +<SkipLang>[^*@\\\n]* { /* any character not a *, @, backslash or new line */ + } +<SkipLang>{DOCNL} { /* new line in verbatim block */ + if (*yytext=='\n') yyextra->lineNr++; + } +<SkipLang>. { /* any other character */ + } /* ----- handle arguments of the cite command ------- */ -<CiteLabel>{CITEID} { // found argument - addCite(yyscanner); +<CiteLabel>{CITEID} { // found argument + addCite(yyscanner); addOutput(yyscanner,yytext); - BEGIN(Comment); - } -<CiteLabel>{DOCNL} { // missing argument - warn(yyextra->fileName,yyextra->lineNr, - "\\cite command has no label" - ); - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - BEGIN( Comment ); - } -<CiteLabel>. { // invalid character for cite label - warn(yyextra->fileName,yyextra->lineNr, - "Invalid or missing cite label" - ); - BEGIN(Comment); - } + BEGIN(Comment); + } +<CiteLabel>{DOCNL} { // missing argument + warn(yyextra->fileName,yyextra->lineNr, + "\\cite command has no label" + ); + //if (*yytext=='\n') yyextra->lineNr++; + //addOutput(yyscanner,'\n'); + unput('\n'); + BEGIN( Comment ); + } +<CiteLabel>. { // invalid character for cite label + warn(yyextra->fileName,yyextra->lineNr, + "Invalid or missing cite label" + ); + BEGIN(Comment); + } /* ----- handle argument of the copydoc command ------- */ -<CopyDoc><<EOF>> | -<CopyDoc>{DOCNL} { - if (*yytext=='\n') yyextra->lineNr++; - addOutput(yyscanner,'\n'); - setOutput(yyscanner,OutputDoc); +<CopyDoc><<EOF>> | +<CopyDoc>{DOCNL} { + if (*yytext=='\n') yyextra->lineNr++; + addOutput(yyscanner,'\n'); + setOutput(yyscanner,OutputDoc); addOutput(yyscanner," \\copydetails "); - addOutput(yyscanner,yyextra->copyDocArg); - addOutput(yyscanner,"\n"); - BEGIN(Comment); - } -<CopyDoc>[^\n\\]+ { - yyextra->copyDocArg+=yytext; - addOutput(yyscanner,yytext); - } -<CopyDoc>. { - yyextra->copyDocArg+=yytext; - addOutput(yyscanner,yytext); - } + addOutput(yyscanner,yyextra->copyDocArg); + addOutput(yyscanner,"\n"); + BEGIN(Comment); + } +<CopyDoc>[^\n\\]+ { + yyextra->copyDocArg+=yytext; + addOutput(yyscanner,yytext); + } +<CopyDoc>. { + yyextra->copyDocArg+=yytext; + addOutput(yyscanner,yytext); + } %% @@ -1897,7 +1933,6 @@ static bool handleDefGroup(yyscan_t yyscanner,const QCString &, const QCStringLi struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::GROUPDOC_SEC); yyextra->current->groupDocType = Entry::GROUPDOC_NORMAL; - setOutput(yyscanner,OutputBrief); BEGIN( GroupDocArg1 ); return stop; } @@ -1936,11 +1971,12 @@ static bool handlePackage(yyscan_t yyscanner,const QCString &, const QCStringLis return stop; } -static bool handleClass(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleClass(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::CLASSDOC_SEC); - BEGIN( ClassDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( ClassDocArg1 ); return stop; } @@ -1951,51 +1987,57 @@ static bool handleHeaderFile(yyscan_t yyscanner,const QCString &, const QCString return FALSE; } -static bool handleProtocol(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleProtocol(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { // Obj-C protocol struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::PROTOCOLDOC_SEC); - BEGIN( ClassDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( ClassDocArg1 ); return stop; } -static bool handleCategory(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleCategory(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { // Obj-C category struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::CATEGORYDOC_SEC); - BEGIN( CategoryDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( CategoryDocArg1 ); return stop; } -static bool handleUnion(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleUnion(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::UNIONDOC_SEC); - BEGIN( ClassDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( ClassDocArg1 ); return stop; } -static bool handleStruct(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleStruct(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::STRUCTDOC_SEC); - BEGIN( ClassDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( ClassDocArg1 ); return stop; } -static bool handleInterface(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleInterface(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::INTERFACEDOC_SEC); - BEGIN( ClassDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( ClassDocArg1 ); return stop; } -static bool handleIdlException(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleIdlException(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::EXCEPTIONDOC_SEC); - BEGIN( ClassDocArg1 ); + yyextra->currentCmd = cmd; + BEGIN( ClassDocArg1 ); return stop; } @@ -2012,7 +2054,7 @@ static bool handleMainpage(yyscan_t yyscanner,const QCString &, const QCStringLi struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::MAINPAGEDOC_SEC); yyextra->current->name = ""; - if (!stop) + if (!stop) { yyextra->current->name = "mainpage"; } @@ -2024,7 +2066,7 @@ static bool handleFile(yyscan_t yyscanner,const QCString &, const QCStringList & { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; bool stop=makeStructuralIndicator(yyscanner,Entry::FILEDOC_SEC); - if (!stop) + if (!stop) { yyextra->current->name = yyextra->fileName; } @@ -2074,7 +2116,7 @@ static bool handleExample(yyscan_t yyscanner,const QCString &cmd, const QCString else { warn(yyextra->fileName,yyextra->lineNr, - "unsupported option '%s' for command '\\%s'",qPrint(opt),qPrint(cmd)); + "unsupported option '%s' for command '\\%s'",qPrint(opt),qPrint(cmd)); } } bool stop=makeStructuralIndicator(yyscanner,section); @@ -2168,9 +2210,9 @@ static bool handleParBlock(yyscan_t yyscanner,const QCString &, const QCStringLi if (yyextra->insideParBlock) { warn(yyextra->fileName,yyextra->lineNr, - "found \\parblock command while already in a parblock!"); + "found \\parblock command while already in a parblock!"); } - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2186,7 +2228,7 @@ static bool handleEndParBlock(yyscan_t yyscanner,const QCString &, const QCStrin if (!yyextra->insideParBlock) { warn(yyextra->fileName,yyextra->lineNr, - "found \\endparblock command without matching \\parblock!"); + "found \\endparblock command without matching \\parblock!"); } addOutput(yyscanner,"@endparblock"); setOutput(yyscanner,OutputDoc); // to end a parblock inside a xrefitem like context @@ -2194,41 +2236,43 @@ static bool handleEndParBlock(yyscan_t yyscanner,const QCString &, const QCStrin return FALSE; } -static bool handleRelated(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleRelated(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (!yyextra->current->relates.isEmpty()) { warn(yyextra->fileName,yyextra->lineNr, - "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition"); + "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition"); } yyextra->current->relatesType = Simple; BEGIN(RelatesParam1); return FALSE; } -static bool handleRelatedAlso(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleRelatedAlso(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (!yyextra->current->relates.isEmpty()) { warn(yyextra->fileName,yyextra->lineNr, - "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition"); + "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition"); } yyextra->current->relatesType = Duplicate; + yyextra->currentCmd = cmd; BEGIN(RelatesParam1); return FALSE; } -static bool handleMemberOf(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleMemberOf(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; if (!yyextra->current->relates.isEmpty()) { warn(yyextra->fileName,yyextra->lineNr, - "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition"); + "found multiple \\relates, \\relatesalso or \\memberof commands in a comment block, using last definition"); } yyextra->current->relatesType = MemberOf; + yyextra->currentCmd = cmd; BEGIN(RelatesParam1); return FALSE; } @@ -2257,15 +2301,15 @@ static bool handleSection(yyscan_t yyscanner,const QCString &s, const QCStringLi static bool handleSubpage(yyscan_t yyscanner,const QCString &s, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; - if (yyextra->current->section!=Entry::EMPTY_SEC && + if (yyextra->current->section!=Entry::EMPTY_SEC && yyextra->current->section!=Entry::PAGEDOC_SEC && yyextra->current->section!=Entry::MAINPAGEDOC_SEC ) { warn(yyextra->fileName,yyextra->lineNr, - "found \\subpage command in a comment block that is not marked as a page!"); + "found \\subpage command in a comment block that is not marked as a page!"); } - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2286,7 +2330,7 @@ static bool handleAnchor(yyscan_t yyscanner,const QCString &s, const QCStringLis static bool handleCite(yyscan_t yyscanner,const QCString &s, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2348,7 +2392,7 @@ static bool handleElseIf(yyscan_t yyscanner,const QCString &, const QCStringList if (yyextra->guards.empty()) { warn(yyextra->fileName,yyextra->lineNr, - "found \\else without matching start command"); + "found \\else without matching start command"); } else { @@ -2365,7 +2409,7 @@ static bool handleElse(yyscan_t yyscanner,const QCString &, const QCStringList & if (yyextra->guards.empty()) { warn(yyextra->fileName,yyextra->lineNr, - "found \\else without matching start command"); + "found \\else without matching start command"); } else { @@ -2381,14 +2425,14 @@ static bool handleEndIf(yyscan_t yyscanner,const QCString &, const QCStringList if (yyextra->guards.empty()) { warn(yyextra->fileName,yyextra->lineNr, - "found \\endif without matching start command"); + "found \\endif without matching start command"); } else { yyextra->guards.pop(); } yyextra->enabledSectionFound=FALSE; - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2408,7 +2452,7 @@ static bool handleIngroup(yyscan_t yyscanner,const QCString &, const QCStringLis static bool handleNoSubGrouping(yyscan_t yyscanner,const QCString &, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; - yyextra->current->subGrouping = FALSE; + yyextra->current->subGrouping = FALSE; return FALSE; } @@ -2490,7 +2534,7 @@ static bool handleInternal(yyscan_t yyscanner,const QCString &, const QCStringLi // make sure some whitespace before a \internal command // is not treated as "documentation" if (yyextra->current->doc.stripWhiteSpace().isEmpty()) - { + { yyextra->current->doc.resize(0); } yyextra->condCount=0; @@ -2499,31 +2543,23 @@ static bool handleInternal(yyscan_t yyscanner,const QCString &, const QCStringLi else { // re-enabled for bug640828 - addOutput(yyscanner," \\internal "); + addOutput(yyscanner," \\internal "); yyextra->inInternalDocs = TRUE; } return FALSE; } -static bool handleLineBr(yyscan_t yyscanner,const QCString &, const QCStringList &) -{ - addOutput(yyscanner,'\n'); - return FALSE; -} - static bool handleStatic(yyscan_t yyscanner,const QCString &, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; - endBrief(yyscanner); - yyextra->current->stat = TRUE; + yyextra->current->stat = TRUE; return FALSE; } static bool handlePure(yyscan_t yyscanner,const QCString &, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; - endBrief(yyscanner); - yyextra->current->virt = Pure; + yyextra->current->virt = Pure; return FALSE; } @@ -2572,7 +2608,7 @@ static bool handlePublicSection(yyscan_t yyscanner,const QCString &, const QCStr static bool handleToc(yyscan_t yyscanner,const QCString &, const QCStringList &optList) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; - if (yyextra->current->section==Entry::PAGEDOC_SEC || + if (yyextra->current->section==Entry::PAGEDOC_SEC || yyextra->current->section==Entry::MAINPAGEDOC_SEC) { QCStringList::ConstIterator it; @@ -2637,9 +2673,10 @@ static bool handleInherit(yyscan_t yyscanner,const QCString &, const QCStringLis return FALSE; } -static bool handleExtends(yyscan_t yyscanner,const QCString &, const QCStringList &) +static bool handleExtends(yyscan_t yyscanner,const QCString &cmd, const QCStringList &) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; + yyextra->currentCmd = cmd; BEGIN(ExtendsParam); return FALSE; } @@ -2653,7 +2690,7 @@ static bool handleCopyBrief(yyscan_t yyscanner,const QCString &, const QCStringL // otherwise it will be copied inline (see bug691315 & bug700788) setOutput(yyscanner,OutputBrief); } - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2666,7 +2703,7 @@ static bool handleCopyDetails(yyscan_t yyscanner,const QCString &, const QCStrin { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; setOutput(yyscanner,OutputDoc); - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2679,7 +2716,7 @@ static bool handleCopyDoc(yyscan_t yyscanner,const QCString &, const QCStringLis { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; setOutput(yyscanner,OutputBrief); - if (!yyextra->spaceBeforeCmd.isEmpty()) + if (!yyextra->spaceBeforeCmd.isEmpty()) { addOutput(yyscanner,yyextra->spaceBeforeCmd); yyextra->spaceBeforeCmd.resize(0); @@ -2727,7 +2764,7 @@ static bool getDocSectionName(int s) case Entry::EXAMPLE_SEC: case Entry::MEMBERGRP_SEC: return TRUE; - default: + default: return FALSE; } } @@ -2785,11 +2822,15 @@ static void addXRefItem(yyscan_t yyscanner, if (listName==0) return; //printf("addXRefItem(%s,%s,%s,%d)\n",listName,itemTitle,listTitle,append); +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_sectionMutex); +#endif + RefList *refList = RefListManager::instance().add(listName,listTitle,itemTitle); RefItem *item = 0; for (RefItem *i : yyextra->current->sli) { - if (i && qstrcmp(i->list()->listName(),listName)==0) + if (i && qstrcmp(i->list()->listName(),listName)==0) { //printf("found %s lii->type=%s\n",listName,lii->type); item = i; @@ -2825,26 +2866,28 @@ static void addXRefItem(yyscan_t yyscanner, yyextra->current->doc += cmdString; } - SectionManager &sm = SectionManager::instance(); - const SectionInfo *si = sm.find(anchorLabel); - if (si) { - if (si->lineNr() != -1) + SectionManager &sm = SectionManager::instance(); + const SectionInfo *si = sm.find(anchorLabel); + if (si) { - warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",anchorLabel.data(),si->fileName().data(),si->lineNr()); + if (si->lineNr() != -1) + { + warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s, line %d)",anchorLabel.data(),si->fileName().data(),si->lineNr()); + } + else + { + warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s)",anchorLabel.data(),si->fileName().data()); + } } else { - warn(listName,yyextra->lineNr,"multiple use of section label '%s', (first occurrence: %s)",anchorLabel.data(),si->fileName().data()); + si = sm.add(anchorLabel,listName,yyextra->lineNr, + yyextra->sectionTitle,SectionType::Anchor, + yyextra->sectionLevel); + yyextra->current->anchors.push_back(si); } } - else - { - si = sm.add(anchorLabel,listName,yyextra->lineNr, - yyextra->sectionTitle,SectionType::Anchor, - yyextra->sectionLevel); - yyextra->current->anchors.push_back(si); - } } yyextra->outputXRef.resize(0); } @@ -2855,13 +2898,16 @@ static void addXRefItem(yyscan_t yyscanner, // not already added. Returns the label of the formula. static QCString addFormula(yyscan_t yyscanner) { +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_formulaMutex); +#endif struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; QCString formLabel; QCString fText=yyextra->formulaText.simplifyWhiteSpace(); int id = FormulaManager::instance().addFormula(fText); formLabel.sprintf("\\_form#%d",id); for (int i=0;i<yyextra->formulaNewLines;i++) formLabel+="@_fakenl"; // add fake newlines to - // keep the warnings + // keep the warnings // correctly aligned. return formLabel; } @@ -2876,6 +2922,9 @@ static SectionType sectionLevelToType(int level) static void addSection(yyscan_t yyscanner) { +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_sectionMutex); +#endif struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; SectionManager &sm = SectionManager::instance(); const SectionInfo *si = sm.find(yyextra->sectionLabel); @@ -2908,6 +2957,9 @@ static void addSection(yyscan_t yyscanner) static void addCite(yyscan_t yyscanner) { +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_citeMutex); +#endif struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; QCString name=yytext; if (yytext[0] =='"') @@ -2926,8 +2978,24 @@ static void stripTrailingWhiteSpace(QCString &s) uint len = s.length(); int i = (int)len-1; char c; - while (i>=0 && ((c = s.at(i))==' ' || c=='\t' || c=='\r')) i--; - if (i!=(int)len-1) + while (i>=0) + { + c = s.at(i); + if (c==' ' || c=='\t' || c=='\r') // normal whitespace + { + i--; + } + else if (c=='r' && i>=7 && qstrncmp("\\ilinebr",s.data()+i-7,8)==0) // special line break marker + { + i-=8; + } + else // non-whitespace + { + break; + } + } + //printf("stripTrailingWhitespace(%s) i=%d len=%d\n",s.data(),i,len); + if (i!=(int)len-1) { s.resize(i+2); // string up to and including char at pos i and \0 terminator } @@ -2942,8 +3010,8 @@ static inline void setOutput(yyscan_t yyscanner,OutputContext ctx) yyextra->xrefAppendFlag = !yyextra->inBody && yyextra->inContext==OutputXRef && ctx==OutputXRef && // two consecutive xref items yyextra->newXRefKind==yyextra->xrefKind && // of the same kind - (yyextra->xrefKind!=XRef_Item || - yyextra->newXRefItemKey==yyextra->xrefItemKey); // with the same key if \xrefitem + (yyextra->xrefKind!=XRef_Item || + yyextra->newXRefItemKey==yyextra->xrefItemKey); // with the same key if \xrefitem //printf("%d && %d && %d && (%d || %d)\n", // yyextra->inContext==OutputXRef, // ctx==OutputXRef, @@ -2951,10 +3019,10 @@ static inline void setOutput(yyscan_t yyscanner,OutputContext ctx) // yyextra->xrefKind!=XRef_Item, // yyextra->newXRefItemKey==yyextra->xrefItemKey); //printf("refKind=%d yyextra->newXRefKind=%d xrefAppendToPrev=%d yyextra->xrefAppendFlag=%d\n", - // yyextra->xrefKind,yyextra->newXRefKind,xrefAppendToPrev,yyextra->xrefAppendFlag); + // yyextra->xrefKind,yyextra->newXRefKind,xrefAppendToPrev,yyextra->xrefAppendFlag); //printf("setOutput(yyscanner,yyextra->inContext=%d ctx=%d)\n",yyextra->inContext,ctx); - if (yyextra->inContext==OutputXRef) // end of XRef section => add the item + if (yyextra->inContext==OutputXRef) // end of XRef section => add the item { // See if we can append this new xref item to the previous one. // We know this at the start of the next item of the same @@ -3059,6 +3127,9 @@ static inline void setOutput(yyscan_t yyscanner,OutputContext ctx) static void addAnchor(yyscan_t yyscanner,const char *anchor) { +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_sectionMutex); +#endif struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; SectionManager &sm = SectionManager::instance(); const SectionInfo *si = sm.find(anchor); @@ -3156,15 +3227,16 @@ CommentScanner::~CommentScanner() bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *parser, /* in */ Entry *curEntry, /* in */ const QCString &comment, - /* in */ const QCString &fileName, - /* in,out */ int &lineNr, - /* in */ bool isBrief, - /* in */ bool isAutoBriefOn, - /* in */ bool isInbody, - /* in,out */ Protection &prot, - /* in,out */ int &position, - /* out */ bool &newEntryNeeded - ) + /* in */ const QCString &fileName, + /* in,out */ int &lineNr, + /* in */ bool isBrief, + /* in */ bool isAutoBriefOn, + /* in */ bool isInbody, + /* in,out */ Protection &prot, + /* in,out */ int &position, + /* out */ bool &newEntryNeeded, + /* in */ bool markdownSupport + ) { yyscan_t yyscanner = p->yyscanner; struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; @@ -3179,8 +3251,8 @@ bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *pars yyextra->inputString = comment; yyextra->inputString.append(" "); yyextra->inputPosition = position; - yyextra->lineNr = lineNr; - yyextra->fileName = fileName; + yyextra->lineNr = lineNr; + yyextra->fileName = fileName; yyextra->protection = prot; yyextra->needNewEntry = FALSE; yyextra->xrefKind = XRef_None; @@ -3188,6 +3260,7 @@ bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *pars yyextra->insidePre = FALSE; yyextra->parseMore = FALSE; yyextra->inBody = isInbody; + yyextra->markdownSupport= markdownSupport; yyextra->outputXRef.resize(0); if (!isBrief && !isAutoBriefOn && !yyextra->current->doc.isEmpty()) { // add newline separator between detailed comment blocks @@ -3209,7 +3282,7 @@ bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *pars Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\n" "input=[\n%s]\n",qPrint(fileName),lineNr,qPrint(yyextra->inputString) ); - + commentscanYYrestart( 0, yyscanner ); BEGIN( Comment ); commentscanYYlex(yyscanner); @@ -3228,7 +3301,7 @@ bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *pars if (yyextra->insideParBlock) { warn(yyextra->fileName,yyextra->lineNr, - "Documentation block ended while inside a \\parblock. Missing \\endparblock"); + "Documentation block ended while inside a \\parblock. Missing \\endparblock"); } yyextra->current->doc=stripLeadingAndTrailingEmptyLines(yyextra->current->doc,yyextra->current->docLine); @@ -3248,14 +3321,14 @@ bool CommentScanner::parseCommentBlock(/* in */ OutlineParserInterface *pars Debug::print(Debug::CommentScan,0,"-----------\nCommentScanner: %s:%d\noutput=[\n" "brief=[line=%d\n%s]\ndocs=[line=%d\n%s]\ninbody=[line=%d\n%s]\n]\n===========\n", qPrint(fileName),lineNr, - yyextra->current->briefLine,qPrint(yyextra->current->brief), + yyextra->current->briefLine,qPrint(yyextra->current->brief), yyextra->current->docLine,qPrint(yyextra->current->doc), yyextra->current->inbodyLine,qPrint(yyextra->current->inbodyDocs) ); - + checkFormula(yyscanner); prot = yyextra->protection; - + yyextra->docGroup.addDocs(curEntry); newEntryNeeded = yyextra->needNewEntry; @@ -3285,7 +3358,7 @@ static void handleGuard(yyscan_t yyscanner,const QCString &expr) if (parentEnabled) { if ( - (sectionEnabled && yyextra->guardType==Guard_If) || + (sectionEnabled && yyextra->guardType==Guard_If) || (!sectionEnabled && yyextra->guardType==Guard_IfNot) ) // section is visible { diff --git a/src/condparser.cpp b/src/condparser.cpp index e76b164..ac6ff61 100644 --- a/src/condparser.cpp +++ b/src/condparser.cpp @@ -2,8 +2,8 @@ * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -19,6 +19,8 @@ * ! NOT operator */ +#include <algorithm> + #include "condparser.h" #include "config.h" #include "message.h" @@ -27,7 +29,7 @@ /** * parses and evaluates the given expression. - * @returns + * @returns * - On error, an error message is returned. * - On success, the result of the expression is either "1" or "0". */ @@ -123,13 +125,13 @@ int CondParser::getOperatorId(const QCString &opName) /** * Get next token in the current string expr. - * Uses the data in m_expr pointed to by m_e to + * Uses the data in m_expr pointed to by m_e to * produce m_tokenType and m_token, set m_err in case of an error */ void CondParser::getToken() { m_tokenType = NOTHING; - m_token.resize(0); + m_token.resize(0); //printf("\tgetToken e:{%c}, ascii=%i, col=%i\n", *e, *e, e-expr); @@ -303,7 +305,7 @@ bool CondParser::evalOperator(int opId, bool lhs, bool rhs) */ bool CondParser::evalVariable(const char *varName) { - if (Config_getList(ENABLED_SECTIONS).find(varName)==-1) return FALSE; - return TRUE; + const StringVector &list = Config_getList(ENABLED_SECTIONS); + return std::find(list.begin(),list.end(),varName)!=list.end(); } diff --git a/src/config.h b/src/config.h index 1b79b1e..31be3a1 100644 --- a/src/config.h +++ b/src/config.h @@ -24,19 +24,24 @@ class FTextStream; //! @{ //! some convenience macros for accessing the config options //! mainly done like this for backward compatibility -#if DYNAMIC_LOOKUP // for debug purposes -#define Config_getString(val) (ConfigValues::instance().*((ConfigValues::InfoString*)ConfigValues::instance().get(#val))->item) -#define Config_getBool(val) (ConfigValues::instance().*((ConfigValues::InfoBool*)ConfigValues::instance().get(#val))->item) -#define Config_getInt(val) (ConfigValues::instance().*((ConfigValues::InfoInt*)ConfigValues::instance().get(#val))->item) -#define Config_getEnum(val) (ConfigValues::instance().*((ConfigValues::InfoString*)ConfigValues::instance().get(#val))->item) -#define Config_getList(val) (ConfigValues::instance().*((ConfigValues::InfoList*)ConfigValues::instance().get(#val))->item) -#else // direct access -#define Config_getString(val) (ConfigValues::instance().val) -#define Config_getBool(val) (ConfigValues::instance().val) -#define Config_getInt(val) (ConfigValues::instance().val) -#define Config_getEnum(val) (ConfigValues::instance().val) -#define Config_getList(val) (ConfigValues::instance().val) -#endif +//#if DYNAMIC_LOOKUP // for debug purposes +//#define Config_getString(val) (ConfigValues::instance().*((ConfigValues::InfoString*)ConfigValues::instance().get(#val))->item) +//#define Config_getBool(val) (ConfigValues::instance().*((ConfigValues::InfoBool*)ConfigValues::instance().get(#val))->item) +//#define Config_getInt(val) (ConfigValues::instance().*((ConfigValues::InfoInt*)ConfigValues::instance().get(#val))->item) +//#define Config_getEnum(val) (ConfigValues::instance().*((ConfigValues::InfoString*)ConfigValues::instance().get(#val))->item) +//#define Config_getList(val) (ConfigValues::instance().*((ConfigValues::InfoList*)ConfigValues::instance().get(#val))->item) +//#else // direct access +#define Config_getString(name) (ConfigValues::instance().name()) +#define Config_getBool(name) (ConfigValues::instance().name()) +#define Config_getInt(name) (ConfigValues::instance().name()) +#define Config_getEnum(name) (ConfigValues::instance().name()) +#define Config_getList(name) (ConfigValues::instance().name()) +#define Config_updateString(name,value) (ConfigValues::instance().update_##name(value)); +#define Config_updateBool(name,value) (ConfigValues::instance().update_##name(value)); +#define Config_updateInt(name,value) (ConfigValues::instance().update_##name(value)); +#define Config_updateEnum(name,value) (ConfigValues::instance().update_##name(value)); +#define Config_updateList(name,...) (ConfigValues::instance().update_##name(__VA_ARGS__)); +//#endif //! @} /** \brief Public function to deal with the configuration file. */ diff --git a/src/config.xml b/src/config.xml index 6a87a0b..81610c0 100644 --- a/src/config.xml +++ b/src/config.xml @@ -950,7 +950,7 @@ Go to the <a href="commands.html">next</a> section or return to the will only generate file names in lower-case letters. If set to \c YES, upper-case letters are also allowed. This is useful if you have classes or files whose names only differ in case and if your file system - supports case sensitive file names. Windows (including Cygwin) ands + supports case sensitive file names. Windows (including Cygwin) and Mac users are advised to set this option to \c NO. ]]> </docs> @@ -1705,10 +1705,12 @@ to disable this feature. <docs> <![CDATA[ If clang assisted parsing is enabled you can provide the clang parser with the - path to the <a href="http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html"> - compilation database</a> used when the files were built. This is equivalent to - specifying the "-p" option to a clang tool, such as clang-check. These options - will then be passed to the parser. + path to the directory containing a file called compile_commands.json. + This file is the <a href="http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html"> + compilation database</a> containing the options used when the source files were built. + This is equivalent to specifying the "-p" option to a clang tool, such as clang-check. + These options will then be passed to the parser. Any options specified with + \ref cfg_clang_options "CLANG_OPTIONS" will be added as well. @note The availability of this option depends on whether or not doxygen was generated with the `-Duse_libclang=ON` option for CMake. @@ -2154,7 +2156,7 @@ The \c DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. <![CDATA[ The \c GENERATE_CHI flag controls if a separate `.chi` index file is generated (\c YES) or that - it should be included in the master `.chm` file (\c NO). + it should be included in the main `.chm` file (\c NO). ]]> </docs> </option> @@ -2756,9 +2758,12 @@ or <option type='bool' id='USE_PDFLATEX' defval='1' depends='GENERATE_LATEX'> <docs> <![CDATA[ - If the \c USE_PDFLATEX tag is set to \c YES, doxygen will use - \c pdflatex to generate the PDF file directly from the \f$\mbox{\LaTeX}\f$ + If the \c USE_PDFLATEX tag is set to \c YES, doxygen will use the engine + as specified with \ref cfg_latex_cmd_name "LATEX_CMD_NAME" + to generate the PDF file directly from the \f$\mbox{\LaTeX}\f$ files. Set this option to \c YES, to get a higher quality PDF documentation. +<br> + See also section \ref cfg_latex_cmd_name "LATEX_CMD_NAME" for selecting the engine. ]]> </docs> </option> @@ -3029,9 +3034,8 @@ front of it. </docs> </option> </group> -<!-- - <group name='Sqlite3' docs='Configuration options related to Sqlite3 output'> - <option type='bool' id='GENERATE_SQLITE3' defval='0'> + <group name='Sqlite3' setting='USE_SQLITE3' docs='Configuration options related to Sqlite3 output'> + <option type='bool' id='GENERATE_SQLITE3' setting='USE_SQLITE3' defval='0'> <docs> <![CDATA[ If the \c GENERATE_SQLITE3 tag is set to \c YES doxygen will generate a @@ -3039,7 +3043,7 @@ If the \c GENERATE_SQLITE3 tag is set to \c YES doxygen will generate a ]]> </docs> </option> - <option type='string' id='SQLITE3_OUTPUT' format='dir' defval='sqlite3' depends='GENERATE_SQLITE3'> + <option type='string' id='SQLITE3_OUTPUT' format='dir' defval='sqlite3' setting='USE_SQLITE3' depends='GENERATE_SQLITE3'> <docs> <![CDATA[ The \c SQLITE3_OUTPUT tag is used to specify where the \c Sqlite3 database will be put. @@ -3048,9 +3052,17 @@ put in front of it. ]]> </docs> </option> + <option type='bool' id='SQLITE3_RECREATE_DB' defval='1' setting='USE_SQLITE3' depends='GENERATE_SQLITE3'> + <docs> +<![CDATA[ +The \c SQLITE3_OVERWRITE_DB tag is set to \c YES, the existing doxygen_sqlite3.db +database file will be recreated with each doxygen run. +If set to \c NO, doxygen will warn if an a database file is already found and not modify it. +]]> + </docs> + </option> </group> ---> <group name='PerlMod' docs='Configuration options related to the Perl module output'> <option type='bool' id='GENERATE_PERLMOD' defval='0'> <docs> diff --git a/src/configgen.py b/src/configgen.py index 6720116..4ffa8f8 100755 --- a/src/configgen.py +++ b/src/configgen.py @@ -345,6 +345,9 @@ def parseOption(node): def parseGroups(node): name = node.getAttribute('name') doc = node.getAttribute('docs') + setting = node.getAttribute('setting') + if len(setting) > 0: + print("#if %s" % (setting)) print("%s%s" % (" //-----------------------------------------", "----------------------------------")) print(" cfg->addInfo(\"%s\",\"%s\");" % (name, doc)) @@ -354,9 +357,40 @@ def parseGroups(node): for n in node.childNodes: if n.nodeType == Node.ELEMENT_NODE: parseOption(n) + if len(setting) > 0: + print("#endif") + + +def parseGroupMapGetter(node): + map = { 'bool':'bool', 'string':'const QCString &', 'enum':'const QCString &', 'int':'int', 'list':'const StringVector &' } + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + setting = n.getAttribute('setting') + if len(setting) > 0: + print("#if %s" % (setting)) + type = n.getAttribute('type') + name = n.getAttribute('id') + if type in map: + print(" %-20s %-30s const { return m_%s; }" % (map[type],name+'()',name)) + if len(setting) > 0: + print("#endif") + +def parseGroupMapSetter(node): + map = { 'bool':'bool', 'string':'const QCString &', 'enum':'const QCString &', 'int':'int', 'list':'const StringVector &' } + for n in node.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + setting = n.getAttribute('setting') + if len(setting) > 0: + print("#if %s" % (setting)) + type = n.getAttribute('type') + name = n.getAttribute('id') + if type in map: + print(" %-20s update_%-46s { m_%s = v; return m_%s; }" % (map[type],name+'('+map[type]+' v)',name,name)) + if len(setting) > 0: + print("#endif") -def parseGroupMap(node): - map = { 'bool':'bool', 'string':'QCString', 'enum':'QCString', 'int':'int', 'list':'QStrList' } +def parseGroupMapVar(node): + map = { 'bool':'bool', 'string':'QCString', 'enum':'QCString', 'int':'int', 'list':'StringVector' } for n in node.childNodes: if n.nodeType == Node.ELEMENT_NODE: setting = n.getAttribute('setting') @@ -365,7 +399,7 @@ def parseGroupMap(node): type = n.getAttribute('type') name = n.getAttribute('id') if type in map: - print(" %-8s %s;" % (map[type],name)) + print(" %-12s m_%s;" % (map[type],name)) if len(setting) > 0: print("#endif") @@ -379,7 +413,7 @@ def parseGroupInit(node): type = n.getAttribute('type') name = n.getAttribute('id') if type in map: - print(" %-25s = ConfigImpl::instance()->get%s(__FILE__,__LINE__,\"%s\");" % (name,map[type],name)) + print(" %-25s = ConfigImpl::instance()->get%s(__FILE__,__LINE__,\"%s\");" % ('m_'+name,map[type],name)) if len(setting) > 0: print("#endif") @@ -393,7 +427,7 @@ def parseGroupMapInit(node): type = n.getAttribute('type') name = n.getAttribute('id') if type in map: - print(" m_map.insert(\"%s\",new Info%s(&ConfigValues::%s));" % (name,map[type],name)) + print(" { %-25s Info{ %-13s &ConfigValues::m_%s }}," % ('\"'+name+'\",','Info::'+map[type]+',',name)) if len(setting) > 0: print("#endif") @@ -652,6 +686,7 @@ def main(): print("#include <qdict.h>") print("#include <qstrlist.h>") print("#include <qcstring.h>") + print("#include \"containers.h\"") print("#include \"settings.h\"") print("") print("class ConfigValues") @@ -661,42 +696,38 @@ def main(): for n in elem.childNodes: if n.nodeType == Node.ELEMENT_NODE: if (n.nodeName == "group"): - parseGroupMap(n) + parseGroupMapGetter(n) + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "group"): + parseGroupMapSetter(n) print(" void init();") - print(" struct Info") - print(" {") - print(" enum Type { Bool, Int, String, List, Unknown };") - print(" Info(Type t) : type(t) {}") - print(" virtual ~Info() {}") - print(" Type type;") - print(" };") - print(" struct InfoBool : public Info") - print(" {") - print(" InfoBool(bool ConfigValues::*ptm) : Info(Info::Bool), item(ptm) {}") - print(" bool ConfigValues::*item;") - print(" };") - print(" struct InfoInt : public Info") - print(" {") - print(" InfoInt(int ConfigValues::*ptm) : Info(Info::Int), item(ptm) {}") - print(" int ConfigValues::*item;") - print(" };") - print(" struct InfoString : public Info") - print(" {") - print(" InfoString(QCString ConfigValues::*ptm) : Info(Info::String), item(ptm) {}") - print(" QCString ConfigValues::*item;") - print(" };") - print(" struct InfoList : public Info") - print(" {") - print(" InfoList(QStrList ConfigValues::*ptm) : Info(Info::List), item(ptm) {}") - print(" QStrList ConfigValues::*item;") - print(" };") - print(" const Info *get(const char *tag) const") - print(" {") - print(" return m_map.find(tag);") - print(" }") + print(" struct Info"); + print(" {"); + print(" enum Type { Bool, Int, String, List, Unknown };"); + print(" Info(Type t,bool ConfigValues::*b) : type(t), value(b) {}"); + print(" Info(Type t,int ConfigValues::*i) : type(t), value(i) {}"); + print(" Info(Type t,QCString ConfigValues::*s) : type(t), value(s) {}"); + print(" Info(Type t,StringVector ConfigValues::*l) : type(t), value(l) {}"); + print(" Type type;"); + print(" union Item"); + print(" {"); + print(" Item(bool ConfigValues::*v) : b(v) {}"); + print(" Item(int ConfigValues::*v) : i(v) {}"); + print(" Item(QCString ConfigValues::*v) : s(v) {}"); + print(" Item(StringVector ConfigValues::*v) : l(v) {}"); + print(" bool ConfigValues::*b;"); + print(" int ConfigValues::*i;"); + print(" QCString ConfigValues::*s;"); + print(" StringVector ConfigValues::*l;"); + print(" } value;"); + print(" };"); + print(" const Info *get(const char *tag) const;"); print(" private:") - print(" ConfigValues();") - print(" QDict<Info> m_map;") + for n in elem.childNodes: + if n.nodeType == Node.ELEMENT_NODE: + if (n.nodeName == "group"): + parseGroupMapVar(n) print("};") print("") print("#endif") @@ -707,15 +738,20 @@ def main(): print(" */") print("#include \"configvalues.h\"") print("#include \"configimpl.h\"") + print("#include <unordered_map>") print("") - print("ConfigValues::ConfigValues() : m_map(257)") - print("{") - print(" m_map.setAutoDelete(TRUE);") + print("const ConfigValues::Info *ConfigValues::get(const char *tag) const"); + print("{"); + print(" static const std::unordered_map< std::string, Info > configMap ="); + print(" {"); for n in elem.childNodes: if n.nodeType == Node.ELEMENT_NODE: if (n.nodeName == "group"): parseGroupMapInit(n) - print("}") + print(" };"); + print(" auto it = configMap.find(tag);"); + print(" return it!=configMap.end() ? &it->second : nullptr;"); + print("}"); print("") print("void ConfigValues::init()") print("{") diff --git a/src/configimpl.h b/src/configimpl.h index 6134088..a267cc6 100644 --- a/src/configimpl.h +++ b/src/configimpl.h @@ -1,13 +1,13 @@ /****************************************************************************** * - * + * * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -24,6 +24,7 @@ #include <qlist.h> #include <qregexp.h> #include "ftextstream.h" +#include "containers.h" /** Abstract base class for any configuration option. @@ -35,8 +36,8 @@ class ConfigOption public: /*! The type of option */ - enum OptionType - { + enum OptionType + { O_Info, //!< A section header O_List, //!< A list of items O_Enum, //!< A fixed set of items @@ -46,14 +47,14 @@ class ConfigOption O_Obsolete, //!< An obsolete option O_Disabled //!< Disabled compile time option }; - enum - { - /*! Maximum length of an option in the config file. Used for + enum + { + /*! Maximum length of an option in the config file. Used for * alignment purposes. */ - MAX_OPTION_LENGTH = 23 + MAX_OPTION_LENGTH = 23 }; - ConfigOption(OptionType t) : m_kind(t) + ConfigOption(OptionType t) : m_kind(t) { m_spaces.fill(' ',40); } @@ -81,8 +82,8 @@ class ConfigOption void writeBoolValue(FTextStream &t,bool v); void writeIntValue(FTextStream &t,int i); - void writeStringValue(FTextStream &t,QCString &s); - void writeStringList(FTextStream &t,QStrList &l); + void writeStringValue(FTextStream &t,const QCString &s); + void writeStringList(FTextStream &t,const StringVector &l); QCString m_spaces; QCString m_name; @@ -98,7 +99,7 @@ class ConfigOption class ConfigInfo : public ConfigOption { public: - ConfigInfo(const char *name,const char *doc) + ConfigInfo(const char *name,const char *doc) : ConfigOption(O_Info) { m_name = name; @@ -115,25 +116,25 @@ class ConfigList : public ConfigOption { public: enum WidgetType { String, File, Dir, FileAndDir }; - ConfigList(const char *name,const char *doc) + ConfigList(const char *name,const char *doc) : ConfigOption(O_List) { m_name = name; m_doc = doc; m_widgetType = String; } - void addValue(const char *v) { m_defaultValue.append(v); } + void addValue(const char *v) { m_defaultValue.push_back(v); } void setWidgetType(WidgetType w) { m_widgetType = w; } WidgetType widgetType() const { return m_widgetType; } - QStrList *valueRef() { return &m_value; } - QStrList getDefault() { return m_defaultValue; } + StringVector *valueRef() { return &m_value; } + StringVector getDefault() { return m_defaultValue; } void writeTemplate(FTextStream &t,bool sl,bool); void compareDoxyfile(FTextStream &t); void substEnvVars(); void init() { m_value = m_defaultValue; } private: - QStrList m_value; - QStrList m_defaultValue; + StringVector m_value; + StringVector m_defaultValue; WidgetType m_widgetType; }; @@ -142,7 +143,7 @@ class ConfigList : public ConfigOption class ConfigEnum : public ConfigOption { public: - ConfigEnum(const char *name,const char *doc,const char *defVal) + ConfigEnum(const char *name,const char *doc,const char *defVal) : ConfigOption(O_Enum) { m_name = name; @@ -151,7 +152,7 @@ class ConfigEnum : public ConfigOption m_defValue = defVal; } void addValue(const char *v) { m_valueRange.append(v); } - QStrListIterator iterator() + QStrListIterator iterator() { return QStrListIterator(m_valueRange); } @@ -174,7 +175,7 @@ class ConfigString : public ConfigOption { public: enum WidgetType { String, File, Dir, Image }; - ConfigString(const char *name,const char *doc) + ConfigString(const char *name,const char *doc) : ConfigOption(O_String) { m_name = name; @@ -193,7 +194,7 @@ class ConfigString : public ConfigOption void substEnvVars(); void init() { m_value = m_defValue.copy(); } void emptyValueToDefault() { if(m_value.isEmpty()) m_value=m_defValue; }; - + private: QCString m_value; QCString m_defValue; @@ -205,7 +206,7 @@ class ConfigString : public ConfigOption class ConfigInt : public ConfigOption { public: - ConfigInt(const char *name,const char *doc,int minVal,int maxVal,int defVal) + ConfigInt(const char *name,const char *doc,int minVal,int maxVal,int defVal) : ConfigOption(O_Int) { m_name = name; @@ -237,7 +238,7 @@ class ConfigInt : public ConfigOption class ConfigBool : public ConfigOption { public: - ConfigBool(const char *name,const char *doc,bool defVal) + ConfigBool(const char *name,const char *doc,bool defVal) : ConfigOption(O_Bool) { m_name = name; @@ -264,7 +265,7 @@ class ConfigBool : public ConfigOption class ConfigObsolete : public ConfigOption { public: - ConfigObsolete(const char *name) : ConfigOption(O_Obsolete) + ConfigObsolete(const char *name) : ConfigOption(O_Obsolete) { m_name = name; } void writeTemplate(FTextStream &,bool,bool); void compareDoxyfile(FTextStream &) {} @@ -276,7 +277,7 @@ class ConfigObsolete : public ConfigOption class ConfigDisabled : public ConfigOption { public: - ConfigDisabled(const char *name) : ConfigOption(O_Disabled) + ConfigDisabled(const char *name) : ConfigOption(O_Disabled) { m_name = name; } void writeTemplate(FTextStream &,bool,bool); void compareDoxyfile(FTextStream &) {} @@ -297,7 +298,7 @@ class ConfigDisabled : public ConfigOption * read from a user-supplied configuration file. * The static member instance() can be used to get * a pointer to the one and only instance. - * + * * Set all variables to their default values by * calling Config::instance()->init() * @@ -321,8 +322,8 @@ class ConfigImpl delete m_instance; m_instance=0; } - - /*! Returns an iterator that can by used to iterate over the + + /*! Returns an iterator that can by used to iterate over the * configuration options. */ QListIterator<ConfigOption> iterator() @@ -330,36 +331,36 @@ class ConfigImpl return QListIterator<ConfigOption>(*m_options); } - /*! + /*! * @name Getting configuration values. * @{ */ - /*! Returns the value of the string option with name \a fileName. + /*! Returns the value of the string option with name \a fileName. * The arguments \a num and \a name are for debugging purposes only. * There is a convenience function Config_getString() for this. */ QCString &getString(const char *fileName,int num,const char *name) const; - /*! Returns the value of the list option with name \a fileName. + /*! Returns the value of the list option with name \a fileName. * The arguments \a num and \a name are for debugging purposes only. * There is a convenience function Config_getList() for this. */ - QStrList &getList(const char *fileName,int num,const char *name) const; + StringVector &getList(const char *fileName,int num,const char *name) const; - /*! Returns the value of the enum option with name \a fileName. + /*! Returns the value of the enum option with name \a fileName. * The arguments \a num and \a name are for debugging purposes only. * There is a convenience function Config_getEnum() for this. */ QCString &getEnum(const char *fileName,int num,const char *name) const; - /*! Returns the value of the integer option with name \a fileName. + /*! Returns the value of the integer option with name \a fileName. * The arguments \a num and \a name are for debugging purposes only. * There is a convenience function Config_getInt() for this. */ int &getInt(const char *fileName,int num,const char *name) const; - /*! Returns the value of the boolean option with name \a fileName. + /*! Returns the value of the boolean option with name \a fileName. * The arguments \a num and \a name are for debugging purposes only. * There is a convenience function Config_getBool() for this. */ @@ -370,12 +371,12 @@ class ConfigImpl */ ConfigOption *get(const char *name) const { - return m_dict->find(name); + return m_dict->find(name); } /* @} */ - /*! - * @name Adding configuration options. + /*! + * @name Adding configuration options. * @{ */ @@ -402,7 +403,7 @@ class ConfigImpl } /*! Adds a new enumeration option with \a name and documentation \a doc - * and initial value \a defVal. + * and initial value \a defVal. * \returns An object representing the option. */ ConfigEnum *addEnum(const char *name, @@ -510,18 +511,18 @@ class ConfigImpl /*! Parse a configuration data in string \a str. * \returns TRUE if successful, or FALSE if the string could not be * parsed. - */ + */ //bool parseString(const char *fn,const char *str); bool parseString(const char *fn,const char *str,bool upd = FALSE); /*! Parse a configuration file with name \a fn. - * \returns TRUE if successful, FALSE if the file could not be + * \returns TRUE if successful, FALSE if the file could not be * opened or read. - */ + */ bool parse(const char *fn,bool upd = FALSE); /*! Called from the constructor, will add doxygen's default options - * to the configuration object + * to the configuration object */ void create(); diff --git a/src/configimpl.l b/src/configimpl.l index 1710fd6..25fa78b 100644 --- a/src/configimpl.l +++ b/src/configimpl.l @@ -1,10 +1,10 @@ /****************************************************************************** * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -29,11 +29,12 @@ #include <qfileinfo.h> #include <qdir.h> -#include <qtextstream.h> #include <qregexp.h> #include <qstack.h> #include <qglobal.h> + #include <thread> +#include <algorithm> #include "configimpl.h" #include "version.h" @@ -61,7 +62,7 @@ void config_err(const char *fmt, ...) va_list args; va_start(args, fmt); vfprintf(stderr, (QCString(error_str) + fmt).data(), args); - va_end(args); + va_end(args); } void config_term(const char *fmt, ...) { @@ -141,7 +142,7 @@ void ConfigOption::writeIntValue(FTextStream &t,int i) t << " " << i; } -void ConfigOption::writeStringValue(FTextStream &t,QCString &s) +void ConfigOption::writeStringValue(FTextStream &t,const QCString &s) { char c; bool needsEscaping=FALSE; @@ -151,10 +152,10 @@ void ConfigOption::writeStringValue(FTextStream &t,QCString &s) if (p) { t << " "; - while ((c=*p++)!=0 && !needsEscaping) + while ((c=*p++)!=0 && !needsEscaping) needsEscaping = (c==' ' || c=='\n' || c=='\t' || c=='"' || c=='#'); if (needsEscaping) - { + { t << "\""; p=se.data(); while (*p) @@ -172,19 +173,17 @@ void ConfigOption::writeStringValue(FTextStream &t,QCString &s) } } -void ConfigOption::writeStringList(FTextStream &t,QStrList &l) +void ConfigOption::writeStringList(FTextStream &t,const StringVector &l) { - const char *p = l.first(); bool first=TRUE; - while (p) + for (const auto &p : l) { - QCString s=p; + if (!first) t << " \\" << endl; + QCString s=p.c_str(); if (!first) t << " "; - first=FALSE; writeStringValue(t,s); - p = l.next(); - if (p) t << " \\" << endl; + first=FALSE; } } @@ -193,7 +192,7 @@ void ConfigOption::writeStringList(FTextStream &t,QStrList &l) ConfigImpl *ConfigImpl::m_instance = 0; -void ConfigInt::convertStrToVal() +void ConfigInt::convertStrToVal() { if (!m_valueString.isEmpty()) { @@ -216,7 +215,7 @@ void ConfigBool::convertStrToVal() QCString val = m_valueString.stripWhiteSpace().lower(); if (!val.isEmpty()) { - if (val=="yes" || val=="true" || val=="1" || val=="all") + if (val=="yes" || val=="true" || val=="1" || val=="all") { m_value=TRUE; } @@ -234,6 +233,11 @@ void ConfigBool::convertStrToVal() void ConfigEnum::convertStrToVal() { + if (m_value.isEmpty()) + { + m_value = m_defValue; + return; + } QCString val = m_value.stripWhiteSpace().lower(); const char *s=m_valueRange.first(); while (s) @@ -254,7 +258,7 @@ void ConfigEnum::convertStrToVal() QCString &ConfigImpl::getString(const char *fileName,int num,const char *name) const { ConfigOption *opt = m_dict->find(name); - if (opt==0) + if (opt==0) { config_term("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); } @@ -265,10 +269,10 @@ QCString &ConfigImpl::getString(const char *fileName,int num,const char *name) c return *((ConfigString *)opt)->valueRef(); } -QStrList &ConfigImpl::getList(const char *fileName,int num,const char *name) const +StringVector &ConfigImpl::getList(const char *fileName,int num,const char *name) const { ConfigOption *opt = m_dict->find(name); - if (opt==0) + if (opt==0) { config_term("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); } @@ -282,7 +286,7 @@ QStrList &ConfigImpl::getList(const char *fileName,int num,const char *name) con QCString &ConfigImpl::getEnum(const char *fileName,int num,const char *name) const { ConfigOption *opt = m_dict->find(name); - if (opt==0) + if (opt==0) { config_term("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); } @@ -296,7 +300,7 @@ QCString &ConfigImpl::getEnum(const char *fileName,int num,const char *name) con int &ConfigImpl::getInt(const char *fileName,int num,const char *name) const { ConfigOption *opt = m_dict->find(name); - if (opt==0) + if (opt==0) { config_term("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); } @@ -310,7 +314,7 @@ int &ConfigImpl::getInt(const char *fileName,int num,const char *name) const bool &ConfigImpl::getBool(const char *fileName,int num,const char *name) const { ConfigOption *opt = m_dict->find(name); - if (opt==0) + if (opt==0) { config_term("%s<%d>: Internal error: Requested unknown option %s!\n",fileName,num,name); } @@ -353,71 +357,33 @@ void ConfigList::writeTemplate(FTextStream &t,bool sl,bool) void ConfigList::compareDoxyfile(FTextStream &t) { - const char *p = m_value.first(); - const char *q = m_defaultValue.first(); - int defCnt = 0; - int valCnt = 0; - - // count non empty elements - while (p) - { - QCString s=p; - if (!s.stripWhiteSpace().isEmpty()) valCnt += 1; - p = m_value.next(); - } - - while (q) - { - QCString s=q; - if (!s.stripWhiteSpace().isEmpty()) defCnt += 1; - q = m_defaultValue.next(); - } + auto get_stripped = [](std::string s) { return QCString(s.c_str()).stripWhiteSpace(); }; + auto is_not_empty = [get_stripped](std::string s) { return !get_stripped(s).isEmpty(); }; + int defCnt = std::count_if( m_value.begin(), m_value.end(),is_not_empty); + int valCnt = std::count_if(m_defaultValue.begin(),m_defaultValue.end(),is_not_empty); if ( valCnt != defCnt) { writeTemplate(t,TRUE,TRUE); return; } - - // get first non empry element - q = m_defaultValue.first(); - p = m_value.first(); - QCString sp = p; - while (p && sp.stripWhiteSpace().isEmpty()) - { - p = m_value.next(); - sp = p; - } - QCString sq = q; - while (q && sq.stripWhiteSpace().isEmpty()) - { - q = m_value.next(); - sq = q; - } - while (p) + auto it1 = m_value.begin(); + auto it2 = m_defaultValue.begin(); + while (it1!=m_value.end() && it2!=m_defaultValue.end()) { - // skip empty elements - sp = p; - while (p && sp.stripWhiteSpace().isEmpty()) + // skip over empty values + while (it1!=m_value.end() && !is_not_empty(*it1)) { - p = m_value.next(); - sp = p; + ++it1; } - sq = q; - while (q && sq.stripWhiteSpace().isEmpty()) + if (it1!=m_value.end()) // non-empty value { - q = m_value.next(); - sq = q; - } - // be sure we have still an element (p and q have same number of 'filled' elements) - if (p) - { - if (sp.stripWhiteSpace() != sq.stripWhiteSpace()) + if (get_stripped(*it1) != get_stripped(*it2)) // not the default, write as difference { writeTemplate(t,TRUE,TRUE); return; } - p = m_value.next(); - q = m_defaultValue.next(); + ++it1; + ++it2; } } } @@ -539,7 +505,7 @@ struct ConfigFileState YY_BUFFER_STATE oldState; YY_BUFFER_STATE newState; QCString fileName; -}; +}; static const char *g_inputString; static int g_inputPosition; @@ -548,11 +514,11 @@ static QCString g_yyFileName; static QCString g_tmpString; static QCString *g_string=0; static bool *g_bool=0; -static QStrList *g_list=0; +static StringVector *g_list=0; static int g_lastState; static QCString g_elemStr; -static QStrList g_includePathList; -static QStack<ConfigFileState> g_includeStack; +static StringVector g_includePathList; +static QStack<ConfigFileState> g_includeStack; static int g_includeDepth; static bool g_configUpdate = FALSE; static QCString g_encoding; @@ -566,7 +532,7 @@ static ConfigImpl *g_config; static yy_size_t yyread(char *buf,yy_size_t max_size) { // no file included - if (g_includeStack.isEmpty()) + if (g_includeStack.isEmpty()) { yy_size_t c=0; if (g_inputString==0) return c; @@ -597,7 +563,7 @@ static QCString configStringRecode( int outputSize=inputSize*4+1; QCString output(outputSize); void *cd = portable_iconv_open(outputEncoding,inputEncoding); - if (cd==(void *)(-1)) + if (cd==(void *)(-1)) { config_term("Error: unsupported character conversion: '%s'->'%s'\n", inputEncoding.data(),outputEncoding.data()); @@ -641,7 +607,7 @@ static FILE *tryPath(const char *path,const char *fileName) return 0; } -static void substEnvVarsInStrList(QStrList &sl); +static void substEnvVarsInStrList(StringVector &sl); static void substEnvVarsInString(QCString &s); static FILE *findFile(const char *fileName) @@ -655,13 +621,11 @@ static FILE *findFile(const char *fileName) return tryPath(NULL, fileName); } substEnvVarsInStrList(g_includePathList); - char *s=g_includePathList.first(); - while (s) // try each of the include paths + for (const auto &s : g_includePathList) { - FILE *f = tryPath(s,fileName); + FILE *f = tryPath(s.c_str(),fileName); if (f) return f; - s=g_includePathList.next(); - } + } // try cwd if g_includePathList fails return tryPath(".",fileName); } @@ -671,7 +635,7 @@ static void readIncludeFile(const char *incName) if (g_includeDepth==MAX_INCLUDE_DEPTH) { config_term("maximum include depth (%d) reached, %s is not included. Aborting...\n", MAX_INCLUDE_DEPTH,incName); - } + } QCString inc = incName; substEnvVarsInString(inc); @@ -692,7 +656,7 @@ static void readIncludeFile(const char *incName) msg("@INCLUDE = %s: parsing...\n",inc.data()); #endif - // store the state of the old file + // store the state of the old file ConfigFileState *fs=new ConfigFileState; fs->oldState=YY_CURRENT_BUFFER; fs->lineNr=g_yyLineNr; @@ -705,7 +669,7 @@ static void readIncludeFile(const char *incName) fs->newState=YY_CURRENT_BUFFER; g_yyFileName=inc; g_includeDepth++; - } + } else { config_term("@INCLUDE = %s: not found!\n",inc.data()); @@ -740,12 +704,12 @@ static void readIncludeFile(const char *incName) <Start,GetString,GetStrList,GetStrList1,GetBool,SkipInvalid>"##".*"\n" { g_config->appendUserComment(yytext);g_yyLineNr++;} <Start,GetString,GetStrList,GetStrList1,GetBool,SkipInvalid>"#" { BEGIN(SkipComment); } <Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"=" { QCString cmd=yytext; - cmd=cmd.left(cmd.length()-1).stripWhiteSpace(); + cmd=cmd.left(cmd.length()-1).stripWhiteSpace(); ConfigOption *option = g_config->get(cmd); if (option==0) // oops not known { config_warn("ignoring unsupported tag '%s' at line %d, file %s\n", - cmd.data(),g_yyLineNr,g_yyFileName.data()); + cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); } else // known tag @@ -801,7 +765,7 @@ static void readIncludeFile(const char *incName) { config_warn("Tag '%s' at line %d of file '%s' has become obsolete.\n" " To avoid this warning please remove this line from your configuration " - "file or upgrade it using \"doxygen -u\"\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file or upgrade it using \"doxygen -u\"\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); } BEGIN(SkipInvalid); break; @@ -815,7 +779,7 @@ static void readIncludeFile(const char *incName) { config_warn("Tag '%s' at line %d of file '%s' belongs to an option that was not enabled at compile time.\n" " To avoid this warning please remove this line from your configuration " - "file or upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file or upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); } BEGIN(SkipInvalid); break; @@ -823,12 +787,12 @@ static void readIncludeFile(const char *incName) } } <Start>[a-z_A-Z][a-z_A-Z0-9]*[ \t]*"+=" { QCString cmd=yytext; - cmd=cmd.left(cmd.length()-2).stripWhiteSpace(); + cmd=cmd.left(cmd.length()-2).stripWhiteSpace(); ConfigOption *option = g_config->get(cmd); if (option==0) // oops not known { config_warn("ignoring unsupported tag '%s' at line %d, file %s\n", - cmd.data(),g_yyLineNr,g_yyFileName.data()); + cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); } else // known tag @@ -857,19 +821,19 @@ static void readIncludeFile(const char *incName) case ConfigOption::O_Int: case ConfigOption::O_Bool: config_warn("operator += not supported for '%s'. Ignoring line at line %d, file %s\n", - yytext,g_yyLineNr,g_yyFileName.data()); + yytext,g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); break; case ConfigOption::O_Obsolete: config_warn("Tag '%s' at line %d of file %s has become obsolete.\n" "To avoid this warning please update your configuration " - "file using \"doxygen -u\"\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file using \"doxygen -u\"\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); break; case ConfigOption::O_Disabled: config_warn("Tag '%s' at line %d of file %s belongs to an option that was not enabled at compile time.\n" "To avoid this warning please remove this line from your configuration " - "file, upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); + "file, upgrade it using \"doxygen -u\", or recompile doxygen with this feature enabled.\n", cmd.data(),g_yyLineNr,g_yyFileName.data()); BEGIN(SkipInvalid); break; } @@ -878,8 +842,8 @@ static void readIncludeFile(const char *incName) <Start>"@INCLUDE_PATH"[ \t]*"=" { BEGIN(GetStrList); g_list=&g_includePathList; g_list->clear(); g_elemStr=""; } /* include a g_config file */ <Start>"@INCLUDE"[ \t]*"=" { BEGIN(Include);} -<Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { - readIncludeFile(configStringRecode(yytext,g_encoding,"UTF-8")); +<Include>([^ \"\t\r\n]+)|("\""[^\n\"]+"\"") { + readIncludeFile(configStringRecode(yytext,g_encoding,"UTF-8")); BEGIN(Start); } <<EOF>> { @@ -907,19 +871,19 @@ static void readIncludeFile(const char *incName) <Start>[a-z_A-Z0-9]+ { config_warn("ignoring unknown tag '%s' at line %d, file %s\n",yytext,g_yyLineNr,g_yyFileName.data()); } <GetString,GetBool,SkipInvalid>\n { g_yyLineNr++; BEGIN(Start); } <GetStrList,GetStrList1>\n { - g_yyLineNr++; + g_yyLineNr++; if (!g_elemStr.isEmpty()) { //printf("elemStr1='%s'\n",g_elemStr.data()); - g_list->append(g_elemStr); + g_list->push_back(g_elemStr.data()); } - BEGIN(Start); + BEGIN(Start); } <GetStrList1>[ \t]+ { if (!g_elemStr.isEmpty()) { //printf("elemStr2='%s'\n",g_elemStr.data()); - g_list->append(g_elemStr); + g_list->push_back(g_elemStr.data()); } g_elemStr.resize(0); } @@ -927,18 +891,18 @@ static void readIncludeFile(const char *incName) if (!g_elemStr.isEmpty()) { //printf("elemStr2='%s'\n",g_elemStr.data()); - g_list->append(g_elemStr); + g_list->push_back(g_elemStr.data()); } g_elemStr.resize(0); } -<GetString>[^ \"\t\r\n]+ { (*g_string)+=configStringRecode(yytext,g_encoding,"UTF-8"); +<GetString>[^ \"\t\r\n]+ { (*g_string)+=configStringRecode(yytext,g_encoding,"UTF-8"); checkEncoding(); } <GetString,GetStrList,GetStrList1,SkipInvalid>"\"" { g_lastState=YY_START; - BEGIN(GetQuotedString); - g_tmpString.resize(0); + BEGIN(GetQuotedString); + g_tmpString.resize(0); } -<GetQuotedString>"\""|"\n" { +<GetQuotedString>"\""|"\n" { // we add a bogus space to signal that the string was quoted. This space will be stripped later on. g_tmpString+=" "; //printf("Quoted String = '%s'\n",g_tmpString.data()); @@ -962,16 +926,16 @@ static void readIncludeFile(const char *incName) g_tmpString+='"'; } <GetQuotedString>. { g_tmpString+=*yytext; } -<GetBool>[a-zA-Z]+ { - QCString bs=yytext; +<GetBool>[a-zA-Z]+ { + QCString bs=yytext; bs=bs.upper(); if (bs=="YES" || bs=="1") *g_bool=TRUE; else if (bs=="NO" || bs=="0") *g_bool=FALSE; - else + else { - *g_bool=FALSE; + *g_bool=FALSE; config_warn("Invalid value '%s' for " "boolean tag in line %d, file %s; use YES or NO\n", bs.data(),g_yyLineNr,g_yyFileName.data()); @@ -986,7 +950,7 @@ static void readIncludeFile(const char *incName) <SkipComment>\n { g_yyLineNr++; BEGIN(Start); } <SkipComment>\\[ \r\t]*\n { g_yyLineNr++; BEGIN(Start); } <*>\\[ \r\t]*\n { g_yyLineNr++; } -<*>. +<*>. <*>\n { g_yyLineNr++ ; } %% @@ -999,7 +963,7 @@ void ConfigImpl::writeTemplate(FTextStream &t,bool sl,bool upd) /* print first lines of user comment that were at the beginning of the file, might have special meaning for editors */ if (m_startComment) { - t << takeStartComment() << endl; + t << takeStartComment() << endl; } t << "# Doxyfile " << getDoxygenVersion() << endl << endl; if (!sl) @@ -1073,12 +1037,12 @@ static void substEnvVarsInString(QCString &s) //printf("substEnvVarInString(%s) end\n",s.data()); } -static void substEnvVarsInStrList(QStrList &sl) +static void substEnvVarsInStrList(StringVector &sl) { - char *s = sl.first(); - while (s) + StringVector results; + for (const auto &s : sl) { - QCString result(s); + QCString result = s.c_str(); // an argument with quotes will have an extra space at the end, so wasQuoted will be TRUE. bool wasQuoted = (result.find(' ')!=-1) || (result.find('\t')!=-1); // here we strip the quote again @@ -1088,8 +1052,8 @@ static void substEnvVarsInStrList(QStrList &sl) if (!wasQuoted) /* as a result of the expansion, a single string may have expanded into a list, which we'll - add to sl. If the original string already - contained multiple elements no further + add to sl. If the original string already + contained multiple elements no further splitting is done to allow quoted items with spaces! */ { int l=result.length(); @@ -1100,7 +1064,7 @@ static void substEnvVarsInStrList(QStrList &sl) { char c=0; // skip until start of new word - while (i<l && ((c=result.at(i))==' ' || c=='\t')) i++; + while (i<l && ((c=result.at(i))==' ' || c=='\t')) i++; p=i; // p marks the start index of the word // skip until end of a word while (i<l && ((c=result.at(i))!=' ' && c!='\t' && c!='"')) i++; @@ -1114,11 +1078,9 @@ static void substEnvVarsInStrList(QStrList &sl) c=result.at(i); if (c=='"') // end quote { - // replace the string in the list and go to the next item. - sl.insert(sl.at(),result.mid(p,i-p)); // insert new item before current item. - sl.next(); // current item is now the old item + results.push_back(result.mid(p,i-p).data()); p=i+1; - break; + break; } else if (c=='\\') // skip escaped stuff { @@ -1128,33 +1090,22 @@ static void substEnvVarsInStrList(QStrList &sl) } else if (c==' ' || c=='\t') // separator { - // replace the string in the list and go to the next item. - sl.insert(sl.at(),result.mid(p,i-p)); // insert new item before current item. - sl.next(); // current item is now the old item + if (i>p) results.push_back(result.mid(p,i-p).data()); p=i+1; } } } if (p!=l) // add the leftover as a string { - // replace the string in the list and go to the next item. - sl.insert(sl.at(),result.right(l-p)); // insert new item before current item. - sl.next(); // current item is now the old item + results.push_back(result.right(l-p).data()); } } else // just goto the next element in the list { - sl.insert(sl.at(),result); - sl.next(); + if (!result.isEmpty()) results.push_back(result.data()); } - // remove the old unexpanded string from the list - int i=sl.at(); - sl.remove(); // current item index changes if the last element is removed. - if (sl.at()==i) // not last item - s = sl.current(); - else // just removed last item - s = 0; } + sl = results; } void ConfigString::substEnvVars() @@ -1221,7 +1172,7 @@ void ConfigImpl::init() void ConfigImpl::create() { - if (m_initialized) return; + if (m_initialized) return; m_initialized = TRUE; addConfigOptions(this); } @@ -1244,7 +1195,7 @@ static QCString configFileToString(const char *name) while ((size=f.readBlock(contents.rawData()+totalSize,bSize))==bSize) { totalSize+=bSize; - contents.resize(totalSize+bSize); + contents.resize(totalSize+bSize); } totalSize+=size+2; contents.resize(totalSize); @@ -1269,7 +1220,7 @@ static QCString configFileToString(const char *name) QCString contents(fsize+2); f.readBlock(contents.rawData(),fsize); f.close(); - if (fsize==0 || contents[fsize-1]=='\n') + if (fsize==0 || contents[fsize-1]=='\n') contents[fsize]='\0'; else contents[fsize]='\n'; // to help the scanner @@ -1277,7 +1228,7 @@ static QCString configFileToString(const char *name) return contents; } } - if (!fileOpened) + if (!fileOpened) { config_term("cannot open file '%s' for reading\n",name); } @@ -1308,59 +1259,42 @@ bool ConfigImpl::parse(const char *fn,bool update) int retval; g_encoding = "UTF-8"; printlex(yy_flex_debug, TRUE, __FILE__, fn); - retval = parseString(fn,configFileToString(fn), update); + retval = parseString(fn,configFileToString(fn), update); printlex(yy_flex_debug, FALSE, __FILE__, fn); return retval; } //---------------------------------------------------------------------- -static void cleanUpPaths(QStrList &str) +static void cleanUpPaths(StringVector &str) { - char *sfp = str.first(); - while (sfp) + for (size_t i=0;i<str.size();i++) { - char *p = sfp; - if (p) + std::string path = str[i]; + std::replace(path.begin(),path.end(),'\\','/'); + if ((path[0]!='/' && (path.size()<=2 || path[1]!=':')) || path[path.size()-1]!='/') { - char c; - while ((c=*p)) - { - if (c=='\\') *p='/'; - p++; - } - } - QCString path = sfp; - if ((path.at(0)!='/' && (path.length()<=2 || path.at(1)!=':')) || - path.at(path.length()-1)!='/' - ) - { - QFileInfo fi(path); + QFileInfo fi(path.c_str()); if (fi.exists() && fi.isDir()) { - int i = str.at(); - QCString path_str = fi.absFilePath().utf8(); - if (path_str[path_str.length()-1]!='/') path_str+='/'; - str.remove(); - if (str.at()==i) // did not remove last item - str.insert(i,path_str); - else - str.append(path_str); + path = fi.absFilePath().utf8().data(); + if (path[path.size()-1]!='/') path+='/'; } } - sfp = str.next(); + str[i]=path; } } -static void checkFileName(QCString &s,const char *optionName) +static bool checkFileName(const QCString &s,const char *optionName) { QCString val = s.stripWhiteSpace().lower(); if ((val=="yes" || val=="true" || val=="1" || val=="all") || (val=="no" || val=="false" || val=="0" || val=="none")) { err("file name expected for option %s, got %s instead. Ignoring...\n",optionName,s.data()); - s=""; // note the use of &s above: this will change the option value! + return false; } + return true; } #include "config.h" @@ -1370,12 +1304,11 @@ void Config::init() ConfigImpl::instance()->init(); } -static void checkList(QStrList &list,const char *name, bool equalRequired,bool valueRequired) +static void checkList(const StringVector &list,const char *name, bool equalRequired,bool valueRequired) { - const char *s=list.first(); - while (s) + for (const auto &s: list) { - QCString item=s; + QCString item=s.c_str(); item=item.stripWhiteSpace(); int i=item.find('='); if (i==-1 && equalRequired) @@ -1398,7 +1331,6 @@ static void checkList(QStrList &list,const char *name, bool equalRequired,bool v } } } - s=list.next(); } } @@ -1406,17 +1338,18 @@ void Config::checkAndCorrect() { ConfigValues::instance().init(); - QCString &warnFormat = Config_getString(WARN_FORMAT); + //------------------------ + // check WARN_FORMAT + QCString warnFormat = Config_getString(WARN_FORMAT); if (warnFormat.stripWhiteSpace().isEmpty()) { - warnFormat="$file:$line $text"; + Config_updateString(WARN_FORMAT,"$file:$line $text"); } else { if (warnFormat.find("$file")==-1) { warn_uncond("warning format does not contain a $file tag!\n"); - } if (warnFormat.find("$line")==-1) { @@ -1428,15 +1361,17 @@ void Config::checkAndCorrect() } } - QCString &manExtension = Config_getString(MAN_EXTENSION); - + //------------------------ // set default man page extension if non is given by the user + QCString manExtension = Config_getString(MAN_EXTENSION); if (manExtension.isEmpty()) { - manExtension=".3"; + Config_updateString(MAN_EXTENSION,".3"); } - QCString &paperType = Config_getEnum(PAPER_TYPE); + //------------------------ + // check and correct PAPER_TYPE + QCString paperType = Config_getEnum(PAPER_TYPE); paperType=paperType.lower().stripWhiteSpace(); if (paperType.isEmpty() || paperType=="a4wide") { @@ -1448,42 +1383,53 @@ void Config::checkAndCorrect() err("Unknown page type specified\n"); paperType="a4"; } + Config_updateEnum(PAPER_TYPE,paperType); - QCString &outputLanguage=Config_getEnum(OUTPUT_LANGUAGE); + //------------------------ + // check & correct OUTPUT_LANGUAGE + QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE); outputLanguage=outputLanguage.stripWhiteSpace(); if (outputLanguage.isEmpty()) { outputLanguage = "English"; } + Config_updateEnum(OUTPUT_LANGUAGE,outputLanguage); - QCString &htmlFileExtension=Config_getString(HTML_FILE_EXTENSION); + //------------------------ + // check & correct HTML_FILE_EXTENSION + QCString htmlFileExtension=Config_getString(HTML_FILE_EXTENSION); htmlFileExtension=htmlFileExtension.stripWhiteSpace(); if (htmlFileExtension.isEmpty()) { htmlFileExtension = ".html"; } + Config_updateString(HTML_FILE_EXTENSION,htmlFileExtension); - // expand the relative stripFromPath values - QStrList &stripFromPath = Config_getList(STRIP_FROM_PATH); - char *sfp = stripFromPath.first(); - if (sfp==0) // by default use the current path + //------------------------ + // check & correct STRIP_FROM_PATH + StringVector stripFromPath = Config_getList(STRIP_FROM_PATH); + if (stripFromPath.empty()) // by default use the current path { QString p = QDir::currentDirPath(); if (p.at(p.length()-1)!='/') p.append('/'); - stripFromPath.append(p.utf8()); + stripFromPath.push_back(p.utf8().data()); } else { cleanUpPaths(stripFromPath); } + Config_updateList(STRIP_FROM_PATH,stripFromPath); - // expand the relative stripFromPath values - QStrList &stripFromIncPath = Config_getList(STRIP_FROM_INC_PATH); + //------------------------ + // check & correct STRIP_FROM_INC_PATH + StringVector stripFromIncPath = Config_getList(STRIP_FROM_INC_PATH); cleanUpPaths(stripFromIncPath); + Config_updateList(STRIP_FROM_INC_PATH,stripFromIncPath); + //------------------------ // Test to see if HTML header is valid - QCString &headerFile = Config_getString(HTML_HEADER); + QCString headerFile = Config_getString(HTML_HEADER); if (!headerFile.isEmpty()) { QFileInfo fi(headerFile); @@ -1493,8 +1439,10 @@ void Config::checkAndCorrect() "does not exist\n",headerFile.data()); } } + + //------------------------ // Test to see if HTML footer is valid - QCString &footerFile = Config_getString(HTML_FOOTER); + QCString footerFile = Config_getString(HTML_FOOTER); if (!footerFile.isEmpty()) { QFileInfo fi(footerFile); @@ -1505,29 +1453,31 @@ void Config::checkAndCorrect() } } + //------------------------ // Test to see if MathJax code file is valid if (Config_getBool(USE_MATHJAX)) { - QCString &MathJaxCodefile = Config_getString(MATHJAX_CODEFILE); - if (!MathJaxCodefile.isEmpty()) + QCString mathJaxCodefile = Config_getString(MATHJAX_CODEFILE); + if (!mathJaxCodefile.isEmpty()) { - QFileInfo fi(MathJaxCodefile); + QFileInfo fi(mathJaxCodefile); if (!fi.exists()) { config_term("tag MATHJAX_CODEFILE file '%s' " - "does not exist\n",MathJaxCodefile.data()); + "does not exist\n",mathJaxCodefile.data()); } } - QCString &path = Config_getString(MATHJAX_RELPATH); + QCString path = Config_getString(MATHJAX_RELPATH); if (!path.isEmpty() && path.at(path.length()-1)!='/') { path+="/"; } - + Config_updateString(MATHJAX_RELPATH,path); } + //------------------------ // Test to see if LaTeX header is valid - QCString &latexHeaderFile = Config_getString(LATEX_HEADER); + QCString latexHeaderFile = Config_getString(LATEX_HEADER); if (!latexHeaderFile.isEmpty()) { QFileInfo fi(latexHeaderFile); @@ -1537,8 +1487,10 @@ void Config::checkAndCorrect() "does not exist\n",latexHeaderFile.data()); } } + + //------------------------ // Test to see if LaTeX footer is valid - QCString &latexFooterFile = Config_getString(LATEX_FOOTER); + QCString latexFooterFile = Config_getString(LATEX_FOOTER); if (!latexFooterFile.isEmpty()) { QFileInfo fi(latexFooterFile); @@ -1549,25 +1501,24 @@ void Config::checkAndCorrect() } } + //------------------------ // check include path - QStrList &includePath = Config_getList(INCLUDE_PATH); - char *s=includePath.first(); - while (s) + const StringVector &includePath = Config_getList(INCLUDE_PATH); + for (const auto &s : includePath) { - QFileInfo fi(s); + QFileInfo fi(s.c_str()); if (!fi.exists()) warn_uncond("tag INCLUDE_PATH: include path '%s' " - "does not exist\n",s); - s=includePath.next(); + "does not exist\n",s.c_str()); } + //------------------------ // check PREDEFINED if (Config_getBool(ENABLE_PREPROCESSING)) { - QStrList &predefList = Config_getList(PREDEFINED); - s=predefList.first(); - while (s) + const StringVector &predefList = Config_getList(PREDEFINED); + for (const auto &s : predefList) { - QCString predef=s; + QCString predef=s.c_str(); predef=predef.stripWhiteSpace(); int i_equals=predef.find('='); int i_obrace=predef.find('('); @@ -1575,84 +1526,93 @@ void Config::checkAndCorrect() { err("Illegal PREDEFINED format '%s', no define name specified\n",predef.data()); } - s=predefList.next(); } } + //------------------------ // check ALIASES - QStrList &aliasList = Config_getList(ALIASES); - s=aliasList.first(); - while (s) + const StringVector &aliasList = Config_getList(ALIASES); + for (const auto &s : aliasList) { QRegExp re1("[a-z_A-Z][a-z_A-Z0-9]*[ \t]*="); // alias without argument QRegExp re2("[a-z_A-Z][a-z_A-Z0-9]*{[0-9]+}[ \t]*="); // alias with argument - QCString alias=s; + QCString alias=s.c_str(); alias=alias.stripWhiteSpace(); if (alias.find(re1)!=0 && alias.find(re2)!=0) { err("Illegal ALIASES format '%s'. Use \"name=value\" or \"name{n}=value\", where n is the number of arguments\n", alias.data()); } - s=aliasList.next(); } + //------------------------ // check EXTENSION_MAPPING checkList(Config_getList(EXTENSION_MAPPING),"EXTENSION_MAPPING",TRUE,TRUE); + //------------------------ // check FILTER_PATTERNS checkList(Config_getList(FILTER_PATTERNS),"FILTER_PATTERNS",TRUE,TRUE); + //------------------------ // check FILTER_SOURCE_PATTERNS checkList(Config_getList(FILTER_SOURCE_PATTERNS),"FILTER_SOURCE_PATTERNS",FALSE,FALSE); + //------------------------ // check TAGFILES checkList(Config_getList(TAGFILES),"TAGFILES",FALSE,TRUE); + //------------------------ // check EXTRA_SEARCH_MAPPINGS if (Config_getBool(SEARCHENGINE) && Config_getBool(GENERATE_HTML)) { checkList(Config_getList(EXTRA_SEARCH_MAPPINGS),"EXTRA_SEARCH_MAPPING",TRUE,TRUE); } + //------------------------ // check if GENERATE_TREEVIEW and GENERATE_HTMLHELP are both enabled if (Config_getBool(GENERATE_TREEVIEW) && Config_getBool(GENERATE_HTMLHELP)) { err("When enabling GENERATE_HTMLHELP the tree view (GENERATE_TREEVIEW) should be disabled. I'll do it for you.\n"); - Config_getBool(GENERATE_TREEVIEW)=FALSE; + Config_updateBool(GENERATE_TREEVIEW,FALSE); } - if (!(Config_getString(HTML_FILE_EXTENSION) == ".html") && Config_getBool(GENERATE_HTMLHELP)) + + //------------------------ + // check if GENERATE_HTMLHELP and HTML_FILE_EXTENSION is not .html + if (Config_getString(HTML_FILE_EXTENSION)!=".html" && Config_getBool(GENERATE_HTMLHELP)) { err("When enabling GENERATE_HTMLHELP the HTML_FILE_EXTENSION should be \".html\". I'll do it for you.\n"); - Config_getString(HTML_FILE_EXTENSION)=".html"; + Config_updateString(HTML_FILE_EXTENSION,".html"); } + + //------------------------ + // check if SEARCHENGINE and GENERATE_HTMLHELP are both enabled if (Config_getBool(SEARCHENGINE) && Config_getBool(GENERATE_HTMLHELP)) { err("When enabling GENERATE_HTMLHELP the search engine (SEARCHENGINE) should be disabled. I'll do it for you.\n"); - Config_getBool(SEARCHENGINE)=FALSE; + Config_updateBool(SEARCHENGINE,FALSE); } + //------------------------ // check if SEPARATE_MEMBER_PAGES and INLINE_GROUPED_CLASSES are both enabled if (Config_getBool(SEPARATE_MEMBER_PAGES) && Config_getBool(INLINE_GROUPED_CLASSES)) { err("When enabling INLINE_GROUPED_CLASSES the SEPARATE_MEMBER_PAGES option should be disabled. I'll do it for you.\n"); - Config_getBool(SEPARATE_MEMBER_PAGES)=FALSE; + Config_updateBool(SEPARATE_MEMBER_PAGES,FALSE); } - // check dot image format - QCString &dotImageFormat=Config_getEnum(DOT_IMAGE_FORMAT); + //------------------------ + // check and correct DOT_IMAGE_FORMAT + QCString dotImageFormat=Config_getEnum(DOT_IMAGE_FORMAT); dotImageFormat=dotImageFormat.stripWhiteSpace(); if (dotImageFormat.isEmpty()) { dotImageFormat = "png"; } - //else if (dotImageFormat!="gif" && dotImageFormat!="png" && dotImageFormat!="jpg") - //{ - // err("Invalid value for DOT_IMAGE_FORMAT: '%s'. Using the default.\n",dotImageFormat.data()); - // dotImageFormat = "png"; - //} + Config_updateEnum(DOT_IMAGE_FORMAT,dotImageFormat); + //------------------------ // correct DOT_FONTNAME if needed - QCString &dotFontName=Config_getString(DOT_FONTNAME); + QCString dotFontName=Config_getString(DOT_FONTNAME); if (dotFontName=="FreeSans" || dotFontName=="FreeSans.ttf") { warn_uncond("doxygen no longer ships with the FreeSans font.\n" @@ -1663,9 +1623,11 @@ void Config::checkAndCorrect() { dotFontName = "Helvetica"; } + Config_updateString(DOT_FONTNAME,dotFontName); + //------------------------ // clip dotFontSize against the maximum bounds - int &dotFontSize = Config_getInt(DOT_FONTSIZE); + int dotFontSize = Config_getInt(DOT_FONTSIZE); if (dotFontSize<4) { dotFontSize=4; @@ -1674,9 +1636,11 @@ void Config::checkAndCorrect() { dotFontSize=24; } + Config_updateInt(DOT_FONTSIZE,dotFontSize); + //------------------------ // clip number of threads - int &dotNumThreads = Config_getInt(DOT_NUM_THREADS); + int dotNumThreads = Config_getInt(DOT_NUM_THREADS); if (dotNumThreads>32) { dotNumThreads=32; @@ -1685,9 +1649,11 @@ void Config::checkAndCorrect() { dotNumThreads=QMAX(2,std::thread::hardware_concurrency()+1); } + Config_updateInt(DOT_NUM_THREADS,dotNumThreads); + //------------------------ // check dot path - QCString &dotPath = Config_getString(DOT_PATH); + QCString dotPath = Config_getString(DOT_PATH); if (!dotPath.isEmpty()) { QFileInfo fi(dotPath); @@ -1717,9 +1683,11 @@ void Config::checkAndCorrect() { dotPath=""; } + Config_updateString(DOT_PATH,dotPath); + //------------------------ // check plantuml path - QCString &plantumlJarPath = Config_getString(PLANTUML_JAR_PATH); + QCString plantumlJarPath = Config_getString(PLANTUML_JAR_PATH); if (!plantumlJarPath.isEmpty()) { QFileInfo pu(plantumlJarPath); @@ -1748,9 +1716,11 @@ void Config::checkAndCorrect() plantumlJarPath=""; } } + Config_updateString(PLANTUML_JAR_PATH,plantumlJarPath); + //------------------------ // check dia path - QCString &diaPath = Config_getString(DIA_PATH); + QCString diaPath = Config_getString(DIA_PATH); if (!diaPath.isEmpty()) { QFileInfo dp(diaPath+"/dia"+Portable::commandExtension()); @@ -1772,52 +1742,52 @@ void Config::checkAndCorrect() { diaPath=""; } + Config_updateString(DIA_PATH,diaPath); - // check input - QStrList &inputSources=Config_getList(INPUT); - if (inputSources.count()==0) + //------------------------ + // check INPUT + StringVector inputSources=Config_getList(INPUT); + if (inputSources.empty()) { // use current dir as the default - inputSources.append(QDir::currentDirPath().utf8()); + inputSources.push_back(QDir::currentDirPath().utf8().data()); } else { - s=inputSources.first(); - while (s) + for (const auto &s : inputSources) { - QFileInfo fi(s); + QFileInfo fi(s.c_str()); if (!fi.exists()) { - warn_uncond("tag INPUT: input source '%s' does not exist\n",s); + warn_uncond("tag INPUT: input source '%s' does not exist\n",s.c_str()); } - s=inputSources.next(); } } + Config_updateList(INPUT,inputSources); + //------------------------ // add default file patterns if needed - QStrList &filePatternList = Config_getList(FILE_PATTERNS); - if (filePatternList.isEmpty()) + StringVector filePatternList = Config_getList(FILE_PATTERNS); + if (filePatternList.empty()) { ConfigOption * opt = ConfigImpl::instance()->get("FILE_PATTERNS"); if (opt->kind()==ConfigOption::O_List) { - QStrList l = ((ConfigList*)opt)->getDefault(); - const char *p = l.first(); - while (p) - { - filePatternList.append(p); - p = l.next(); - } + filePatternList = ((ConfigList*)opt)->getDefault(); } } + Config_updateList(FILE_PATTERNS,filePatternList); + //------------------------ // add default pattern if needed - QStrList &examplePatternList = Config_getList(EXAMPLE_PATTERNS); - if (examplePatternList.isEmpty()) + StringVector examplePatternList = Config_getList(EXAMPLE_PATTERNS); + if (examplePatternList.empty()) { - examplePatternList.append("*"); + examplePatternList.push_back("*"); + Config_updateList(EXAMPLE_PATTERNS,examplePatternList); } + //------------------------ // if no output format is enabled, warn the user if (!Config_getBool(GENERATE_HTML) && !Config_getBool(GENERATE_LATEX) && @@ -1834,6 +1804,7 @@ void Config::checkAndCorrect() warn_uncond("No output formats selected! Set at least one of the main GENERATE_* options to YES.\n"); } + //------------------------ // check HTMLHELP creation requirements if (!Config_getBool(GENERATE_HTML) && Config_getBool(GENERATE_HTMLHELP)) @@ -1841,36 +1812,40 @@ void Config::checkAndCorrect() warn_uncond("GENERATE_HTMLHELP=YES requires GENERATE_HTML=YES.\n"); } + //------------------------ // check QHP creation requirements if (Config_getBool(GENERATE_QHP)) { if (Config_getString(QHP_NAMESPACE).isEmpty()) { err("GENERATE_QHP=YES requires QHP_NAMESPACE to be set. Using 'org.doxygen.doc' as default!.\n"); - Config_getString(QHP_NAMESPACE)="org.doxygen.doc"; + Config_updateString(QHP_NAMESPACE,"org.doxygen.doc"); } if (Config_getString(QHP_VIRTUAL_FOLDER).isEmpty()) { err("GENERATE_QHP=YES requires QHP_VIRTUAL_FOLDER to be set. Using 'doc' as default!\n"); - Config_getString(QHP_VIRTUAL_FOLDER)="doc"; + Config_updateString(QHP_VIRTUAL_FOLDER,"doc"); } } + //------------------------ if (Config_getBool(OPTIMIZE_OUTPUT_JAVA) && Config_getBool(INLINE_INFO)) { // don't show inline info for Java output, since Java has no inline // concept. - Config_getBool(INLINE_INFO)=FALSE; + Config_updateBool(INLINE_INFO,FALSE); } - int &depth = Config_getInt(MAX_DOT_GRAPH_DEPTH); + //------------------------ + int depth = Config_getInt(MAX_DOT_GRAPH_DEPTH); if (depth==0) { - depth=1000; + Config_updateInt(MAX_DOT_GRAPH_DEPTH,1000); } - int &hue = Config_getInt(HTML_COLORSTYLE_HUE); + //------------------------ + int hue = Config_getInt(HTML_COLORSTYLE_HUE); if (hue<0) { hue=0; @@ -1879,8 +1854,10 @@ void Config::checkAndCorrect() { hue=hue%360; } + Config_updateInt(HTML_COLORSTYLE_HUE,hue); - int &sat = Config_getInt(HTML_COLORSTYLE_SAT); + //------------------------ + int sat = Config_getInt(HTML_COLORSTYLE_SAT); if (sat<0) { sat=0; @@ -1889,7 +1866,11 @@ void Config::checkAndCorrect() { sat=255; } - int &gamma = Config_getInt(HTML_COLORSTYLE_GAMMA); + Config_updateInt(HTML_COLORSTYLE_SAT,sat); + + + //------------------------ + int gamma = Config_getInt(HTML_COLORSTYLE_GAMMA); if (gamma<40) { gamma=40; @@ -1898,32 +1879,30 @@ void Config::checkAndCorrect() { gamma=240; } + Config_updateInt(HTML_COLORSTYLE_GAMMA,gamma); + //------------------------ QCString mathJaxFormat = Config_getEnum(MATHJAX_FORMAT); if (!mathJaxFormat.isEmpty() && mathJaxFormat!="HTML-CSS" && mathJaxFormat!="NativeMML" && mathJaxFormat!="SVG") { err("Unsupported value for MATHJAX_FORMAT: Should be one of HTML-CSS, NativeMML, or SVG\n"); - Config_getEnum(MATHJAX_FORMAT)="HTML-CSS"; + Config_updateEnum(MATHJAX_FORMAT,"HTML-CSS"); } + //------------------------ // add default words if needed - QStrList &annotationFromBrief = Config_getList(ABBREVIATE_BRIEF); - if (annotationFromBrief.isEmpty()) - { - annotationFromBrief.append("The $name class"); - annotationFromBrief.append("The $name widget"); - annotationFromBrief.append("The $name file"); - annotationFromBrief.append("is"); - annotationFromBrief.append("provides"); - annotationFromBrief.append("specifies"); - annotationFromBrief.append("contains"); - annotationFromBrief.append("represents"); - annotationFromBrief.append("a"); - annotationFromBrief.append("an"); - annotationFromBrief.append("the"); + const StringVector &annotationFromBrief = Config_getList(ABBREVIATE_BRIEF); + if (annotationFromBrief.empty()) + { + Config_updateList(ABBREVIATE_BRIEF, + { "The $name class", "The $name widget", + "The $name file", "is", "provides", "specifies", + "contains", "represents", "a", "an", "the" + }); } + //------------------------ // some default settings for vhdl if (Config_getBool(OPTIMIZE_OUTPUT_VHDL) && (Config_getBool(INLINE_INHERITED_MEMB) || @@ -1953,15 +1932,18 @@ void Config::checkAndCorrect() "%s%s%s%s%s%s",s1,s2,s3,s4,s5,s6 ); - Config_getBool(INLINE_INHERITED_MEMB) = FALSE; - Config_getBool(INHERIT_DOCS) = FALSE; - Config_getBool(HIDE_SCOPE_NAMES) = TRUE; - Config_getBool(EXTRACT_PRIVATE) = TRUE; - Config_getBool(ENABLE_PREPROCESSING) = FALSE; - Config_getBool(EXTRACT_PACKAGE) = TRUE; + Config_updateBool(INLINE_INHERITED_MEMB, FALSE); + Config_updateBool(INHERIT_DOCS, FALSE); + Config_updateBool(HIDE_SCOPE_NAMES, TRUE); + Config_updateBool(EXTRACT_PRIVATE, TRUE); + Config_updateBool(ENABLE_PREPROCESSING, FALSE); + Config_updateBool(EXTRACT_PACKAGE, TRUE); } - checkFileName(Config_getString(GENERATE_TAGFILE),"GENERATE_TAGFILE"); + if (!checkFileName(Config_getString(GENERATE_TAGFILE),"GENERATE_TAGFILE")) + { + Config_updateString(GENERATE_TAGFILE,""); + } #if 0 // TODO: this breaks test 25; SOURCEBROWSER = NO and SOURCE_TOOLTIPS = YES. // So this and other regressions should be analysed and fixed before this can be enabled @@ -2016,10 +1998,10 @@ void Config::postProcess(bool clearHeaderAndFooter, bool compare) // refers to the files that we are supposed to parse. if (clearHeaderAndFooter) { - Config_getString(HTML_HEADER)=""; - Config_getString(HTML_FOOTER)=""; - Config_getString(LATEX_HEADER)=""; - Config_getString(LATEX_FOOTER)=""; + Config_updateString(HTML_HEADER ,""); + Config_updateString(HTML_FOOTER ,""); + Config_updateString(LATEX_HEADER,""); + Config_updateString(LATEX_FOOTER,""); } } diff --git a/src/context.cpp b/src/context.cpp index 9684870..83e8e7a 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -298,18 +298,16 @@ class ConfigContext::Private public: Private() { m_cachedLists.setAutoDelete(TRUE); } virtual ~Private() { } - TemplateVariant fetchList(const QCString &name,const QStrList *list) + TemplateVariant fetchList(const QCString &name,const StringVector &list) { TemplateVariant *v = m_cachedLists.find(name); if (v==0) { TemplateList *tlist = TemplateList::alloc(); m_cachedLists.insert(name,new TemplateVariant(tlist)); - QStrListIterator li(*list); - char *s; - for (li.toFirst();(s=li.current());++li) + for (const auto &s : list) { - tlist->append(s); + tlist->append(s.c_str()); } return tlist; } @@ -345,23 +343,23 @@ TemplateVariant ConfigContext::get(const char *name) const { case ConfigValues::Info::Bool: { - bool b = ConfigValues::instance().*((ConfigValues::InfoBool*)option)->item; + bool b = ConfigValues::instance().*(option->value.b); return TemplateVariant(b); } case ConfigValues::Info::Int: { - int i = ConfigValues::instance().*((ConfigValues::InfoInt*)option)->item; + int i = ConfigValues::instance().*(option->value.i); return TemplateVariant(i); } case ConfigValues::Info::String: { - QCString s = ConfigValues::instance().*((ConfigValues::InfoString*)option)->item; + QCString s = ConfigValues::instance().*(option->value.s); return TemplateVariant(s); } case ConfigValues::Info::List: { - const QStrList &l = ConfigValues::instance().*((ConfigValues::InfoList*)option)->item; - return p->fetchList(name,&l); + const StringVector &l = ConfigValues::instance().*(option->value.l); + return p->fetchList(name,l); } default: break; @@ -1264,7 +1262,8 @@ static TemplateVariant parseDoc(const Definition *def,const QCString &file,int l const QCString &relPath,const QCString &docStr,bool isBrief) { TemplateVariant result; - DocRoot *root = validatingParseDoc(file,line,def,0,docStr,TRUE,FALSE,0,isBrief,FALSE); + DocRoot *root = validatingParseDoc(file,line,def,0,docStr,TRUE,FALSE, + 0,isBrief,FALSE,Config_getBool(MARKDOWN_SUPPORT)); QGString docs; { FTextStream ts(&docs); @@ -1775,10 +1774,7 @@ class IncludeInfoListContext::Private : public GenericNodeListContext IncludeInfo *ii; for (li.toFirst();(ii=li.current());++li) { - if (!ii->indirect) - { - append(IncludeInfoContext::alloc(ii,lang)); - } + append(IncludeInfoContext::alloc(ii,lang)); } } }; @@ -10345,7 +10341,7 @@ void generateTemplateFiles(const char *templateDir) QCString outDir = QCString(templateDir)+"/html"; if (!thisDir.exists(outDir) && !thisDir.mkdir(outDir)) { - err("Failed to create output directory '%s'\n",templateDir); + err("Failed to create output directory '%s'\n",outDir.data()); return; } ResourceMgr::instance().writeCategory("html",outDir); diff --git a/src/debug.cpp b/src/debug.cpp index ca3c1e9..f56ef3a 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -42,7 +42,8 @@ static std::map< std::string, Debug::DebugMask > s_labels = { "filteroutput", Debug::FilterOutput }, { "lex", Debug::Lex }, { "plantuml", Debug::Plantuml }, - { "fortranfixed2free", Debug::FortranFixed2Free } + { "fortranfixed2free", Debug::FortranFixed2Free }, + { "cite", Debug::Cite } }; //------------------------------------------------------------------------ @@ -114,11 +115,11 @@ class Timer { m_startTime = std::chrono::system_clock::now(); } - int elapsedTimeMs() + double elapsedTimeS() { - return std::chrono::duration_cast< + return (std::chrono::duration_cast< std::chrono::milliseconds>( - std::chrono::system_clock::now() - m_startTime).count(); + std::chrono::system_clock::now() - m_startTime).count()) / 1000.0; } private: std::chrono::time_point<std::chrono::system_clock> m_startTime; @@ -131,8 +132,8 @@ void Debug::startTimer() g_runningTime.start(); } -int Debug::elapsedTime() +double Debug::elapsedTime() { - return g_runningTime.elapsedTimeMs(); + return g_runningTime.elapsedTimeS(); } diff --git a/src/debug.h b/src/debug.h index 0c046f4..e71595f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -36,7 +36,8 @@ class Debug FilterOutput = 0x00001000, Lex = 0x00002000, Plantuml = 0x00004000, - FortranFixed2Free = 0x00008000 + FortranFixed2Free = 0x00008000, + Cite = 0x00010000 }; static void print(DebugMask mask,int prio,const char *fmt,...); @@ -47,7 +48,7 @@ class Debug static void setPriority(int p); static void startTimer(); - static int elapsedTime(); + static double elapsedTime(); private: static DebugMask curMask; diff --git a/src/define.h b/src/define.h index 0a3d62c..015d399 100644 --- a/src/define.h +++ b/src/define.h @@ -16,11 +16,13 @@ #ifndef DEFINE_H #define DEFINE_H -#include <map> -#include <string> +#include <vector> #include <memory> +#include <string> +#include <unordered_map> #include <qcstring.h> +#include "containers.h" class FileDef; @@ -44,5 +46,6 @@ class Define /** List of all macro definitions */ using DefineList = std::vector< std::unique_ptr<Define> >; +using DefinesPerFileList = std::unordered_map< std::string, DefineList >; #endif diff --git a/src/definition.cpp b/src/definition.cpp index 09b4f56..3ed331c 100644 --- a/src/definition.cpp +++ b/src/definition.cpp @@ -159,13 +159,12 @@ void DefinitionImpl::setDefFile(const QCString &df,int defLine,int defCol) static bool matchExcludedSymbols(const char *name) { - static QStrList &exclSyms = Config_getList(EXCLUDE_SYMBOLS); - if (exclSyms.count()==0) return FALSE; // nothing specified - const char *pat = exclSyms.first(); + const StringVector &exclSyms = Config_getList(EXCLUDE_SYMBOLS); + if (exclSyms.empty()) return FALSE; // nothing specified QCString symName = name; - while (pat) + for (const auto &pat : exclSyms) { - QCString pattern = pat; + QCString pattern = pat.c_str(); bool forceStart=FALSE; bool forceEnd=FALSE; if (pattern.at(0)=='^') @@ -210,7 +209,6 @@ static bool matchExcludedSymbols(const char *name) } } } - pat = exclSyms.next(); } //printf("--> name=%s: no match\n",name); return FALSE; @@ -1930,15 +1928,13 @@ QCString abbreviate(const char *s,const char *name) result=result.left(result.length()-1); // strip any predefined prefix - QStrList &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF); - const char *p = briefDescAbbrev.first(); - while (p) + const StringVector &briefDescAbbrev = Config_getList(ABBREVIATE_BRIEF); + for (const auto &p : briefDescAbbrev) { - QCString str = p; + QCString str = p.c_str(); str.replace(QRegExp("\\$name"), scopelessName); // replace $name with entity name str += " "; stripWord(result,str); - p = briefDescAbbrev.next(); } // capitalize first word @@ -2181,7 +2177,7 @@ QCString DefinitionImpl::externalReference(const QCString &relPath) const return relPath; } -QCString DefinitionImpl::name() const +const QCString &DefinitionImpl::name() const { return m_impl->name; } diff --git a/src/definition.h b/src/definition.h index 2d167dc..8ad15b2 100644 --- a/src/definition.h +++ b/src/definition.h @@ -111,7 +111,7 @@ class Definition : public DefinitionIntf virtual bool isAlias() const = 0; /*! Returns the name of the definition */ - virtual QCString name() const = 0; + virtual const QCString &name() const = 0; /*! Returns TRUE iff this definition has an artificially generated name * (typically starting with a @) that is used for nameless definitions diff --git a/src/definitionimpl.h b/src/definitionimpl.h index c35a89e..e91d989 100644 --- a/src/definitionimpl.h +++ b/src/definitionimpl.h @@ -31,7 +31,7 @@ class DefinitionImpl : virtual public Definition virtual ~DefinitionImpl(); virtual bool isAlias() const { return FALSE; } - virtual QCString name() const; + virtual const QCString &name() const; virtual bool isAnonymous() const; virtual QCString localName() const; virtual QCString qualifiedName() const; @@ -142,7 +142,7 @@ class DefinitionAliasImpl : virtual public Definition virtual ~DefinitionAliasImpl(); virtual bool isAlias() const { return TRUE; } - virtual QCString name() const + virtual const QCString &name() const { return m_def->name(); } virtual bool isAnonymous() const { return m_def->isAnonymous(); } diff --git a/src/dirdef.cpp b/src/dirdef.cpp index 0f8f04b..b058f86 100644 --- a/src/dirdef.cpp +++ b/src/dirdef.cpp @@ -69,7 +69,7 @@ class DirDefImpl : public DefinitionImpl, public DirDef void endMemberDeclarations(OutputList &ol); static DirDef *createNewDir(const char *path); - static bool matchPath(const QCString &path,QStrList &l); + static bool matchPath(const QCString &path,const StringVector &l); DirList m_subdirs; QCString m_dispName; @@ -223,7 +223,8 @@ void DirDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title) // repeat brief description if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF)) { - ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } // separator between brief and details if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF) && @@ -243,7 +244,8 @@ void DirDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title) // write documentation if (!documentation().isEmpty()) { - ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } } } @@ -253,7 +255,8 @@ void DirDefImpl::writeBriefDescription(OutputList &ol) if (hasBriefDescription()) { DocRoot *rootNode = validatingParseDoc( - briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE); + briefFile(),briefLine(),this,0,briefDescription(),TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (rootNode && !rootNode->isEmpty()) { ol.startParagraph(); @@ -341,7 +344,8 @@ void DirDefImpl::writeSubDirList(OutputList &ol) FALSE, // isExample 0, // exampleName TRUE, // single line - TRUE // link from index + TRUE, // link from index + Config_getBool(MARKDOWN_SUPPORT) ); ol.endMemberDescription(); } @@ -412,7 +416,8 @@ void DirDefImpl::writeFileList(OutputList &ol) FALSE, // isExample 0, // exampleName TRUE, // single line - TRUE // link from index + TRUE, // link from index + Config_getBool(MARKDOWN_SUPPORT) ); ol.endMemberDescription(); } @@ -750,7 +755,7 @@ int FilePairDict::compareValues(const FilePair *left,const FilePair *right) cons //---------------------------------------------------------------------- -UsedDir::UsedDir(DirDef *dir,bool inherited) : +UsedDir::UsedDir(const DirDef *dir,bool inherited) : m_dir(dir), m_filePairs(7), m_inherited(inherited) { m_filePairs.setAutoDelete(TRUE); @@ -792,17 +797,15 @@ DirDef *DirDefImpl::createNewDir(const char *path) return dir; } -bool DirDefImpl::matchPath(const QCString &path,QStrList &l) +bool DirDefImpl::matchPath(const QCString &path,const StringVector &l) { - const char *s=l.first(); - while (s) + for (const auto &s : l) { - QCString prefix = s; - if (qstricmp(prefix.left(path.length()),path)==0) // case insensitive compare + std::string prefix = s.substr(0,path.length()); + if (qstricmp(prefix.c_str(),path)==0) // case insensitive compare { return TRUE; } - s = l.next(); } return FALSE; } diff --git a/src/dirdef.h b/src/dirdef.h index 399e0c2..468901d 100644 --- a/src/dirdef.h +++ b/src/dirdef.h @@ -104,7 +104,7 @@ class FilePairDict : public SDict<FilePair> class UsedDir { public: - UsedDir(DirDef *dir,bool inherited); + UsedDir(const DirDef *dir,bool inherited); virtual ~UsedDir(); void addFileDep(FileDef *srcFd,FileDef *dstFd); FilePair *findFilePair(const char *name); @@ -114,7 +114,7 @@ class UsedDir void sort(); private: - DirDef *m_dir; + const DirDef *m_dir; FilePairDict m_filePairs; bool m_inherited; }; diff --git a/src/docparser.cpp b/src/docparser.cpp index 00f287c..73131f6 100644 --- a/src/docparser.cpp +++ b/src/docparser.cpp @@ -114,6 +114,7 @@ static uint g_includeFileOffset; static uint g_includeFileLength; static int g_includeFileLine; static bool g_includeFileShowLineNo; +static bool g_markdownSupport; /** Parser's context to store all global variables. @@ -1799,7 +1800,7 @@ static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children, if (doc.isEmpty()) return retval; - doctokenizerYYinit(doc,g_fileName); + doctokenizerYYinit(doc,g_fileName,g_markdownSupport); // first parse any number of paragraphs bool isFirst=TRUE; @@ -1846,18 +1847,16 @@ static void readTextFileByName(const QCString &file,QCString &text) return; } } - QStrList &examplePathList = Config_getList(EXAMPLE_PATH); - char *s=examplePathList.first(); - while (s) + const StringVector &examplePathList = Config_getList(EXAMPLE_PATH); + for (const auto &s : examplePathList) { - QCString absFileName = QCString(s)+Portable::pathSeparator()+file; + QCString absFileName = QCString(s.c_str())+Portable::pathSeparator()+file; QFileInfo fi(absFileName); if (fi.exists()) { text = fileToString(absFileName,Config_getBool(FILTER_SOURCE_FILES)); return; } - s=examplePathList.next(); } // as a fallback we also look in the exampleNameDict @@ -2569,7 +2568,7 @@ void DocRef::parse() DocCite::DocCite(DocNode *parent,const QCString &target,const QCString &) //context) { - static uint numBibFiles = Config_getList(CITE_BIB_FILES).count(); + size_t numBibFiles = Config_getList(CITE_BIB_FILES).size(); m_parent = parent; //printf("DocCite::DocCite(target=%s)\n",target.data()); ASSERT(!target.isEmpty()); @@ -7567,7 +7566,8 @@ DocRoot *validatingParseDoc(const char *fileName,int startLine, const Definition *ctx,const MemberDef *md, const char *input,bool indexWords, bool isExample, const char *exampleName, - bool singleLine, bool linkFromIndex) + bool singleLine, bool linkFromIndex, + bool markdownSupport) { //printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>", // md?md->name().data():"<none>", @@ -7724,6 +7724,7 @@ DocRoot *validatingParseDoc(const char *fileName,int startLine, g_retvalsFound.clear(); g_paramsFound.setAutoDelete(FALSE); g_paramsFound.clear(); + g_markdownSupport = markdownSupport; //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine); doctokenizerYYlineno=startLine; @@ -7734,7 +7735,7 @@ DocRoot *validatingParseDoc(const char *fileName,int startLine, inpStr+='\n'; } //printf("processCopyDoc(in='%s' out='%s')\n",input,inpStr.data()); - doctokenizerYYinit(inpStr,g_fileName); + doctokenizerYYinit(inpStr,g_fileName,markdownSupport); // build abstract syntax tree DocRoot *root = new DocRoot(md!=0,singleLine); @@ -7802,7 +7803,7 @@ DocText *validatingParseText(const char *input) if (input) { doctokenizerYYlineno=1; - doctokenizerYYinit(input,g_fileName); + doctokenizerYYinit(input,g_fileName,Config_getBool(MARKDOWN_SUPPORT)); // build abstract syntax tree txt->parse(); diff --git a/src/docparser.h b/src/docparser.h index d05dea9..1dc6b3f 100644 --- a/src/docparser.h +++ b/src/docparser.h @@ -1,13 +1,13 @@ /****************************************************************************** * - * + * * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -52,7 +52,7 @@ QCString getJsDirEmbeddingChar(QString::Direction textDir); * @param md Member definition to which the documentation belongs. * Can be 0. * @param input String representation of the documentation block. - * @param indexWords Indicates whether or not words should be put in the + * @param indexWords Indicates whether or not words should be put in the * search index. * @param isExample TRUE if the documentation belongs to an example. * @param exampleName Base name of the example file (0 if isExample is FALSE). @@ -61,16 +61,19 @@ QCString getJsDirEmbeddingChar(QString::Direction textDir); * @param linkFromIndex TRUE if the documentation is generated from an * index page. In this case context is not used to determine * the relative path when making a link. + * @param markdownSupport TRUE if the input needs to take markdown markup into + * account. * @returns Root node of the abstract syntax tree. Ownership of the * pointer is handed over to the caller. */ DocRoot *validatingParseDoc(const char *fileName,int startLine, const Definition *context, const MemberDef *md, const char *input,bool indexWords, - bool isExample,const char *exampleName=0, - bool singleLine=FALSE,bool linkFromIndex=FALSE); + bool isExample,const char *exampleName, + bool singleLine,bool linkFromIndex, + bool markdownSupport); -/*! Main entry point for parsing simple text fragments. These +/*! Main entry point for parsing simple text fragments. These * fragments are limited to words, whitespace and symbols. */ DocText *validatingParseText(const char *input); @@ -87,11 +90,11 @@ class DocNode { public: /*! Available node types. */ - enum Kind { Kind_Root = 0, - Kind_Word = 1, - Kind_WhiteSpace = 2, - Kind_Para = 3, - Kind_AutoList = 4, + enum Kind { Kind_Root = 0, + Kind_Word = 1, + Kind_WhiteSpace = 2, + Kind_Para = 3, + Kind_AutoList = 4, Kind_AutoListItem = 5, Kind_Symbol = 6, Kind_URL = 7, @@ -158,7 +161,7 @@ class DocNode /*! Sets a new parent for this node. */ void setParent(DocNode *parent) { m_parent = parent; } - /*! Acceptor function for node visitors. Part of the visitor pattern. + /*! Acceptor function for node visitors. Part of the visitor pattern. * @param v Abstract visitor. */ virtual void accept(DocVisitor *v) = 0; @@ -185,14 +188,14 @@ template<class T> class CompAccept : public DocNode { public: CompAccept() { m_children.setAutoDelete(TRUE); } - void accept(DocVisitor *v) + void accept(DocVisitor *v) { T *obj = dynamic_cast<T *>(this); - v->visitPre(obj); + v->visitPre(obj); QListIterator<DocNode> cli(m_children); DocNode *n; for (cli.toFirst();(n=cli.current());++cli) n->accept(v); - v->visitPost(obj); + v->visitPost(obj); } const QList<DocNode> &children() const { return m_children; } QList<DocNode> &children() { return m_children; } @@ -228,13 +231,13 @@ template<class T> class CompAccept : public DocNode { return getTextBasicDir(0); } - + protected: QList<DocNode> m_children; }; -/** Node representing a word +/** Node representing a word */ class DocWord : public DocNode { @@ -282,7 +285,7 @@ class DocLinkedWord : public DocNode class DocURL : public DocNode { public: - DocURL(DocNode *parent,const QCString &url,bool isEmail) : + DocURL(DocNode *parent,const QCString &url,bool isEmail) : m_url(url), m_isEmail(isEmail) { m_parent=parent; } QCString url() const { return m_url; } Kind kind() const { return Kind_URL; } @@ -482,7 +485,7 @@ class DocSymbol : public DocNode const char *symb; const PerlType type; }PerlSymb; - DocSymbol(DocNode *parent,SymType s) : + DocSymbol(DocNode *parent,SymType s) : m_symbol(s) { m_parent = parent; } SymType symbol() const { return m_symbol; } Kind kind() const { return Kind_Symbol; } @@ -512,7 +515,7 @@ class DocEmoji : public DocNode class DocWhiteSpace : public DocNode { public: - DocWhiteSpace(DocNode *parent,const QCString &chars) : + DocWhiteSpace(DocNode *parent,const QCString &chars) : m_chars(chars) { m_parent = parent; } Kind kind() const { return Kind_WhiteSpace; } QCString chars() const { return m_chars; } @@ -625,7 +628,7 @@ class DocIncOperator : public DocNode public: enum Type { Line, SkipLine, Skip, Until }; DocIncOperator(DocNode *parent,Type t,const QCString &pat, - const QCString &context,bool isExample,const QCString &exampleFile) : + const QCString &context,bool isExample,const QCString &exampleFile) : m_type(t), m_pattern(pat), m_context(context), m_isFirst(FALSE), m_isLast(FALSE), m_isExample(isExample), m_exampleFile(exampleFile) { m_parent = parent; } @@ -695,7 +698,7 @@ class DocFormula : public DocNode class DocIndexEntry : public DocNode { public: - DocIndexEntry(DocNode *parent,const Definition *scope,const MemberDef *md) + DocIndexEntry(DocNode *parent,const Definition *scope,const MemberDef *md) : m_scope(scope), m_member(md){ m_parent = parent; } Kind kind() const { return Kind_IndexEntry; } int parse(); @@ -962,7 +965,7 @@ class DocHRef : public CompAccept<DocHRef> { public: DocHRef(DocNode *parent,const HtmlAttribList &attribs,const QCString &url, - const QCString &relPath) : + const QCString &relPath) : m_attribs(attribs), m_url(url), m_relPath(relPath) { m_parent = parent; } int parse(); QCString url() const { return m_url; } @@ -980,7 +983,7 @@ class DocHRef : public CompAccept<DocHRef> class DocHtmlHeader : public CompAccept<DocHtmlHeader> { public: - DocHtmlHeader(DocNode *parent,const HtmlAttribList &attribs,int level) : + DocHtmlHeader(DocNode *parent,const HtmlAttribList &attribs,int level) : m_level(level), m_attribs(attribs) { m_parent = parent; } int level() const { return m_level; } Kind kind() const { return Kind_HtmlHeader; } @@ -996,7 +999,7 @@ class DocHtmlHeader : public CompAccept<DocHtmlHeader> class DocHtmlDescTitle : public CompAccept<DocHtmlDescTitle> { public: - DocHtmlDescTitle(DocNode *parent,const HtmlAttribList &attribs) : + DocHtmlDescTitle(DocNode *parent,const HtmlAttribList &attribs) : m_attribs(attribs) { m_parent = parent; } Kind kind() const { return Kind_HtmlDescTitle; } const HtmlAttribList &attribs() const { return m_attribs; } @@ -1025,7 +1028,7 @@ class DocSection : public CompAccept<DocSection> { public: DocSection(DocNode *parent,int level,const QCString &id) : - m_level(level), m_id(id) { m_parent = parent; } + m_level(level), m_id(id) { m_parent = parent; } Kind kind() const { return Kind_Section; } int level() const { return m_level; } QCString title() const { return m_title; } @@ -1046,7 +1049,7 @@ class DocSection : public CompAccept<DocSection> class DocSecRefItem : public CompAccept<DocSecRefItem> { public: - DocSecRefItem(DocNode *parent,const QCString &target) : + DocSecRefItem(DocNode *parent,const QCString &target) : m_target(target) { m_parent = parent; } Kind kind() const { return Kind_SecRefItem; } QCString target() const { return m_target; } @@ -1110,7 +1113,7 @@ class DocHtmlList : public CompAccept<DocHtmlList> { public: enum Type { Unordered, Ordered }; - DocHtmlList(DocNode *parent,const HtmlAttribList &attribs,Type t) : + DocHtmlList(DocNode *parent,const HtmlAttribList &attribs,Type t) : m_type(t), m_attribs(attribs) { m_parent = parent; } Kind kind() const { return Kind_HtmlList; } Type type() const { return m_type; } @@ -1127,8 +1130,8 @@ class DocHtmlList : public CompAccept<DocHtmlList> class DocSimpleSect : public CompAccept<DocSimpleSect> { public: - enum Type - { + enum Type + { Unknown, See, Return, Author, Authors, Version, Since, Date, Note, Warning, Copyright, Pre, Post, Invar, Remark, Attention, User, Rcs }; @@ -1150,7 +1153,7 @@ class DocSimpleSect : public CompAccept<DocSimpleSect> }; /** Node representing a separator between two simple sections of the - * same type. + * same type. */ class DocSimpleSectSep : public DocNode { @@ -1167,16 +1170,16 @@ class DocParamSect : public CompAccept<DocParamSect> { friend class DocParamList; public: - enum Type - { + enum Type + { Unknown, Param, RetVal, Exception, TemplateParam }; enum Direction { In=1, Out=2, InOut=3, Unspecified=0 }; - DocParamSect(DocNode *parent,Type t) - : m_type(t), m_hasInOutSpecifier(FALSE), m_hasTypeSpecifier(FALSE) + DocParamSect(DocNode *parent,Type t) + : m_type(t), m_hasInOutSpecifier(FALSE), m_hasTypeSpecifier(FALSE) { m_parent = parent; } int parse(const QCString &cmdName,bool xmlContext,Direction d); Kind kind() const { return Kind_ParamSect; } @@ -1194,7 +1197,7 @@ class DocParamSect : public CompAccept<DocParamSect> class DocPara : public CompAccept<DocPara> { public: - DocPara(DocNode *parent) : + DocPara(DocNode *parent) : m_isFirst(FALSE), m_isLast(FALSE) { m_parent = parent; } int parse(); Kind kind() const { return Kind_Para; } @@ -1241,12 +1244,12 @@ class DocPara : public CompAccept<DocPara> class DocParamList : public DocNode { public: - DocParamList(DocNode *parent,DocParamSect::Type t,DocParamSect::Direction d) + DocParamList(DocNode *parent,DocParamSect::Type t,DocParamSect::Direction d) : m_type(t), m_dir(d), m_isFirst(TRUE), m_isLast(TRUE) - { m_paragraphs.setAutoDelete(TRUE); - m_params.setAutoDelete(TRUE); + { m_paragraphs.setAutoDelete(TRUE); + m_params.setAutoDelete(TRUE); m_paramTypes.setAutoDelete(TRUE); - m_parent = parent; + m_parent = parent; } virtual ~DocParamList() { } Kind kind() const { return Kind_ParamList; } @@ -1259,12 +1262,12 @@ class DocParamList : public DocNode bool isFirst() const { return m_isFirst; } bool isLast() const { return m_isLast; } void accept(DocVisitor *v) - { - v->visitPre(this); + { + v->visitPre(this); QListIterator<DocPara> cli(m_paragraphs); DocNode *n; for (cli.toFirst();(n=cli.current());++cli) n->accept(v); - v->visitPost(this); + v->visitPost(this); } int parse(const QCString &cmdName); int parseXml(const QCString ¶mName); @@ -1290,9 +1293,9 @@ class DocSimpleListItem : public DocNode Kind kind() const { return Kind_SimpleListItem; } void accept(DocVisitor *v) { - v->visitPre(this); + v->visitPre(this); m_paragraph->accept(v); - v->visitPost(this); + v->visitPost(this); } private: @@ -1303,7 +1306,7 @@ class DocSimpleListItem : public DocNode class DocHtmlListItem : public CompAccept<DocHtmlListItem> { public: - DocHtmlListItem(DocNode *parent,const HtmlAttribList &attribs,int num) : + DocHtmlListItem(DocNode *parent,const HtmlAttribList &attribs,int num) : m_attribs(attribs), m_itemNum(num) { m_parent = parent; } Kind kind() const { return Kind_HtmlListItem; } int itemNumber() const { return m_itemNum; } @@ -1335,7 +1338,7 @@ class DocHtmlCell : public CompAccept<DocHtmlCell> friend class DocHtmlTable; public: enum Alignment { Left, Right, Center }; - DocHtmlCell(DocNode *parent,const HtmlAttribList &attribs,bool isHeading) : + DocHtmlCell(DocNode *parent,const HtmlAttribList &attribs,bool isHeading) : m_isHeading(isHeading), m_attribs(attribs) { m_parent = parent; } bool isHeading() const { return m_isHeading; } bool isFirst() const { return m_isFirst; } @@ -1387,7 +1390,7 @@ class DocHtmlRow : public CompAccept<DocHtmlRow> { friend class DocHtmlTable; public: - DocHtmlRow(DocNode *parent,const HtmlAttribList &attribs) : + DocHtmlRow(DocNode *parent,const HtmlAttribList &attribs) : m_attribs(attribs) { m_parent = parent; } Kind kind() const { return Kind_HtmlRow; } uint numCells() const { return m_children.count(); } @@ -1422,7 +1425,7 @@ class DocHtmlRow : public CompAccept<DocHtmlRow> class DocHtmlTable : public CompAccept<DocHtmlTable> { public: - DocHtmlTable(DocNode *parent,const HtmlAttribList &attribs) + DocHtmlTable(DocNode *parent,const HtmlAttribList &attribs) : m_attribs(attribs) { m_caption=0; m_numCols=0; m_parent = parent; } ~DocHtmlTable() { delete m_caption; } Kind kind() const { return Kind_HtmlTable; } diff --git a/src/doctokenizer.h b/src/doctokenizer.h index e01f045..f43cd07 100644 --- a/src/doctokenizer.h +++ b/src/doctokenizer.h @@ -6,8 +6,8 @@ * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -78,7 +78,7 @@ struct TokenInfo QCString text; // comment blocks - + // list token info bool isEnumList = false; int indent = 0; @@ -124,7 +124,7 @@ const char *tokToString(int token); // operations on the scanner void doctokenizerYYFindSections(const char *input,const Definition *d, const char *fileName); -void doctokenizerYYinit(const char *input,const char *fileName); +void doctokenizerYYinit(const char *input,const char *fileName,bool markdownSupport); void doctokenizerYYcleanup(); void doctokenizerYYpushContext(); bool doctokenizerYYpopContext(); diff --git a/src/doctokenizer.l b/src/doctokenizer.l index 5317de5..ac5b6d2 100644 --- a/src/doctokenizer.l +++ b/src/doctokenizer.l @@ -60,6 +60,7 @@ static const char *g_inputString; static QCString g_fileName; static bool g_insidePre; static int g_sharpCount=0; +static bool g_markdownSupport=TRUE; // context for section finding phase static const Definition *g_definition; @@ -113,6 +114,20 @@ bool doctokenizerYYpopContext() return TRUE; } +QCString extractPartAfterNewLine(const QCString &text) +{ + int nl1 = text.findRev('\n'); + if (nl1!=-1) + { + return text.mid(nl1+1); + } + int nl2 = text.findRev("\\ilinebr"); + if (nl2!=-1) + { + return text.mid(nl2+8); + } + return text; +} //-------------------------------------------------------------------------- @@ -377,7 +392,7 @@ SPCMD2 {CMD}[\\@<>&$#%~".+=|-] SPCMD3 {CMD}_form#[0-9]+ SPCMD4 {CMD}"::" SPCMD5 {CMD}":" -INOUT "inout"|"in"|"out"|("in"{BLANK}*","{BLANK}*"out")|("out"{BLANK}*","{BLANK}*"in") +INOUT "in"|"out"|("in"{BLANK}*","?{BLANK}*"out")|("out"{BLANK}*","?{BLANK}*"in") PARAMIO {CMD}param{BLANK}*"["{BLANK}*{INOUT}{BLANK}*"]" VARARGS "..." TEMPCHAR [a-z_A-Z0-9.,: \t\*\&\(\)\[\]] @@ -487,7 +502,7 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} return TK_LISTITEM; } <St_Para>^{MLISTITEM} { /* list item */ - if (!Doxygen::markdownSupport || g_insidePre) + if (!g_markdownSupport || g_insidePre) { REJECT; } @@ -503,7 +518,7 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} } } <St_Para>^{OLISTITEM} { /* numbered list item */ - if (!Doxygen::markdownSupport || g_insidePre) + if (!g_markdownSupport || g_insidePre) { REJECT; } @@ -519,25 +534,23 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} return TK_LISTITEM; } } -<St_Para>{BLANK}*\n{LISTITEM} { /* list item on next line */ - QCString text=yytext; - text=text.right(text.length()-text.find('\n')-1); +<St_Para>{BLANK}*(\n|"\\ilinebr"){LISTITEM} { /* list item on next line */ + QCString text=extractPartAfterNewLine(yytext); int dashPos = text.findRev('-'); g_token->isEnumList = text.at(dashPos+1)=='#'; g_token->id = -1; g_token->indent = computeIndent(text,dashPos); return TK_LISTITEM; } -<St_Para>{BLANK}*\n{MLISTITEM} { /* list item on next line */ - if (!Doxygen::markdownSupport || g_insidePre) +<St_Para>{BLANK}*(\n|"\\ilinebr"){MLISTITEM} { /* list item on next line */ + if (!g_markdownSupport || g_insidePre) { REJECT; } else { - QCString text=yytext; + QCString text=extractPartAfterNewLine(yytext); static QRegExp re("[*+]"); - text=text.right(text.length()-text.find('\n')-1); int markPos = text.findRev(re); g_token->isEnumList = FALSE; g_token->id = -1; @@ -545,17 +558,14 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} return TK_LISTITEM; } } -<St_Para>{BLANK}*\n{OLISTITEM} { /* list item on next line */ - if (!Doxygen::markdownSupport || g_insidePre) +<St_Para>{BLANK}*(\n|"\\ilinebr"){OLISTITEM} { /* list item on next line */ + if (!g_markdownSupport || g_insidePre) { REJECT; } else { - QCString text=yytext; - int nl=text.findRev('\n'); - int len=text.length(); - text=text.right(len-nl-1); + QCString text=extractPartAfterNewLine(yytext); static QRegExp re("[1-9]"); int digitPos = text.find(re); int dotPos = text.find('.',digitPos); @@ -570,11 +580,10 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->indent = computeIndent(yytext,dotPos); return TK_ENDLIST; } -<St_Para>{BLANK}*\n{ENDLIST} { /* end list on next line */ - QCString text=yytext; - text=text.right(text.length()-text.find('\n')-1); +<St_Para>{BLANK}*(\n|"\\ilinebr"){ENDLIST} { /* end list on next line */ + QCString text=extractPartAfterNewLine(yytext); int dotPos = text.findRev('.'); - g_token->indent = computeIndent(text,dotPos); + g_token->indent = computeIndent(text,dotPos); return TK_ENDLIST; } <St_Para>"{"{BLANK}*"@link"/{BLANK}+ { @@ -585,9 +594,9 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->name = "inheritdoc"; return TK_COMMAND_AT; } -<St_Para>"@_fakenl" { // artificial new line - yylineno++; - } +<St_Para>"@_fakenl" { // artificial new line + yylineno++; + } <St_Para>{SPCMD3} { g_token->name = "_form"; bool ok; @@ -602,6 +611,8 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->paramDir=TokenInfo::Unspecified; return TK_COMMAND_SEL(); } +<St_Para>"\\ilinebr" { + } <St_Para>{SPCMD1} | <St_Para>{SPCMD2} | <St_Para>{SPCMD5} | @@ -768,13 +779,13 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} } } <St_Para>({BLANK}*\n)+{BLANK}*\n/{MLISTITEM} { /* skip trailing paragraph followed by new list item */ - if (!Doxygen::markdownSupport || g_insidePre || g_autoListLevel==0) + if (!g_markdownSupport || g_insidePre || g_autoListLevel==0) { REJECT; } } <St_Para>({BLANK}*\n)+{BLANK}*\n/{OLISTITEM} { /* skip trailing paragraph followed by new list item */ - if (!Doxygen::markdownSupport || g_insidePre || g_autoListLevel==0) + if (!g_markdownSupport || g_insidePre || g_autoListLevel==0) { REJECT; } @@ -799,9 +810,10 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->name = g_token->name.mid(i+1,g_token->name.length()-i-2); BEGIN(St_Code); } +<St_CodeOpt>"\\ilinebr" | <St_CodeOpt>\n | <St_CodeOpt>. { - unput(*yytext); + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); BEGIN(St_Code); } <St_Code>{WS}*{CMD}"endcode" { @@ -823,6 +835,10 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} unput(*yytext); BEGIN(St_HtmlOnly); } +<St_HtmlOnlyOption>"\\ilinebr" { + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); + BEGIN(St_HtmlOnly); + } <St_HtmlOnly>{CMD}"endhtmlonly" { return RetVal_OK; } @@ -914,10 +930,15 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->sectionId = QCString(yytext).stripWhiteSpace(); return RetVal_OK; } +<St_PlantUMLOpt>{BLANK}*{FILEMASK}{BLANK}*/"\\ilinebr" { // case 5: plain file name specified without title or attributes + g_token->sectionId = QCString(yytext).stripWhiteSpace(); + return RetVal_OK; + } +<St_PlantUMLOpt>"\\ilinebr" | <St_PlantUMLOpt>"\n" | <St_PlantUMLOpt>. { g_token->sectionId = ""; - unput(*yytext); + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); return RetVal_OK; } <St_PlantUML>{CMD}"enduml" { @@ -943,12 +964,20 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} unput(*yytext); return 0; } +<St_Title>"\\ilinebr" { + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); + return 0; + } <St_TitleN>"&"{ID}";" { /* symbol */ g_token->name = yytext; return TK_SYMBOL; } <St_TitleN>{HTMLTAG} { } +<St_TitleN>(\n|"\\ilinebr") { /* new line => end of title */ + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); + return 0; + } <St_TitleN>{SPCMD1} | <St_TitleN>{SPCMD2} { /* special command */ g_token->name = yytext+1; @@ -975,14 +1004,14 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->chars=yytext; return TK_WHITESPACE; } -<St_TitleN>\n { /* new line => end of title */ - unput(*yytext); - return 0; - } <St_TitleQ>"&"{ID}";" { /* symbol */ g_token->name = yytext; return TK_SYMBOL; } +<St_TitleQ>(\n|"\\ilinebr") { /* new line => end of title */ + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); + return 0; + } <St_TitleQ>{SPCMD1} | <St_TitleQ>{SPCMD2} { /* special command */ g_token->name = yytext+1; @@ -1002,10 +1031,6 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} BEGIN(St_TitleA); return 0; } -<St_TitleQ>\n { /* new line => end of title */ - unput(*yytext); - return 0; - } <St_TitleA>{BLANK}*{ID}{BLANK}*"="{BLANK}* { // title attribute g_token->name = yytext; g_token->name = g_token->name.left(g_token->name.find('=')).stripWhiteSpace(); @@ -1020,8 +1045,8 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} unput(*yytext); return 0; } -<St_TitleV,St_TitleA>\n { - unput(*yytext); +<St_TitleV,St_TitleA>(\n|"\\ilinebr") { + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); return 0; } @@ -1049,8 +1074,8 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} unput(' '); return 0; } -<St_Cite>\n { // new line - unput(*yytext); +<St_Cite>(\n|"\\ilinebr") { // new line + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); return 0; } <St_Cite>. { // any other character @@ -1076,8 +1101,8 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} <St_Ref>{WS}+"\""{WS}* { // white space following by quoted string BEGIN(St_Ref2); } -<St_Ref>\n { // new line - unput(*yytext); +<St_Ref>(\n|"\\ilinebr") { // new line + for (int i=yyleng-1;i>=0;i--) unput(yytext[i]); return 0; } <St_Ref>. { // any other character @@ -1123,6 +1148,9 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->name = yytext; return TK_SYMBOL; } +<St_Ref2>"\""|\n|"\\ilinebr" { /* " or \n => end of title */ + return 0; + } <St_Ref2>{SPCMD1} | <St_Ref2>{SPCMD2} { /* special command */ g_token->name = yytext+1; @@ -1139,9 +1167,6 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} g_token->chars=yytext; return TK_WHITESPACE; } -<St_Ref2>"\""|\n { /* " or \n => end of title */ - return 0; - } <St_XRefItem>{LABELID} { g_token->name=yytext; } @@ -1235,7 +1260,7 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} /* State for skipping title (all chars until the end of the line) */ <St_SkipTitle>. -<St_SkipTitle>\n { return 0; } +<St_SkipTitle>(\n|"\\ilinebr") { return 0; } /* State for the pass used to find the anchors and sections */ @@ -1341,9 +1366,9 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} } <St_SecSkip>[^a-z_A-Z0-9\-\\\@]+ <St_SecSkip>. -<St_SecSkip>\n +<St_SecSkip>(\n|"\\ilinebr") <St_Sections>. -<St_Sections>\n +<St_Sections>(\n|"\\ilinebr") <St_SecLabel1>{LABELID} { g_secLabel = yytext; processSection(); @@ -1359,6 +1384,10 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} <St_SecTitle>[^\n]*\n { g_secTitle = yytext; g_secTitle = g_secTitle.stripWhiteSpace(); + if (g_secTitle.right(8)=="\\ilinebr") + { + g_secTitle.left(g_secTitle.length()-8); + } processSection(); BEGIN(St_Sections); } @@ -1366,17 +1395,23 @@ REFWORD_NOCV {FILEMASK}|{LABELID}|{REFWORD2_NOCV}|{REFWORD3}|{REFWORD4_NOCV} warn(g_fileName,yylineno,"Unexpected character '%s' while looking for section label or title",yytext); } -<St_Snippet>[^\n]+ | -<St_Snippet>[^\n]*\n { - g_token->name = yytext; +<St_Snippet>[^\\\n]+ { + g_token->name += yytext; + } +<St_Snippet>"\\" { + g_token->name += yytext; + } +<St_Snippet>(\n|"\\ilinebr") { g_token->name = g_token->name.stripWhiteSpace(); - return TK_WORD; + return TK_WORD; } /* Generic rules that work for all states */ <*>\n { warn(g_fileName,yylineno,"Unexpected new line character"); } +<*>"\\ilinebr" { + } <*>[\\@<>&$#%~"=] { /* unescaped special character */ //warn(g_fileName,yylineno,"Unexpected character '%s', assuming command \\%s was meant.",yytext,yytext); g_token->name = yytext; @@ -1405,13 +1440,14 @@ void doctokenizerYYFindSections(const char *input,const Definition *d, printlex(yy_flex_debug, FALSE, __FILE__, fileName); } -void doctokenizerYYinit(const char *input,const char *fileName) +void doctokenizerYYinit(const char *input,const char *fileName,bool markdownSupport) { g_autoListLevel = 0; g_inputString = input; g_inputPos = 0; g_fileName = fileName; g_insidePre = FALSE; + g_markdownSupport = markdownSupport; BEGIN(St_Para); } @@ -1569,6 +1605,7 @@ void doctokenizerYYsetStateAnchor() void doctokenizerYYsetStateSnippet() { + g_token->name=""; BEGIN(St_Snippet); } diff --git a/src/dot.cpp b/src/dot.cpp index 675ead6..ddabbc7 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -13,7 +13,8 @@ * */ -#include <stdlib.h> +#include <cstdlib> +#include <cassert> #include <qdir.h> diff --git a/src/dotfilepatcher.cpp b/src/dotfilepatcher.cpp index 20ce4c1..17f8cb7 100644 --- a/src/dotfilepatcher.cpp +++ b/src/dotfilepatcher.cpp @@ -460,7 +460,7 @@ bool DotFilePatcher::run() const convertMapFile(tt,map->mapFile,map->relPath,map->urlOnly,map->context); if (!result.isEmpty()) { - t << "<map name=\"" << map->label << "\" id=\"" << map->label << "\">" << endl; + t << "<map name=\"" << map->label << "\" id=\"" << correctId(map->label) << "\">" << endl; t << result; t << "</map>" << endl; } diff --git a/src/dotgraph.cpp b/src/dotgraph.cpp index c0cc4fd..1ad85e1 100644 --- a/src/dotgraph.cpp +++ b/src/dotgraph.cpp @@ -236,7 +236,7 @@ void DotGraph::generateCode(FTextStream &t) else // add link to bitmap file with image map { if (!m_noDivTag) t << "<div class=\"center\">"; - t << "<img src=\"" << relImgName() << "\" border=\"0\" usemap=\"#" << getMapLabel() << "\" alt=\"" << getImgAltText() << "\"/>"; + t << "<img src=\"" << relImgName() << "\" border=\"0\" usemap=\"#" << correctId(getMapLabel()) << "\" alt=\"" << getImgAltText() << "\"/>"; if (!m_noDivTag) t << "</div>"; t << endl; if (m_regenerate || !insertMapFile(t, absMapName(), m_relPath, getMapLabel())) diff --git a/src/dotrunner.cpp b/src/dotrunner.cpp index 8cf09fa..a1bbc52 100644 --- a/src/dotrunner.cpp +++ b/src/dotrunner.cpp @@ -13,6 +13,8 @@ * */ +#include <cassert> + #include "dotrunner.h" #include "qstring.h" @@ -151,7 +153,6 @@ DotRunner::DotRunner(const std::string& absDotName, const std::string& md5Hash) , m_md5Hash(md5Hash.data()) , m_dotExe(Config_getString(DOT_PATH)+"dot") , m_cleanUp(Config_getBool(DOT_CLEANUP)) - , m_jobs() { } diff --git a/src/doxygen.cpp b/src/doxygen.cpp index c7c9b45..dab7549 100644 --- a/src/doxygen.cpp +++ b/src/doxygen.cpp @@ -103,6 +103,8 @@ #include "emoji.h" #include "plantuml.h" #include "stlsupport.h" +#include "threadpool.h" +#include "clangparser.h" // provided by the generated file resources.cpp extern void initResources(); @@ -157,10 +159,9 @@ int Doxygen::subpageNestingLevel = 0; bool Doxygen::userComments = FALSE; QCString Doxygen::spaces; bool Doxygen::generatingXmlOutput = FALSE; -bool Doxygen::markdownSupport = TRUE; GenericsSDict *Doxygen::genericsDict; -Preprocessor *Doxygen::preprocessor = 0; -DefineList Doxygen::macroDefinitions; +DefinesPerFileList Doxygen::macroDefinitions; +bool Doxygen::clangAssistedParsing = FALSE; // locally accessible globals static std::unordered_map< std::string, const Entry* > g_classEntries; @@ -628,7 +629,7 @@ static void addIncludeFile(ClassDef *cd,FileDef *ifd,const Entry *root) iName=fd->name(); } } - else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty()) + else if (!Config_getList(STRIP_FROM_INC_PATH).empty()) { iName=stripFromIncludePath(fd->absFilePath()); } @@ -3443,7 +3444,7 @@ static void buildFunctionList(const Entry *root) { // merge argument lists ArgumentList mergedArgList = root->argList; - mergeArguments(mdAl,mergedArgList,!root->proto); + mergeArguments(mdAl,mergedArgList,!root->doc.isEmpty()); // merge documentation if (md->documentation().isEmpty() && !root->doc.isEmpty()) { @@ -4952,7 +4953,7 @@ static void addMemberDocs(const Entry *root, { ArgumentList mergedAl = *al; //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty()); - mergeArguments(mdAl,mergedAl,!root->proto); + mergeArguments(mdAl,mergedAl,!root->doc.isEmpty()); } else { @@ -4965,7 +4966,7 @@ static void addMemberDocs(const Entry *root, { //printf("merging arguments (2)\n"); ArgumentList mergedArgList = root->argList; - mergeArguments(mdAl,mergedArgList,!root->proto); + mergeArguments(mdAl,mergedArgList,!root->doc.isEmpty()); } } if (over_load) // the \overload keyword was used @@ -5645,7 +5646,7 @@ static void addMemberFunction(const Entry *root, root->protection,root->stat,root->virt,spec,relates); return; } - if (md->argsString()==argListToString(root->argList,TRUE,FALSE)) + if (md->argsString()==argListToString(root->argList,FALSE,FALSE)) { // exact argument list match -> remember ucd = ecd = ccd; umd = emd = cmd; @@ -7478,18 +7479,18 @@ static void generateFileSources() if (!Doxygen::inputNameLinkedMap->empty()) { #if USE_LIBCLANG - static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); - if (clangAssistedParsing) + if (Doxygen::clangAssistedParsing) { - QDict<void> g_processedFiles(10007); + StringUnorderedSet processedFiles; // create a dictionary with files to process - QDict<void> g_filesToProcess(10007); + StringUnorderedSet filesToProcess; + for (const auto &fn : *Doxygen::inputNameLinkedMap) { for (const auto &fd : *fn) { - g_filesToProcess.insert(fd->absFilePath(),(void*)0x8); + filesToProcess.insert(fd->absFilePath().str()); } } // process source files (and their include dependencies) @@ -7499,51 +7500,49 @@ static void generateFileSources() { if (fd->isSource() && !fd->isReference()) { - QStrList filesInSameTu; - fd->getAllIncludeFilesRecursively(filesInSameTu); - fd->startParsing(); + auto clangParser = ClangParser::instance()->createTUParser(fd.get()); if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output { msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*g_outputList,FALSE,filesInSameTu); + clangParser->parse(); + fd->writeSource(*g_outputList,clangParser.get()); } else if (!fd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(FALSE,filesInSameTu); + clangParser->parse(); + fd->parseSource(clangParser.get()); } - char *incFile = filesInSameTu.first(); - while (incFile && g_filesToProcess.find(incFile)) + for (auto incFile : clangParser->filesInSameTU()) { - if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile)) + if (filesToProcess.find(incFile)!=filesToProcess.end() && // part of input + fd->absFilePath()!=incFile && // not same file + processedFiles.find(incFile)==processedFiles.end()) // not yet marked as processed { - QStrList moreFiles; + StringVector moreFiles; bool ambig; - FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile,ambig); + FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig); if (ifd && !ifd->isReference()) { if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output { msg(" Generating code for file %s...\n",ifd->docName().data()); - ifd->writeSource(*g_outputList,TRUE,moreFiles); - + ifd->writeSource(*g_outputList,clangParser.get()); } else if (!ifd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg(" Parsing code for file %s...\n",ifd->docName().data()); - ifd->parseSource(TRUE,moreFiles); + ifd->parseSource(clangParser.get()); } - g_processedFiles.insert(incFile,(void*)0x8); + processedFiles.insert(incFile); } } - incFile = filesInSameTu.next(); } - fd->finishParsing(); - g_processedFiles.insert(fd->absFilePath(),(void*)0x8); + processedFiles.insert(fd->absFilePath().str()); } } } @@ -7552,23 +7551,23 @@ static void generateFileSources() { for (const auto &fd : *fn) { - if (!g_processedFiles.find(fd->absFilePath())) // not yet processed + if (processedFiles.find(fd->absFilePath().str())==processedFiles.end()) // not yet processed { - QStrList filesInSameTu; - fd->startParsing(); + auto clangParser = ClangParser::instance()->createTUParser(fd.get()); if (fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate) // sources need to be shown in the output { msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*g_outputList,FALSE,filesInSameTu); + clangParser->parse(); + fd->writeSource(*g_outputList,clangParser.get()); } else if (!fd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(FALSE,filesInSameTu); + clangParser->parse(); + fd->parseSource(clangParser.get()); } - fd->finishParsing(); } } } @@ -7580,21 +7579,20 @@ static void generateFileSources() { for (const auto &fd : *fn) { - QStrList filesInSameTu; - fd->startParsing(); + StringVector filesInSameTu; + fd->getAllIncludeFilesRecursively(filesInSameTu); if (fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate) // sources need to be shown in the output { msg("Generating code for file %s...\n",fd->docName().data()); - fd->writeSource(*g_outputList,FALSE,filesInSameTu); + fd->writeSource(*g_outputList,nullptr); } else if (!fd->isReference() && Doxygen::parseSourcesNeeded) // we needed to parse the sources even if we do not show them { msg("Parsing code for file %s...\n",fd->docName().data()); - fd->parseSource(FALSE,filesInSameTu); + fd->parseSource(nullptr); } - fd->finishParsing(); } } } @@ -7702,28 +7700,35 @@ static void addSourceReferences() // add the macro definitions found during preprocessing as file members static void buildDefineList() { - for (const auto &def : Doxygen::macroDefinitions) + for (const auto &s : g_inputFiles) { - std::unique_ptr<MemberDef> md { createMemberDef( - def->fileName,def->lineNr,def->columnNr, - "#define",def->name,def->args,0, - Public,Normal,FALSE,Member,MemberType_Define, - ArgumentList(),ArgumentList(),"") }; - - if (!def->args.isEmpty()) + auto it = Doxygen::macroDefinitions.find(s); + if (it!=Doxygen::macroDefinitions.end()) { - md->moveArgumentList(stringToArgumentList(SrcLangExt_Cpp, def->args)); - } - md->setInitializer(def->definition); - md->setFileDef(def->fileDef); - md->setDefinition("#define "+def->name); + for (const auto &def : it->second) + { + std::unique_ptr<MemberDef> md { createMemberDef( + def->fileName,def->lineNr,def->columnNr, + "#define",def->name,def->args,0, + Public,Normal,FALSE,Member,MemberType_Define, + ArgumentList(),ArgumentList(),"") }; - MemberName *mn=Doxygen::functionNameLinkedMap->add(def->name); - if (def->fileDef) - { - def->fileDef->insertMember(md.get()); + if (!def->args.isEmpty()) + { + md->moveArgumentList(stringToArgumentList(SrcLangExt_Cpp, def->args)); + } + md->setInitializer(def->definition); + md->setFileDef(def->fileDef); + md->setDefinition("#define "+def->name); + + MemberName *mn=Doxygen::functionNameLinkedMap->add(def->name); + if (def->fileDef) + { + def->fileDef->insertMember(md.get()); + } + mn->push_back(std::move(md)); + } } - mn->push_back(std::move(md)); } } @@ -8632,7 +8637,10 @@ static void generateExampleDocs() pd->documentation()+"\n\n\\include"+lineNoOptStr+" "+pd->name(), // docs TRUE, // index words TRUE, // is example - pd->name() + pd->name(), + FALSE, + FALSE, + Config_getBool(MARKDOWN_SUPPORT) ); endFile(*g_outputList); // contains g_outputList->endContents() } @@ -8856,10 +8864,10 @@ static void readTagFile(const std::shared_ptr<Entry> &root,const char *tl) //---------------------------------------------------------------------------- static void copyLatexStyleSheet() { - QStrList latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET); - for (uint i=0; i<latexExtraStyleSheet.count(); ++i) + const StringVector &latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET); + for (const auto &sheet : latexExtraStyleSheet) { - QCString fileName(latexExtraStyleSheet.at(i)); + QCString fileName = sheet.c_str(); if (!fileName.isEmpty()) { QFileInfo fi(fileName); @@ -8883,14 +8891,14 @@ static void copyLatexStyleSheet() //---------------------------------------------------------------------------- static void copyStyleSheet() { - QCString &htmlStyleSheet = Config_getString(HTML_STYLESHEET); + QCString htmlStyleSheet = Config_getString(HTML_STYLESHEET); if (!htmlStyleSheet.isEmpty()) { QFileInfo fi(htmlStyleSheet); if (!fi.exists()) { err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data()); - htmlStyleSheet.resize(0); // revert to the default + htmlStyleSheet = Config_updateString(HTML_STYLESHEET,""); // revert to the default } else { @@ -8898,10 +8906,10 @@ static void copyStyleSheet() copyFile(htmlStyleSheet,destFileName); } } - QStrList htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET); - for (uint i=0; i<htmlExtraStyleSheet.count(); ++i) + const StringVector &htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET); + for (const auto &sheet : htmlExtraStyleSheet) { - QCString fileName(htmlExtraStyleSheet.at(i)); + QCString fileName = sheet.c_str(); if (!fileName.isEmpty()) { QFileInfo fi(fileName); @@ -8924,14 +8932,14 @@ static void copyStyleSheet() static void copyLogo(const QCString &outputOption) { - QCString &projectLogo = Config_getString(PROJECT_LOGO); + QCString projectLogo = Config_getString(PROJECT_LOGO); if (!projectLogo.isEmpty()) { QFileInfo fi(projectLogo); if (!fi.exists()) { err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data()); - projectLogo.resize(0); // revert to the default + projectLogo = Config_updateString(PROJECT_LOGO,""); // revert to the default } else { @@ -8942,13 +8950,11 @@ static void copyLogo(const QCString &outputOption) } } -static void copyExtraFiles(QStrList files,const QCString &filesOption,const QCString &outputOption) +static void copyExtraFiles(const StringVector &files,const QCString &filesOption,const QCString &outputOption) { - uint i; - for (i=0; i<files.count(); ++i) + for (const auto &file : files) { - QCString fileName(files.at(i)); - + QCString fileName = file.c_str(); if (!fileName.isEmpty()) { QFileInfo fi(fileName); @@ -9034,7 +9040,7 @@ static void generateDiskNames() //---------------------------------------------------------------------------- -static OutlineParserInterface &getParserForFile(const char *fn) +static std::unique_ptr<OutlineParserInterface> getParserForFile(const char *fn) { QCString fileName=fn; QCString extension; @@ -9052,15 +9058,10 @@ static OutlineParserInterface &getParserForFile(const char *fn) return Doxygen::parserManager->getOutlineParser(extension); } -static void parseFile(OutlineParserInterface &parser, - const std::shared_ptr<Entry> &root,FileDef *fd,const char *fn, - bool sameTu,QStrList &filesInSameTu) +static std::shared_ptr<Entry> parseFile(OutlineParserInterface &parser, + FileDef *fd,const char *fn, + ClangTUParser *clangParser,bool newTU) { -#if USE_LIBCLANG - static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); -#else - static bool clangAssistedParsing = FALSE; -#endif QCString fileName=fn; QCString extension; int ei = fileName.findRev('.'); @@ -9079,10 +9080,16 @@ static void parseFile(OutlineParserInterface &parser, if (Config_getBool(ENABLE_PREPROCESSING) && parser.needsPreprocessing(extension)) { + Preprocessor preprocessor; + const StringVector &includePath = Config_getList(INCLUDE_PATH); + for (const auto &s : includePath) + { + preprocessor.addSearchDir(QFileInfo(s.c_str()).absFilePath().utf8()); + } BufStr inBuf(fi.size()+4096); msg("Preprocessing %s...\n",fn); readInputFile(fileName,inBuf); - Doxygen::preprocessor->processFile(fileName,inBuf,preBuf); + preprocessor.processFile(fileName,inBuf,preBuf); } else // no preprocessing { @@ -9101,32 +9108,173 @@ static void parseFile(OutlineParserInterface &parser, convBuf.addChar('\0'); - if (clangAssistedParsing && !sameTu) - { - fd->getAllIncludeFilesRecursively(filesInSameTu); - } - std::shared_ptr<Entry> fileRoot = std::make_shared<Entry>(); // use language parse to parse the file - parser.parseInput(fileName,convBuf.data(),fileRoot,sameTu,filesInSameTu); + if (clangParser) + { + if (newTU) clangParser->parse(); + clangParser->switchToFile(fd); + } + parser.parseInput(fileName,convBuf.data(),fileRoot,clangParser); fileRoot->setFileDef(fd); - root->moveToSubEntryAndKeep(fileRoot); + return fileRoot; +} + +#if MULTITHREADED_INPUT + +//! parse the list of input files +static void parseFiles(const std::shared_ptr<Entry> &root) +{ +#if USE_LIBCLANG + if (Doxygen::clangAssistedParsing) + { + StringUnorderedSet processedFiles; + + // create a dictionary with files to process + StringUnorderedSet filesToProcess; + for (const auto &s : g_inputFiles) + { + filesToProcess.insert(s); + } + + std::mutex processedFilesLock; + // process source files (and their include dependencies) + std::size_t numThreads = std::thread::hardware_concurrency(); + msg("Processing input using %lu threads.\n",numThreads); + ThreadPool threadPool(numThreads); + std::vector< std::future< std::vector< std::shared_ptr<Entry> > > > results; + for (const auto &s : g_inputFiles) + { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + ASSERT(fd!=0); + if (fd->isSource() && !fd->isReference()) // this is a source file + { + // lambda representing the work to executed by a thread + auto processFile = [s,&filesToProcess,&processedFilesLock,&processedFiles]() { + bool ambig; + std::vector< std::shared_ptr<Entry> > roots; + FileDef *fd = findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser = getParserForFile(s.c_str()); + auto fileRoot { parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true) }; + roots.push_back(fileRoot); + + // Now process any include files in the same translation unit + // first. When libclang is used this is much more efficient. + for (auto incFile : clangParser->filesInSameTU()) + { + if (filesToProcess.find(incFile)!=filesToProcess.end()) + { + bool needsToBeProcessed; + { + std::lock_guard<std::mutex> lock(processedFilesLock); + needsToBeProcessed = processedFiles.find(incFile)==processedFiles.end(); + if (needsToBeProcessed) processedFiles.insert(incFile); + } + if (incFile!=s && needsToBeProcessed) + { + FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig); + if (ifd && !ifd->isReference()) + { + //printf(" Processing %s in same translation unit as %s\n",incFile,s->c_str()); + fileRoot = parseFile(*parser.get(),ifd,incFile.c_str(),clangParser.get(),false); + roots.push_back(fileRoot); + } + } + } + } + return roots; + }; + // dispatch the work and collect the future results + results.emplace_back(threadPool.queue(processFile)); + } + } + // synchronise with the Entry result lists produced and add them to the root + for (auto &f : results) + { + auto l = f.get(); + for (auto &e : l) + { + root->moveToSubEntryAndKeep(e); + } + } + // process remaining files + results.clear(); + for (const auto &s : g_inputFiles) + { + if (processedFiles.find(s)==processedFiles.end()) // not yet processed + { + // lambda representing the work to executed by a thread + auto processFile = [s]() { + bool ambig; + std::vector< std::shared_ptr<Entry> > roots; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser { getParserForFile(s.c_str()) }; + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + roots.push_back(fileRoot); + return roots; + }; + // dispatch the work and collect the future results + results.emplace_back(threadPool.queue(processFile)); + } + } + // synchronise with the Entry result lists produced and add them to the root + for (auto &f : results) + { + auto l = f.get(); + for (auto &e : l) + { + root->moveToSubEntryAndKeep(e); + } + } + } + else // normal processing +#endif + { + std::size_t numThreads = std::thread::hardware_concurrency(); + msg("Processing input using %lu threads.\n",numThreads); + ThreadPool threadPool(numThreads); + std::vector< std::future< std::shared_ptr<Entry> > > results; + for (const auto &s : g_inputFiles) + { + // lambda representing the work to executed by a thread + auto processFile = [s]() { + bool ambig; + FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser = getParserForFile(s.c_str()); + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + return fileRoot; + }; + // dispatch the work and collect the future results + results.emplace_back(threadPool.queue(processFile)); + } + // synchronise with the Entry results produced and add them to the root + for (auto &f : results) + { + root->moveToSubEntryAndKeep(f.get()); + } +#warning "Multi-threaded input enabled. This is a highly experimental feature. Only use for doxygen development." + } } +#else // !MULTITHREADED_INPUT + //! parse the list of input files static void parseFiles(const std::shared_ptr<Entry> &root) { #if USE_LIBCLANG - static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); - if (clangAssistedParsing) + if (Doxygen::clangAssistedParsing) { - QDict<void> g_processedFiles(10007); + StringUnorderedSet processedFiles; // create a dictionary with files to process - QDict<void> g_filesToProcess(10007); + StringUnorderedSet filesToProcess; for (const auto &s : g_inputFiles) { - g_filesToProcess.insert(s.c_str(),(void*)0x8); + filesToProcess.insert(s); } // process source files (and their include dependencies) @@ -9137,48 +9285,44 @@ static void parseFiles(const std::shared_ptr<Entry> &root) ASSERT(fd!=0); if (fd->isSource() && !fd->isReference()) // this is a source file { - QStrList filesInSameTu; - OutlineParserInterface &parser = getParserForFile(s.c_str()); - parser.startTranslationUnit(s.c_str()); - parseFile(parser,root,fd,s.c_str(),FALSE,filesInSameTu); - //printf(" got %d extra files in tu\n",filesInSameTu.count()); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser { getParserForFile(s.c_str()) }; + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + root->moveToSubEntryAndKeep(fileRoot); + processedFiles.insert(s); // Now process any include files in the same translation unit // first. When libclang is used this is much more efficient. - char *incFile = filesInSameTu.first(); - while (incFile && g_filesToProcess.find(incFile)) + for (auto incFile : clangParser->filesInSameTU()) { - if (qstrcmp(incFile,s.c_str()) && !g_processedFiles.find(incFile)) + //printf(" file %s\n",incFile.c_str()); + if (filesToProcess.find(incFile)!=filesToProcess.end() && // file need to be processed + processedFiles.find(incFile)==processedFiles.end()) // and is not processed already { - FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile,ambig); + FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig); if (ifd && !ifd->isReference()) { - QStrList moreFiles; - //printf(" Processing %s in same translation unit as %s\n",incFile,s->c_str()); - parseFile(parser,root,ifd,incFile,TRUE,moreFiles); - g_processedFiles.insert(incFile,(void*)0x8); + //printf(" Processing %s in same translation unit as %s\n",incFile.c_str(),s.c_str()); + fileRoot = parseFile(*parser.get(),ifd,incFile.c_str(),clangParser.get(),false); + root->moveToSubEntryAndKeep(fileRoot); + processedFiles.insert(incFile); } } - incFile = filesInSameTu.next(); } - parser.finishTranslationUnit(); - g_processedFiles.insert(s.c_str(),(void*)0x8); } } // process remaining files for (const auto &s : g_inputFiles) { - if (!g_processedFiles.find(s.c_str())) // not yet processed + if (processedFiles.find(s)==processedFiles.end()) // not yet processed { bool ambig; - QStrList filesInSameTu; FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); - ASSERT(fd!=0); - OutlineParserInterface &parser = getParserForFile(s.c_str()); - parser.startTranslationUnit(s.c_str()); - parseFile(parser,root,fd,s.c_str(),FALSE,filesInSameTu); - parser.finishTranslationUnit(); - g_processedFiles.insert(s.c_str(),(void*)0x8); + auto clangParser = ClangParser::instance()->createTUParser(fd); + auto parser { getParserForFile(s.c_str()) }; + auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true); + root->moveToSubEntryAndKeep(fileRoot); + processedFiles.insert(s); } } } @@ -9188,16 +9332,17 @@ static void parseFiles(const std::shared_ptr<Entry> &root) for (const auto &s : g_inputFiles) { bool ambig; - QStrList filesInSameTu; FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig); ASSERT(fd!=0); - OutlineParserInterface &parser = getParserForFile(s.c_str()); - parser.startTranslationUnit(s.c_str()); - parseFile(parser,root,fd,s.c_str(),FALSE,filesInSameTu); + std::unique_ptr<OutlineParserInterface> parser { getParserForFile(s.c_str()) }; + std::shared_ptr<Entry> fileRoot = parseFile(*parser.get(),fd,s.c_str(),nullptr,true); + root->moveToSubEntryAndKeep(fileRoot); } } } +#endif + // resolves a path that may include symlinks, if a recursive symlink is // found an empty string is returned. static QCString resolveSymlink(QCString path) @@ -9277,8 +9422,8 @@ static QDict<void> g_pathsVisited(1009); static int readDir(QFileInfo *fi, FileNameLinkedMap *fnMap, StringUnorderedSet *exclSet, - QStrList *patList, - QStrList *exclPatList, + const StringVector *patList, + const StringVector *exclPatList, StringVector *resultList, StringUnorderedSet *resultSet, bool errorIfNotExist, @@ -9325,8 +9470,8 @@ static int readDir(QFileInfo *fi, } else if (cfi->isFile() && (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) && - (patList==0 || patternMatch(*cfi,patList)) && - !patternMatch(*cfi,exclPatList) && + (patList==0 || patternMatch(*cfi,*patList)) && + (exclPatList==0 || !patternMatch(*cfi,*exclPatList)) && (killSet==0 || killSet->find(cfi->absFilePath().utf8().data())==killSet->end()) ) { @@ -9350,7 +9495,7 @@ static int readDir(QFileInfo *fi, else if (recursive && (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) && cfi->isDir() && - !patternMatch(*cfi,exclPatList) && + (exclPatList==0 || !patternMatch(*cfi,*exclPatList)) && cfi->fileName().at(0)!='.') // skip "." ".." and ".dir" { cfi->setFile(cfi->absFilePath()); @@ -9373,8 +9518,8 @@ static int readDir(QFileInfo *fi, int readFileOrDirectory(const char *s, FileNameLinkedMap *fnMap, StringUnorderedSet *exclSet, - QStrList *patList, - QStrList *exclPatList, + const StringVector *patList, + const StringVector *exclPatList, StringVector *resultList, StringUnorderedSet *resultSet, bool recursive, @@ -9483,7 +9628,7 @@ static void escapeAliases() value.mid(in,14)!="\\nosubgrouping" ) { - newValue+="\\_linebr "; + newValue+="\\ilinebr "; } else { @@ -9498,7 +9643,7 @@ static void escapeAliases() while ((in=value.find("^^",p))!=-1) { newValue+=value.mid(p,in-p); - newValue+="\\\\_linebr "; + newValue+="\\ilinebr "; p=in+2; } newValue+=value.mid(p,value.length()-p); @@ -9513,13 +9658,12 @@ void readAliases() { // add aliases to a dictionary Doxygen::aliasDict.setAutoDelete(TRUE); - QStrList &aliasList = Config_getList(ALIASES); - const char *s=aliasList.first(); - while (s) + const StringVector &aliasList = Config_getList(ALIASES); + for (const auto &s : aliasList) { - if (Doxygen::aliasDict[s]==0) + QCString alias=s.c_str(); + if (Doxygen::aliasDict[alias]==0) { - QCString alias=s; int i=alias.find('='); if (i>0) { @@ -9540,7 +9684,6 @@ void readAliases() } } } - s=aliasList.next(); } expandAliases(); escapeAliases(); @@ -9668,14 +9811,16 @@ static const char *getArg(int argc,char **argv,int &optind) class NullOutlineParser : public OutlineParserInterface { public: - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} - void parseInput(const char *, const char *,const std::shared_ptr<Entry> &, bool, QStrList &) {} + void parseInput(const char *, const char *,const std::shared_ptr<Entry> &, ClangTUParser*) {} bool needsPreprocessing(const QCString &) const { return FALSE; } void parsePrototype(const char *) {} }; +template<class T> std::function< std::unique_ptr<T>() > make_output_parser_factory() +{ + return []() { return std::make_unique<T>(); }; +} void initDoxygen() { @@ -9689,27 +9834,25 @@ void initDoxygen() Portable::correct_path(); Debug::startTimer(); - Doxygen::preprocessor = new Preprocessor(); - - Doxygen::parserManager = new ParserManager( std::make_unique<NullOutlineParser>(), + Doxygen::parserManager = new ParserManager( make_output_parser_factory<NullOutlineParser>(), std::make_unique<FileCodeParser>()); - Doxygen::parserManager->registerParser("c", std::make_unique<COutlineParser>(), + Doxygen::parserManager->registerParser("c", make_output_parser_factory<COutlineParser>(), std::make_unique<CCodeParser>()); - Doxygen::parserManager->registerParser("python", std::make_unique<PythonOutlineParser>(), + Doxygen::parserManager->registerParser("python", make_output_parser_factory<PythonOutlineParser>(), std::make_unique<PythonCodeParser>()); - Doxygen::parserManager->registerParser("fortran", std::make_unique<FortranOutlineParser>(), + Doxygen::parserManager->registerParser("fortran", make_output_parser_factory<FortranOutlineParser>(), std::make_unique<FortranCodeParser>()); - Doxygen::parserManager->registerParser("fortranfree", std::make_unique<FortranOutlineParserFree>(), + Doxygen::parserManager->registerParser("fortranfree", make_output_parser_factory<FortranOutlineParserFree>(), std::make_unique<FortranCodeParserFree>()); - Doxygen::parserManager->registerParser("fortranfixed", std::make_unique<FortranOutlineParserFixed>(), + Doxygen::parserManager->registerParser("fortranfixed", make_output_parser_factory<FortranOutlineParserFixed>(), std::make_unique<FortranCodeParserFixed>()); - Doxygen::parserManager->registerParser("vhdl", std::make_unique<VHDLOutlineParser>(), + Doxygen::parserManager->registerParser("vhdl", make_output_parser_factory<VHDLOutlineParser>(), std::make_unique<VHDLCodeParser>()); - Doxygen::parserManager->registerParser("xml", std::make_unique<NullOutlineParser>(), + Doxygen::parserManager->registerParser("xml", make_output_parser_factory<NullOutlineParser>(), std::make_unique<XMLCodeParser>()); - Doxygen::parserManager->registerParser("sql", std::make_unique<NullOutlineParser>(), + Doxygen::parserManager->registerParser("sql", make_output_parser_factory<NullOutlineParser>(), std::make_unique<SQLCodeParser>()); - Doxygen::parserManager->registerParser("md", std::make_unique<MarkdownOutlineParser>(), + Doxygen::parserManager->registerParser("md", make_output_parser_factory<MarkdownOutlineParser>(), std::make_unique<FileCodeParser>()); // register any additional parsers here... @@ -9788,7 +9931,6 @@ void cleanUpDoxygen() delete Doxygen::exampleSDict; delete Doxygen::globalScope; delete Doxygen::parserManager; - delete Doxygen::preprocessor; delete theTranslator; delete g_outputList; Mappers::freeMappers(); @@ -10250,14 +10392,6 @@ void adjustConfiguration() warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data()); } - QStrList &includePath = Config_getList(INCLUDE_PATH); - char *s=includePath.first(); - while (s) - { - QFileInfo fi(s); - Doxygen::preprocessor->addSearchDir(fi.absFilePath().utf8()); - s=includePath.next(); - } /* Set the global html file extension. */ Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION); @@ -10268,21 +10402,17 @@ void adjustConfiguration() Config_getBool(REFERENCES_RELATION) || Config_getBool(REFERENCED_BY_RELATION); - Doxygen::markdownSupport = Config_getBool(MARKDOWN_SUPPORT); - /************************************************************************** * Add custom extension mappings **************************************************************************/ - QStrList &extMaps = Config_getList(EXTENSION_MAPPING); - char *mapping = extMaps.first(); - while (mapping) + const StringVector &extMaps = Config_getList(EXTENSION_MAPPING); + for (const auto &mapping : extMaps) { - QCString mapStr = mapping; + QCString mapStr = mapping.c_str(); int i=mapStr.find('='); if (i==-1) { - mapping = extMaps.next(); continue; } else @@ -10291,7 +10421,6 @@ void adjustConfiguration() QCString language = mapStr.mid(i+1).stripWhiteSpace().lower(); if (ext.isEmpty() || language.isEmpty()) { - mapping = extMaps.next(); continue; } @@ -10307,23 +10436,20 @@ void adjustConfiguration() ext.data(),language.data()); } } - mapping = extMaps.next(); } // add predefined macro name to a dictionary - QStrList &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED); - s=expandAsDefinedList.first(); - while (s) + const StringVector &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED); + for (const auto &s : expandAsDefinedList) { - Doxygen::expandAsDefinedSet.insert(s); - s=expandAsDefinedList.next(); + Doxygen::expandAsDefinedSet.insert(s.c_str()); } // read aliases and store them in a dictionary readAliases(); // store number of spaces in a tab into Doxygen::spaces - int &tabSize = Config_getInt(TAB_SIZE); + int tabSize = Config_getInt(TAB_SIZE); Doxygen::spaces.resize(tabSize+1); int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' '; Doxygen::spaces.at(tabSize)='\0'; @@ -10353,7 +10479,7 @@ static void stopDoxygen(int) static void writeTagFile() { - QCString &generateTagFile = Config_getString(GENERATE_TAGFILE); + QCString generateTagFile = Config_getString(GENERATE_TAGFILE); if (generateTagFile.isEmpty()) return; QFile tag(generateTagFile); @@ -10456,26 +10582,26 @@ static void exitDoxygen() } static QCString createOutputDirectory(const QCString &baseDirName, - QCString &formatDirName, + const QCString &formatDirName, const char *defaultDirName) { - // Note the & on the next line, we modify the formatDirOption! - if (formatDirName.isEmpty()) + QCString result = formatDirName; + if (result.isEmpty()) { - formatDirName = baseDirName + defaultDirName; + result = baseDirName + defaultDirName; } else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':')) { - formatDirName.prepend(baseDirName+'/'); + result.prepend(baseDirName+'/'); } - QDir formatDir(formatDirName); - if (!formatDir.exists() && !formatDir.mkdir(formatDirName)) + QDir formatDir(result); + if (!formatDir.exists() && !formatDir.mkdir(result)) { - err("Could not create output directory %s\n", formatDirName.data()); + err("Could not create output directory %s\n", result.data()); cleanUpDoxygen(); exit(1); } - return formatDirName; + return result; } static QCString getQchFileName() @@ -10499,23 +10625,20 @@ void searchInputFiles() { StringUnorderedSet killSet; - QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS); + const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS); bool alwaysRecursive = Config_getBool(RECURSIVE); StringUnorderedSet excludeNameSet; // gather names of all files in the include path g_s.begin("Searching for include files...\n"); killSet.clear(); - QStrList &includePathList = Config_getList(INCLUDE_PATH); - char *s=includePathList.first(); - while (s) + const StringVector &includePathList = Config_getList(INCLUDE_PATH); + for (const auto &s : includePathList) { - QStrList &pl = Config_getList(INCLUDE_FILE_PATTERNS); - if (pl.count()==0) - { - pl = Config_getList(FILE_PATTERNS); - } - readFileOrDirectory(s, // s + size_t plSize = Config_getList(INCLUDE_FILE_PATTERNS).size(); + const StringVector &pl = plSize==0 ? Config_getList(FILE_PATTERNS) : + Config_getList(INCLUDE_FILE_PATTERNS); + readFileOrDirectory(s.c_str(), // s Doxygen::includeNameLinkedMap, // fnDict 0, // exclSet &pl, // patList @@ -10525,17 +10648,15 @@ void searchInputFiles() alwaysRecursive, // recursive TRUE, // errorIfNotExist &killSet); // killSet - s=includePathList.next(); } g_s.end(); g_s.begin("Searching for example files...\n"); killSet.clear(); - QStrList &examplePathList = Config_getList(EXAMPLE_PATH); - s=examplePathList.first(); - while (s) + const StringVector &examplePathList = Config_getList(EXAMPLE_PATH); + for (const auto &s : examplePathList) { - readFileOrDirectory(s, // s + readFileOrDirectory(s.c_str(), // s Doxygen::exampleNameLinkedMap, // fnDict 0, // exclSet &Config_getList(EXAMPLE_PATTERNS), // patList @@ -10545,17 +10666,15 @@ void searchInputFiles() (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)), // recursive TRUE, // errorIfNotExist &killSet); // killSet - s=examplePathList.next(); } g_s.end(); g_s.begin("Searching for images...\n"); killSet.clear(); - QStrList &imagePathList=Config_getList(IMAGE_PATH); - s=imagePathList.first(); - while (s) + const StringVector &imagePathList=Config_getList(IMAGE_PATH); + for (const auto &s : imagePathList) { - readFileOrDirectory(s, // s + readFileOrDirectory(s.c_str(), // s Doxygen::imageNameLinkedMap, // fnDict 0, // exclSet 0, // patList @@ -10565,17 +10684,15 @@ void searchInputFiles() alwaysRecursive, // recursive TRUE, // errorIfNotExist &killSet); // killSet - s=imagePathList.next(); } g_s.end(); g_s.begin("Searching for dot files...\n"); killSet.clear(); - QStrList &dotFileList=Config_getList(DOTFILE_DIRS); - s=dotFileList.first(); - while (s) + const StringVector &dotFileList=Config_getList(DOTFILE_DIRS); + for (const auto &s : dotFileList) { - readFileOrDirectory(s, // s + readFileOrDirectory(s.c_str(), // s Doxygen::dotFileNameLinkedMap, // fnDict 0, // exclSet 0, // patList @@ -10585,17 +10702,15 @@ void searchInputFiles() alwaysRecursive, // recursive TRUE, // errorIfNotExist &killSet); // killSet - s=dotFileList.next(); } g_s.end(); g_s.begin("Searching for msc files...\n"); killSet.clear(); - QStrList &mscFileList=Config_getList(MSCFILE_DIRS); - s=mscFileList.first(); - while (s) + const StringVector &mscFileList=Config_getList(MSCFILE_DIRS); + for (const auto &s : mscFileList) { - readFileOrDirectory(s, // s + readFileOrDirectory(s.c_str(), // s Doxygen::mscFileNameLinkedMap, // fnDict 0, // exclSet 0, // patList @@ -10605,17 +10720,15 @@ void searchInputFiles() alwaysRecursive, // recursive TRUE, // errorIfNotExist &killSet); // killSet - s=mscFileList.next(); } g_s.end(); g_s.begin("Searching for dia files...\n"); killSet.clear(); - QStrList &diaFileList=Config_getList(DIAFILE_DIRS); - s=diaFileList.first(); - while (s) + const StringVector &diaFileList=Config_getList(DIAFILE_DIRS); + for (const auto &s : diaFileList) { - readFileOrDirectory(s, // s + readFileOrDirectory(s.c_str(), // s Doxygen::diaFileNameLinkedMap, // fnDict 0, // exclSet 0, // patList @@ -10625,16 +10738,14 @@ void searchInputFiles() alwaysRecursive, // recursive TRUE, // errorIfNotExist &killSet); // killSet - s=diaFileList.next(); } g_s.end(); g_s.begin("Searching for files to exclude\n"); - QStrList &excludeList = Config_getList(EXCLUDE); - s=excludeList.first(); - while (s) + const StringVector &excludeList = Config_getList(EXCLUDE); + for (const auto &s : excludeList) { - readFileOrDirectory(s, // s + readFileOrDirectory(s.c_str(), // s 0, // fnDict 0, // exclSet &Config_getList(FILE_PATTERNS), // patList @@ -10643,7 +10754,6 @@ void searchInputFiles() &excludeNameSet, // resultSet alwaysRecursive, // recursive FALSE); // errorIfNotExist - s=excludeList.next(); // killSet } g_s.end(); @@ -10654,11 +10764,10 @@ void searchInputFiles() g_s.begin("Searching INPUT for files to process...\n"); killSet.clear(); Doxygen::inputPaths.clear(); - QStrList &inputList=Config_getList(INPUT); - s=inputList.first(); - while (s) + const StringVector &inputList=Config_getList(INPUT); + for (const auto &s : inputList) { - QCString path=s; + QCString path=s.c_str(); uint l = path.length(); if (l>0) { @@ -10678,7 +10787,6 @@ void searchInputFiles() &killSet, // killSet &Doxygen::inputPaths); // paths } - s=inputList.next(); } std::sort(Doxygen::inputNameLinkedMap->begin(), Doxygen::inputNameLinkedMap->end(), @@ -10696,6 +10804,10 @@ void parseInput() { atexit(exitDoxygen); +#if USE_LIBCLANG + Doxygen::clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); +#endif + // we would like to show the versionString earlier, but we first have to handle the configuration file // to know the value of the QUIET setting. QCString versionString = getFullVersion(); @@ -10704,10 +10816,10 @@ void parseInput() /************************************************************************** * Make sure the output directory exists **************************************************************************/ - QCString &outputDirectory = Config_getString(OUTPUT_DIRECTORY); + QCString outputDirectory = Config_getString(OUTPUT_DIRECTORY); if (outputDirectory.isEmpty()) { - outputDirectory=QDir::currentDirPath().utf8(); + outputDirectory = Config_updateString(OUTPUT_DIRECTORY,QDir::currentDirPath().utf8()); } else { @@ -10729,7 +10841,7 @@ void parseInput() } dir.cd(outputDirectory); } - outputDirectory=dir.absPath().utf8(); + outputDirectory = Config_updateString(OUTPUT_DIRECTORY,dir.absPath().utf8()); } /************************************************************************** @@ -10761,39 +10873,62 @@ void parseInput() **************************************************************************/ QCString htmlOutput; - bool &generateHtml = Config_getBool(GENERATE_HTML); + bool generateHtml = Config_getBool(GENERATE_HTML); if (generateHtml || g_useOutputTemplate /* TODO: temp hack */) + { htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html"); + Config_updateString(HTML_OUTPUT,htmlOutput); + } QCString docbookOutput; - bool &generateDocbook = Config_getBool(GENERATE_DOCBOOK); + bool generateDocbook = Config_getBool(GENERATE_DOCBOOK); if (generateDocbook) + { docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook"); + Config_updateString(DOCBOOK_OUTPUT,docbookOutput); + } QCString xmlOutput; - bool &generateXml = Config_getBool(GENERATE_XML); + bool generateXml = Config_getBool(GENERATE_XML); if (generateXml) + { xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml"); + Config_updateString(XML_OUTPUT,xmlOutput); + } QCString latexOutput; - bool &generateLatex = Config_getBool(GENERATE_LATEX); + bool generateLatex = Config_getBool(GENERATE_LATEX); if (generateLatex) - latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT),"/latex"); + { + latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT), "/latex"); + Config_updateString(LATEX_OUTPUT,latexOutput); + } QCString rtfOutput; - bool &generateRtf = Config_getBool(GENERATE_RTF); + bool generateRtf = Config_getBool(GENERATE_RTF); if (generateRtf) + { rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf"); + Config_updateString(RTF_OUTPUT,rtfOutput); + } QCString manOutput; - bool &generateMan = Config_getBool(GENERATE_MAN); + bool generateMan = Config_getBool(GENERATE_MAN); if (generateMan) + { manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man"); + Config_updateString(MAN_OUTPUT,manOutput); + } - //QCString sqlOutput; - //bool &generateSql = Config_getBool(GENERATE_SQLITE3); - //if (generateSql) - // sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3"); +#if USE_SQLITE3 + QCString sqlOutput; + bool generateSql = Config_getBool(GENERATE_SQLITE3); + if (generateSql) + { + sqlOutput = createOutputDirectory(outputDirectory,Config_getString(SQLITE3_OUTPUT),"/sqlite3"); + Config_updateString(SQLITE3_OUTPUT,sqlOutput); + } +#endif if (Config_getBool(HAVE_DOT)) { @@ -10822,11 +10957,11 @@ void parseInput() **************************************************************************/ LayoutDocManager::instance().init(); - QCString &layoutFileName = Config_getString(LAYOUT_FILE); + QCString layoutFileName = Config_getString(LAYOUT_FILE); bool defaultLayoutUsed = FALSE; if (layoutFileName.isEmpty()) { - layoutFileName = "DoxygenLayout.xml"; + layoutFileName = Config_updateString(LAYOUT_FILE,"DoxygenLayout.xml"); defaultLayoutUsed = TRUE; } @@ -10846,13 +10981,14 @@ void parseInput() **************************************************************************/ // prevent search in the output directories - QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS); - if (generateHtml) exclPatterns.append(htmlOutput); - if (generateDocbook) exclPatterns.append(docbookOutput); - if (generateXml) exclPatterns.append(xmlOutput); - if (generateLatex) exclPatterns.append(latexOutput); - if (generateRtf) exclPatterns.append(rtfOutput); - if (generateMan) exclPatterns.append(manOutput); + StringVector exclPatterns = Config_getList(EXCLUDE_PATTERNS); + if (generateHtml) exclPatterns.push_back(htmlOutput.data()); + if (generateDocbook) exclPatterns.push_back(docbookOutput.data()); + if (generateXml) exclPatterns.push_back(xmlOutput.data()); + if (generateLatex) exclPatterns.push_back(latexOutput.data()); + if (generateRtf) exclPatterns.push_back(rtfOutput.data()); + if (generateMan) exclPatterns.push_back(manOutput.data()); + Config_updateList(EXCLUDE_PATTERNS,exclPatterns); searchInputFiles(); @@ -10885,12 +11021,10 @@ void parseInput() std::shared_ptr<Entry> root = std::make_shared<Entry>(); msg("Reading and parsing tag files\n"); - QStrList &tagFileList = Config_getList(TAGFILES); - char *s=tagFileList.first(); - while (s) + const StringVector &tagFileList = Config_getList(TAGFILES); + for (const auto &s : tagFileList) { - readTagFile(root,s); - s=tagFileList.next(); + readTagFile(root,s.c_str()); } /************************************************************************** @@ -11411,12 +11545,14 @@ void generateOutput() Doxygen::generatingXmlOutput=FALSE; g_s.end(); } - if (USE_SQLITE3) +#if USE_SQLITE3 + if (Config_getBool(GENERATE_SQLITE3)) { g_s.begin("Generating SQLITE3 output...\n"); generateSqlite3(); g_s.end(); } +#endif if (Config_getBool(GENERATE_AUTOGEN_DEF)) { @@ -11554,7 +11690,7 @@ void generateOutput() if (Debug::isFlagSet(Debug::Time)) { msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n", - ((double)Debug::elapsedTime())/1000.0, + ((double)Debug::elapsedTime()), Portable::getSysElapsedTime() ); g_s.print(); diff --git a/src/doxygen.h b/src/doxygen.h index b824b54..e5757c3 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -30,6 +30,20 @@ #include "memberlist.h" #include "define.h" +#ifndef MULTITHREADED_INPUT +#define MULTITHREADED_INPUT 0 +#endif + +#if MULTITHREADED_INPUT +#define THREAD_LOCAL thread_local +#define AtomicInt std::atomic_int +#define AtomicBool std::atomic_bool +#else +#define THREAD_LOCAL +#define AtomicInt int +#define AtomicBool bool +#endif + class RefList; class PageSList; class PageSDict; @@ -136,10 +150,9 @@ class Doxygen static int subpageNestingLevel; static QCString spaces; static bool generatingXmlOutput; - static bool markdownSupport; static GenericsSDict *genericsDict; - static Preprocessor *preprocessor; - static DefineList macroDefinitions; + static DefinesPerFileList macroDefinitions; + static bool clangAssistedParsing; }; void initDoxygen(); @@ -154,8 +167,8 @@ void cleanUpDoxygen(); int readFileOrDirectory(const char *s, FileNameLinkedMap *fnDict, StringUnorderedSet *exclSet, - QStrList *patList, - QStrList *exclPatList, + const StringVector *patList, + const StringVector *exclPatList, StringVector *resultList, StringUnorderedSet *resultSet, bool recursive, diff --git a/src/entry.cpp b/src/entry.cpp index 0c7da99..6e343b0 100644 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -24,18 +24,15 @@ #include "doxygen.h" #include "arguments.h" #include "config.h" -//------------------------------------------------------------------ - -#define HEADER ('D'<<24)+('O'<<16)+('X'<<8)+'!' //------------------------------------------------------------------ -int Entry::num=0; +static AtomicInt g_num; Entry::Entry() { //printf("Entry::Entry(%p)\n",this); - num++; + g_num++; m_parent=0; section = EMPTY_SEC; //printf("Entry::Entry() tArgList=0\n"); @@ -50,7 +47,7 @@ Entry::Entry() Entry::Entry(const Entry &e) { //printf("Entry::Entry(%p):copy\n",this); - num++; + g_num++; section = e.section; type = e.type; name = e.name; @@ -123,11 +120,11 @@ Entry::Entry(const Entry &e) Entry::~Entry() { - //printf("Entry::~Entry(%p) num=%d\n",this,num); + //printf("Entry::~Entry(%p) num=%d\n",this,g_num); //printf("Deleting entry %d name %s type %x children %d\n", // num,name.data(),section,sublist->count()); - num--; + g_num--; } void Entry::moveToSubEntryAndRefresh(Entry *¤t) @@ -150,7 +147,7 @@ void Entry::moveToSubEntryAndKeep(Entry *current) m_sublist.emplace_back(current); } -void Entry::moveToSubEntryAndKeep(std::shared_ptr<Entry> ¤t) +void Entry::moveToSubEntryAndKeep(std::shared_ptr<Entry> current) { current->m_parent=this; m_sublist.push_back(current); @@ -183,10 +180,10 @@ void Entry::removeSubEntry(const Entry *e) void Entry::reset() { - static bool entryCallGraph = Config_getBool(CALL_GRAPH); - static bool entryCallerGraph = Config_getBool(CALLER_GRAPH); - static bool entryReferencedByRelation = Config_getBool(REFERENCED_BY_RELATION); - static bool entryReferencesRelation = Config_getBool(REFERENCES_RELATION); + bool entryCallGraph = Config_getBool(CALL_GRAPH); + bool entryCallerGraph = Config_getBool(CALLER_GRAPH); + bool entryReferencedByRelation = Config_getBool(REFERENCED_BY_RELATION); + bool entryReferencesRelation = Config_getBool(REFERENCES_RELATION); //printf("Entry::reset()\n"); name.resize(0); type.resize(0); diff --git a/src/entry.h b/src/entry.h index bdc8ab8..d6c0936 100644 --- a/src/entry.h +++ b/src/entry.h @@ -207,7 +207,7 @@ class Entry * @{ */ void moveToSubEntryAndKeep(Entry* e); - void moveToSubEntryAndKeep(std::shared_ptr<Entry> &e); + void moveToSubEntryAndKeep(std::shared_ptr<Entry> e); /*! @} */ /*! @name add entry as a child, pass ownership and reinitialize entry */ @@ -297,9 +297,6 @@ class Entry LocalToc localToc; QCString metaData; //!< Slice metadata - - static int num; //!< counts the total number of entries - /// return the command name used to define GROUPDOC_SEC const char *groupDocCmd() const { diff --git a/src/filedef.cpp b/src/filedef.cpp index 7e8afdc..658023b 100644 --- a/src/filedef.cpp +++ b/src/filedef.cpp @@ -55,7 +55,8 @@ class FileDefImpl : public DefinitionImpl, public FileDef virtual ~FileDefImpl(); virtual DefType definitionType() const { return TypeFile; } - virtual QCString name() const; + virtual const QCString &name() const; + virtual QCString displayName(bool=TRUE) const { return name(); } virtual QCString fileName() const { return m_fileName; } virtual QCString getOutputFileBase() const; @@ -81,7 +82,7 @@ class FileDefImpl : public DefinitionImpl, public FileDef virtual SDict<Definition> *getUsedClasses() const { return m_usingDeclList; } virtual QList<IncludeInfo> *includeFileList() const { return m_includeList; } virtual QList<IncludeInfo> *includedByFileList() const { return m_includedByList; } - virtual void getAllIncludeFilesRecursively(QStrList &incFiles) const; + virtual void getAllIncludeFilesRecursively(StringVector &incFiles) const; virtual MemberList *getMemberList(MemberListType lt) const; virtual const QList<MemberList> &getMemberLists() const { return m_memberLists; } virtual MemberGroupSDict *getMemberGroupSDict() const { return m_memberGroupSDict; } @@ -100,10 +101,8 @@ class FileDefImpl : public DefinitionImpl, public FileDef virtual void writeQuickMemberLinks(OutputList &ol,const MemberDef *currentMd) const; virtual void writeSummaryLinks(OutputList &ol) const; virtual void writeTagFile(FTextStream &t); - virtual void startParsing(); - virtual void writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu); - virtual void parseSource(bool sameTu,QStrList &filesInSameTu); - virtual void finishParsing(); + virtual void writeSource(OutputList &ol,ClangTUParser *clangParser); + virtual void parseSource(ClangTUParser *clangParser); virtual void setDiskName(const QCString &name); virtual void insertMember(MemberDef *md); virtual void insertClass(ClassDef *cd); @@ -116,7 +115,7 @@ class FileDefImpl : public DefinitionImpl, public FileDef virtual void combineUsingRelations(); virtual bool generateSourceFile() const; virtual void sortMemberLists(); - virtual void addIncludeDependency(FileDef *fd,const char *incName,bool local,bool imported,bool indirect); + virtual void addIncludeDependency(FileDef *fd,const char *incName,bool local,bool imported); virtual void addIncludedByDependency(FileDef *fd,const char *incName,bool local,bool imported); virtual void addMembersToMemberGroup(); virtual void distributeMemberGroupDocumentation(); @@ -356,25 +355,22 @@ void FileDefImpl::writeTagFile(FTextStream &tagFile) IncludeInfo *ii; for (;(ii=ili.current());++ili) { - if (!ii->indirect) + FileDef *fd=ii->fileDef; + if (fd && fd->isLinkable() && !fd->isReference()) { - FileDef *fd=ii->fileDef; - if (fd && fd->isLinkable() && !fd->isReference()) - { - bool isIDLorJava = FALSE; - SrcLangExt lang = fd->getLanguage(); - isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java; - const char *locStr = (ii->local || isIDLorJava) ? "yes" : "no"; - const char *impStr = (ii->imported || isIDLorJava) ? "yes" : "no"; - tagFile << " <includes id=\"" - << convertToXML(fd->getOutputFileBase()) << "\" " - << "name=\"" << convertToXML(fd->name()) << "\" " - << "local=\"" << locStr << "\" " - << "imported=\"" << impStr << "\">" - << convertToXML(ii->includeName) - << "</includes>" - << endl; - } + bool isIDLorJava = FALSE; + SrcLangExt lang = fd->getLanguage(); + isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java; + const char *locStr = (ii->local || isIDLorJava) ? "yes" : "no"; + const char *impStr = (ii->imported || isIDLorJava) ? "yes" : "no"; + tagFile << " <includes id=\"" + << convertToXML(fd->getOutputFileBase()) << "\" " + << "name=\"" << convertToXML(fd->name()) << "\" " + << "local=\"" << locStr << "\" " + << "imported=\"" << impStr << "\">" + << convertToXML(ii->includeName) + << "</includes>" + << endl; } } } @@ -476,7 +472,8 @@ void FileDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title) ol.startTextBlock(); if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF)) { - ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF) && !documentation().isEmpty()) @@ -493,7 +490,8 @@ void FileDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title) } if (!documentation().isEmpty()) { - ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } //printf("Writing source ref for file %s\n",name().data()); if (Config_getBool(SOURCE_BROWSER)) @@ -541,7 +539,8 @@ void FileDefImpl::writeBriefDescription(OutputList &ol) if (hasBriefDescription()) { DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(),this,0, - briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + briefDescription(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (rootNode && !rootNode->isEmpty()) { @@ -596,61 +595,58 @@ void FileDefImpl::writeIncludeFiles(OutputList &ol) IncludeInfo *ii; for (;(ii=ili.current());++ili) { - if (!ii->indirect) + FileDef *fd=ii->fileDef; + bool isIDLorJava = FALSE; + if (fd) { - FileDef *fd=ii->fileDef; - bool isIDLorJava = FALSE; - if (fd) - { - SrcLangExt lang = fd->getLanguage(); - isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java; - } - ol.startTypewriter(); - if (isIDLorJava) // IDL/Java include - { - ol.docify("import "); - } - else if (ii->imported) // Objective-C include - { - ol.docify("#import "); - } - else // C/C++ include - { - ol.docify("#include "); - } - if (ii->local || isIDLorJava) - ol.docify("\""); - else - ol.docify("<"); - ol.disable(OutputGenerator::Html); - ol.docify(ii->includeName); - ol.enableAll(); - ol.disableAllBut(OutputGenerator::Html); - - // Here we use the include file name as it appears in the file. - // we could also we the name as it is used within doxygen, - // then we should have used fd->docName() instead of ii->includeName - if (fd && fd->isLinkable()) - { - ol.writeObjectLink(fd->getReference(), - fd->generateSourceFile() ? fd->includeName() : fd->getOutputFileBase(), - 0,ii->includeName); - } - else - { - ol.docify(ii->includeName); - } + SrcLangExt lang = fd->getLanguage(); + isIDLorJava = lang==SrcLangExt_IDL || lang==SrcLangExt_Java; + } + ol.startTypewriter(); + if (isIDLorJava) // IDL/Java include + { + ol.docify("import "); + } + else if (ii->imported) // Objective-C include + { + ol.docify("#import "); + } + else // C/C++ include + { + ol.docify("#include "); + } + if (ii->local || isIDLorJava) + ol.docify("\""); + else + ol.docify("<"); + ol.disable(OutputGenerator::Html); + ol.docify(ii->includeName); + ol.enableAll(); + ol.disableAllBut(OutputGenerator::Html); - ol.enableAll(); - if (ii->local || isIDLorJava) - ol.docify("\""); - else - ol.docify(">"); - if (isIDLorJava) - ol.docify(";"); - ol.endTypewriter(); - ol.lineBreak(); + // Here we use the include file name as it appears in the file. + // we could also we the name as it is used within doxygen, + // then we should have used fd->docName() instead of ii->includeName + if (fd && fd->isLinkable()) + { + ol.writeObjectLink(fd->getReference(), + fd->generateSourceFile() ? fd->includeName() : fd->getOutputFileBase(), + 0,ii->includeName); + } + else + { + ol.docify(ii->includeName); } + + ol.enableAll(); + if (ii->local || isIDLorJava) + ol.docify("\""); + else + ol.docify(">"); + if (isIDLorJava) + ol.docify(";"); + ol.endTypewriter(); + ol.lineBreak(); } ol.endTextBlock(); } @@ -1153,7 +1149,7 @@ void FileDefImpl::writeQuickMemberLinks(OutputList &ol,const MemberDef *currentM } /*! Write a source listing of this file to the output */ -void FileDefImpl::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu) +void FileDefImpl::writeSource(OutputList &ol,ClangTUParser *clangParser) { static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW); static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); @@ -1211,23 +1207,13 @@ void FileDefImpl::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu ol.popGeneratorState(); } - (void)sameTu; - (void)filesInSameTu; #if USE_LIBCLANG - static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); - if (clangAssistedParsing && + if (Doxygen::clangAssistedParsing && clangParser && (getLanguage()==SrcLangExt_Cpp || getLanguage()==SrcLangExt_ObjC)) { ol.startCodeFragment(); - if (!sameTu) - { - ClangParser::instance()->start(absFilePath(),filesInSameTu); - } - else - { - ClangParser::instance()->switchToFile(absFilePath()); - } - ClangParser::instance()->writeSources(ol,this); + clangParser->switchToFile(this); + clangParser->writeSources(ol,this); ol.endCodeFragment(); } else @@ -1271,26 +1257,16 @@ void FileDefImpl::writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu ol.enableAll(); } -void FileDefImpl::parseSource(bool sameTu,QStrList &filesInSameTu) +void FileDefImpl::parseSource(ClangTUParser *clangParser) { static bool filterSourceFiles = Config_getBool(FILTER_SOURCE_FILES); DevNullCodeDocInterface devNullIntf; - (void)sameTu; - (void)filesInSameTu; #if USE_LIBCLANG - static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING); - if (clangAssistedParsing && + if (Doxygen::clangAssistedParsing && clangParser && (getLanguage()==SrcLangExt_Cpp || getLanguage()==SrcLangExt_ObjC)) { - if (!sameTu) - { - ClangParser::instance()->start(absFilePath(),filesInSameTu); - } - else - { - ClangParser::instance()->switchToFile(absFilePath()); - } - ClangParser::instance()->writeSources(devNullIntf,this); + clangParser->switchToFile(this); + clangParser->writeSources(devNullIntf,this); } else #endif @@ -1306,15 +1282,6 @@ void FileDefImpl::parseSource(bool sameTu,QStrList &filesInSameTu) } } -void FileDefImpl::startParsing() -{ -} - -void FileDefImpl::finishParsing() -{ - ClangParser::instance()->finish(); -} - void FileDefImpl::addMembersToMemberGroup() { QListIterator<MemberList> mli(m_memberLists); @@ -1464,7 +1431,7 @@ void FileDefImpl::insertNamespace(NamespaceDef *nd) } } -QCString FileDefImpl::name() const +const QCString &FileDefImpl::name() const { if (Config_getBool(FULL_PATH_NAMES)) return m_fileName; @@ -1540,8 +1507,7 @@ void FileDefImpl::addUsingDeclaration(Definition *d) } } -void FileDefImpl::addIncludeDependency(FileDef *fd,const char *incName,bool local, - bool imported,bool indirect) +void FileDefImpl::addIncludeDependency(FileDef *fd,const char *incName,bool local,bool imported) { //printf("FileDefImpl::addIncludeDependency(%p,%s,%d)\n",fd,incName,local); QCString iName = fd ? fd->absFilePath().data() : incName; @@ -1558,7 +1524,6 @@ void FileDefImpl::addIncludeDependency(FileDef *fd,const char *incName,bool loca ii->includeName = incName; ii->local = local; ii->imported = imported; - ii->indirect = indirect; m_includeList->append(ii); m_includeDict->insert(iName,ii); } @@ -1655,7 +1620,6 @@ void FileDefImpl::addIncludedByDependency(FileDef *fd,const char *incName, ii->includeName = incName; ii->local = local; ii->imported = imported; - ii->indirect = FALSE; m_includedByList->append(ii); m_includedByDict->insert(iName,ii); } @@ -2166,7 +2130,7 @@ bool FileDefImpl::isLinkableInProject() const } static void getAllIncludeFilesRecursively( - QDict<void> *filesVisited,const FileDef *fd,QStrList &incFiles) + StringUnorderedSet &filesVisited,const FileDef *fd,StringVector &incFiles) { if (fd->includeFileList()) { @@ -2175,21 +2139,21 @@ static void getAllIncludeFilesRecursively( for (iii.toFirst();(ii=iii.current());++iii) { if (ii->fileDef && !ii->fileDef->isReference() && - !filesVisited->find(ii->fileDef->absFilePath())) + filesVisited.find(ii->fileDef->absFilePath().str())==filesVisited.end()) { //printf("FileDefImpl::addIncludeDependency(%s)\n",ii->fileDef->absFilePath().data()); - incFiles.append(ii->fileDef->absFilePath()); - filesVisited->insert(ii->fileDef->absFilePath(),(void*)0x8); + incFiles.push_back(ii->fileDef->absFilePath().str()); + filesVisited.insert(ii->fileDef->absFilePath().str()); getAllIncludeFilesRecursively(filesVisited,ii->fileDef,incFiles); } } } } -void FileDefImpl::getAllIncludeFilesRecursively(QStrList &incFiles) const +void FileDefImpl::getAllIncludeFilesRecursively(StringVector &incFiles) const { - QDict<void> includes(257); - ::getAllIncludeFilesRecursively(&includes,this,incFiles); + StringUnorderedSet includes; + ::getAllIncludeFilesRecursively(includes,this,incFiles); } QCString FileDefImpl::title() const diff --git a/src/filedef.h b/src/filedef.h index 2ca33db..e4bb549 100644 --- a/src/filedef.h +++ b/src/filedef.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -25,6 +25,7 @@ #include "definition.h" #include "sortdict.h" #include "memberlist.h" +#include "containers.h" class MemberList; class FileDef; @@ -40,24 +41,24 @@ class MemberGroupSDict; class PackageDef; class DirDef; class FTextStream; +class ClangTUParser; /** Class representing the data associated with a \#include statement. */ struct IncludeInfo { - IncludeInfo() : fileDef(0), local(FALSE), imported(FALSE), indirect(FALSE) {} + IncludeInfo() : fileDef(0), local(FALSE), imported(FALSE) {} ~IncludeInfo() {} FileDef *fileDef; QCString includeName; bool local; bool imported; - bool indirect; }; -/** A model of a file symbol. - * +/** A model of a file symbol. + * * An object of this class contains all file information that is gathered. * This includes the members and compounds defined in the file. - * + * * The member writeDocumentation() can be used to generate the page of * documentation to HTML and LaTeX. */ @@ -71,7 +72,7 @@ class FileDef : virtual public Definition virtual DefType definitionType() const = 0; /*! Returns the unique file name (this may include part of the path). */ - virtual QCString name() const = 0; + virtual const QCString &name() const = 0; virtual QCString displayName(bool=TRUE) const = 0; virtual QCString fileName() const = 0; @@ -119,7 +120,7 @@ class FileDef : virtual public Definition virtual SDict<Definition> *getUsedClasses() const = 0; virtual QList<IncludeInfo> *includeFileList() const = 0; virtual QList<IncludeInfo> *includedByFileList() const = 0; - virtual void getAllIncludeFilesRecursively(QStrList &incFiles) const = 0; + virtual void getAllIncludeFilesRecursively(StringVector &incFiles) const = 0; virtual MemberList *getMemberList(MemberListType lt) const = 0; virtual const QList<MemberList> &getMemberLists() const = 0; @@ -149,10 +150,8 @@ class FileDef : virtual public Definition virtual void writeSummaryLinks(OutputList &ol) const = 0; virtual void writeTagFile(FTextStream &t) = 0; - virtual void startParsing() = 0; - virtual void writeSource(OutputList &ol,bool sameTu,QStrList &filesInSameTu) = 0; - virtual void parseSource(bool sameTu,QStrList &filesInSameTu) = 0; - virtual void finishParsing() = 0; + virtual void writeSource(OutputList &ol,ClangTUParser *clangParser) = 0; + virtual void parseSource(ClangTUParser *clangParser) = 0; virtual void setDiskName(const QCString &name) = 0; virtual void insertMember(MemberDef *md) = 0; @@ -170,7 +169,7 @@ class FileDef : virtual public Definition virtual bool generateSourceFile() const = 0; virtual void sortMemberLists() = 0; - virtual void addIncludeDependency(FileDef *fd,const char *incName,bool local,bool imported,bool indirect) = 0; + virtual void addIncludeDependency(FileDef *fd,const char *incName,bool local,bool imported) = 0; virtual void addIncludedByDependency(FileDef *fd,const char *incName,bool local,bool imported) = 0; virtual void addMembersToMemberGroup() = 0; @@ -228,11 +227,11 @@ class DirEntry { public: enum EntryKind { Dir, File }; - DirEntry(DirEntry *parent,FileDef *fd) - : m_parent(parent), m_name(fd->name()), m_kind(File), m_fd(fd), + DirEntry(DirEntry *parent,FileDef *fd) + : m_parent(parent), m_name(fd->name()), m_kind(File), m_fd(fd), m_isLast(FALSE) { } - DirEntry(DirEntry *parent,QCString name) - : m_parent(parent), m_name(name), m_kind(Dir), + DirEntry(DirEntry *parent,QCString name) + : m_parent(parent), m_name(name), m_kind(Dir), m_fd(0), m_isLast(FALSE) { } virtual ~DirEntry() { } EntryKind kind() const { return m_kind; } @@ -257,7 +256,7 @@ class DirEntry class Directory : public DirEntry { public: - Directory(Directory *parent,const QCString &name) + Directory(Directory *parent,const QCString &name) : DirEntry(parent,name) { m_children.setAutoDelete(TRUE); } virtual ~Directory() {} diff --git a/src/fortranscanner.h b/src/fortranscanner.h index 6ffcb1f..0e67bb2 100644 --- a/src/fortranscanner.h +++ b/src/fortranscanner.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -29,13 +29,10 @@ class FortranOutlineParser : public OutlineParserInterface public: FortranOutlineParser(FortranFormat format=FortranFormat_Unknown); ~FortranOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &extension) const; void parsePrototype(const char *text); diff --git a/src/fortranscanner.l b/src/fortranscanner.l index 852c4d9..cf48a3e 100644 --- a/src/fortranscanner.l +++ b/src/fortranscanner.l @@ -467,6 +467,7 @@ SCOPENAME ({ID}{BS}"::"{BS})* <Use>{ID} { DBG_CTX((stderr,"using dir %s\n",yytext)); yyextra->current->name=yytext; + yyextra->current->name=yyextra->current->name.lower(); yyextra->current->fileName = yyextra->fileName; yyextra->current->section=Entry::USINGDIR_SEC; yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current); @@ -475,12 +476,14 @@ SCOPENAME ({ID}{BS}"::"{BS})* } <Use>{ID}/, { yyextra->useModuleName=yytext; + yyextra->useModuleName=yyextra->useModuleName.lower(); } <Use>,{BS}"ONLY" { BEGIN(UseOnly); } <UseOnly>{BS},{BS} {} <UseOnly>{ID} { yyextra->current->name= yyextra->useModuleName+"::"+yytext; + yyextra->current->name=yyextra->current->name.lower(); yyextra->current->fileName = yyextra->fileName; yyextra->current->section=Entry::USINGDECL_SEC; yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current); @@ -2514,7 +2517,8 @@ static void handleCommentBlock(yyscan_t yyscanner,const QCString &doc,bool brief int lineNr = brief ? yyextra->current->briefLine : yyextra->current->docLine; int position=0; bool needsEntry = FALSE; - QCString processedDoc = processMarkdownForCommentBlock(doc,yyextra->fileName,lineNr); + Markdown markdown(yyextra->fileName,lineNr); + QCString processedDoc = Config_getBool(MARKDOWN_SUPPORT) ? markdown.process(doc,lineNr) : doc; while (yyextra->commentScanner.parseCommentBlock( yyextra->thisParser, yyextra->docBlockInBody ? yyextra->subrCurrent.back().get() : yyextra->current.get(), @@ -2526,8 +2530,9 @@ static void handleCommentBlock(yyscan_t yyscanner,const QCString &doc,bool brief yyextra->docBlockInBody, yyextra->defaultProtection, position, - needsEntry - )) + needsEntry, + Config_getBool(MARKDOWN_SUPPORT) + )) { DBG_CTX((stderr,"parseCommentBlock position=%d [%s] needsEntry=%d\n",position,doc.data()+position,needsEntry)); if (needsEntry) addCurrentEntry(yyscanner,false); @@ -2801,8 +2806,7 @@ FortranOutlineParser::~FortranOutlineParser() void FortranOutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool /*sameTranslationUnit*/, - QStrList & /*filesInSameTranslationUnit*/) + ClangTUParser * /*clangParser*/) { struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; yyextra->thisParser = this; diff --git a/src/ftextstream.h b/src/ftextstream.h index bfc5bd5..5b6a9ca 100644 --- a/src/ftextstream.h +++ b/src/ftextstream.h @@ -60,7 +60,8 @@ inline FTextStream &FTextStream::operator<<( const char* s) inline FTextStream &FTextStream::operator<<( const QCString &s) { - return operator<<(s.data()); + if (m_dev) m_dev->writeBlock( s, s.length() ); + return *this; } typedef FTextStream & (*FTSFUNC)(FTextStream &);// manipulator function diff --git a/src/ftvhelp.cpp b/src/ftvhelp.cpp index cb50af1..6fc14bf 100644 --- a/src/ftvhelp.cpp +++ b/src/ftvhelp.cpp @@ -348,7 +348,8 @@ static void generateBriefDoc(FTextStream &t,const Definition *def) if (!brief.isEmpty()) { DocNode *root = validatingParseDoc(def->briefFile(),def->briefLine(), - def,0,brief,FALSE,FALSE,0,TRUE,TRUE); + def,0,brief,FALSE,FALSE, + 0,TRUE,TRUE,Config_getBool(MARKDOWN_SUPPORT)); QCString relPath = relativePathToRoot(def->getOutputFileBase()); HtmlCodeGenerator htmlGen(t,relPath); HtmlDocVisitor *visitor = new HtmlDocVisitor(t,htmlGen,def); @@ -669,7 +670,7 @@ static void generateJSNavTree(const QList<FTVNode> &nodeList) t << "var NAVTREE =" << endl; t << "[" << endl; t << " [ "; - QCString &projName = Config_getString(PROJECT_NAME); + QCString projName = Config_getString(PROJECT_NAME); if (projName.isEmpty()) { if (mainPageHasTitle()) // Use title of main page as root diff --git a/src/groupdef.cpp b/src/groupdef.cpp index 3b4d537..9b33356 100644 --- a/src/groupdef.cpp +++ b/src/groupdef.cpp @@ -834,7 +834,8 @@ void GroupDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title // repeat brief description if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF)) { - ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } // write separator between brief and details if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF) && @@ -854,13 +855,15 @@ void GroupDefImpl::writeDetailedDescription(OutputList &ol,const QCString &title // write detailed documentation if (!documentation().isEmpty()) { - ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } // write inbody documentation if (!inbodyDocumentation().isEmpty()) { - ol.generateDoc(inbodyFile(),inbodyLine(),this,0,inbodyDocumentation()+"\n",TRUE,FALSE); + ol.generateDoc(inbodyFile(),inbodyLine(),this,0,inbodyDocumentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } } } @@ -870,7 +873,8 @@ void GroupDefImpl::writeBriefDescription(OutputList &ol) if (hasBriefDescription()) { DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(),this,0, - briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + briefDescription(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (rootNode && !rootNode->isEmpty()) { ol.startParagraph(); @@ -944,7 +948,8 @@ void GroupDefImpl::writeFiles(OutputList &ol,const QCString &title) if (!fd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC)) { ol.startMemberDescription(fd->getOutputFileBase()); - ol.generateDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + ol.generateDoc(briefFile(),briefLine(),fd,0,fd->briefDescription(),FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberDescription(); } ol.endMemberDeclaration(0,0); @@ -999,7 +1004,8 @@ void GroupDefImpl::writeNestedGroups(OutputList &ol,const QCString &title) if (!gd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC)) { ol.startMemberDescription(gd->getOutputFileBase()); - ol.generateDoc(briefFile(),briefLine(),gd,0,gd->briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + ol.generateDoc(briefFile(),briefLine(),gd,0,gd->briefDescription(),FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberDescription(); } ol.endMemberDeclaration(0,0); @@ -1030,7 +1036,8 @@ void GroupDefImpl::writeDirs(OutputList &ol,const QCString &title) if (!dd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC)) { ol.startMemberDescription(dd->getOutputFileBase()); - ol.generateDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(),FALSE,FALSE,0,TRUE,FALSE); + ol.generateDoc(briefFile(),briefLine(),dd,0,dd->briefDescription(),FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberDescription(); } ol.endMemberDeclaration(0,0); @@ -1068,7 +1075,8 @@ void GroupDefImpl::writePageDocumentation(OutputList &ol) ol.endSection(si->label(),SectionType::Subsection); } ol.startTextBlock(); - ol.generateDoc(pd->docFile(),pd->docLine(),pd,0,pd->documentation()+pd->inbodyDocumentation(),TRUE,FALSE,0,TRUE,FALSE); + ol.generateDoc(pd->docFile(),pd->docLine(),pd,0,pd->documentation()+pd->inbodyDocumentation(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endTextBlock(); } } @@ -1199,6 +1207,11 @@ void GroupDefImpl::writeDocumentation(OutputList &ol) ol.pushGeneratorState(); ol.disableAllBut(OutputGenerator::Man); ol.endTitleHead(getOutputFileBase(),name()); + if (!m_title.isEmpty()) + { + ol.writeString(" - "); + ol.parseText(m_title); + } ol.popGeneratorState(); ol.endHeaderSection(); ol.startContents(); diff --git a/src/growbuf.h b/src/growbuf.h index cd6a67b..2f8075b 100644 --- a/src/growbuf.h +++ b/src/growbuf.h @@ -13,6 +13,7 @@ class GrowBuf GrowBuf() : m_str(0), m_pos(0), m_len(0) {} GrowBuf(uint initialSize) : m_pos(0), m_len(initialSize) { m_str=(char*)malloc(m_len); } ~GrowBuf() { free(m_str); } + void reserve(uint size) { if (m_len<size) { m_len = size; m_str = (char*)realloc(m_str,m_len); } } void clear() { m_pos=0; } void addChar(char c) { if (m_pos>=m_len) { m_len+=GROW_AMOUNT; m_str = (char*)realloc(m_str,m_len); } m_str[m_pos++]=c; diff --git a/src/htags.cpp b/src/htags.cpp index 1a240b1..0c3a9af 100644 --- a/src/htags.cpp +++ b/src/htags.cpp @@ -3,8 +3,8 @@ * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -36,25 +36,25 @@ static QDict<QCString> g_symbolDict(10007); */ bool Htags::execute(const QCString &htmldir) { - static QStrList &inputSource = Config_getList(INPUT); - static bool quiet = Config_getBool(QUIET); - static bool warnings = Config_getBool(WARNINGS); - static QCString htagsOptions = ""; //Config_getString(HTAGS_OPTIONS); - static QCString projectName = Config_getString(PROJECT_NAME); - static QCString projectNumber = Config_getString(PROJECT_NUMBER); + const StringVector &inputSource = Config_getList(INPUT); + bool quiet = Config_getBool(QUIET); + bool warnings = Config_getBool(WARNINGS); + QCString htagsOptions = ""; //Config_getString(HTAGS_OPTIONS); + QCString projectName = Config_getString(PROJECT_NAME); + QCString projectNumber = Config_getString(PROJECT_NUMBER); QCString cwd = QDir::currentDirPath().utf8(); - if (inputSource.isEmpty()) + if (inputSource.empty()) { g_inputDir.setPath(cwd); } - else if (inputSource.count()==1) + else if (inputSource.size()==1) { - g_inputDir.setPath(inputSource.first()); + g_inputDir.setPath(inputSource.back().c_str()); if (!g_inputDir.exists()) err("Cannot find directory %s. " "Check the value of the INPUT tag in the configuration file.\n", - inputSource.first() + inputSource.back().c_str() ); } else @@ -69,16 +69,16 @@ bool Htags::execute(const QCString &htmldir) QCString commandLine = " -g -s -a -n "; if (!quiet) commandLine += "-v "; if (warnings) commandLine += "-w "; - if (!htagsOptions.isEmpty()) + if (!htagsOptions.isEmpty()) { commandLine += ' '; commandLine += htagsOptions; } - if (!projectName.isEmpty()) + if (!projectName.isEmpty()) { commandLine += "-t \""; commandLine += projectName; - if (!projectNumber.isEmpty()) + if (!projectNumber.isEmpty()) { commandLine += '-'; commandLine += projectNumber; @@ -150,7 +150,7 @@ bool Htags::loadFilemap(const QCString &htmlDir) } else { - err("file %s cannot be opened\n",fileMapName.data()); + err("file %s cannot be opened\n",fileMapName.data()); } } return FALSE; diff --git a/src/htmlgen.cpp b/src/htmlgen.cpp index 7458b23..7b125af 100644 --- a/src/htmlgen.cpp +++ b/src/htmlgen.cpp @@ -67,7 +67,7 @@ static void writeClientSearchBox(FTextStream &t,const char *relPath) { t << " <div id=\"MSearchBox\" class=\"MSearchBoxInactive\">\n"; t << " <span class=\"left\">\n"; - t << " <img id=\"MSearchSelect\" src=\"" << relPath << "search/mag_sel.png\"\n"; + t << " <img id=\"MSearchSelect\" src=\"" << relPath << "search/mag_sel.svg\"\n"; t << " onmouseover=\"return searchBox.OnSearchSelectShow()\"\n"; t << " onmouseout=\"return searchBox.OnSearchSelectHide()\"\n"; t << " alt=\"\"/>\n"; @@ -78,7 +78,7 @@ static void writeClientSearchBox(FTextStream &t,const char *relPath) t << " onkeyup=\"searchBox.OnSearchFieldChange(event)\"/>\n"; t << " </span><span class=\"right\">\n"; t << " <a id=\"MSearchClose\" href=\"javascript:searchBox.CloseResultsWindow()\">" - << "<img id=\"MSearchCloseImg\" border=\"0\" src=\"" << relPath << "search/close.png\" alt=\"\"/></a>\n"; + << "<img id=\"MSearchCloseImg\" border=\"0\" src=\"" << relPath << "search/close.svg\" alt=\"\"/></a>\n"; t << " </span>\n"; t << " </div>\n"; } @@ -100,7 +100,7 @@ static void writeServerSearchBox(FTextStream &t,const char *relPath,bool highlig t << "search.php"; } t << "\" method=\"get\">\n"; - t << " <img id=\"MSearchSelect\" src=\"" << relPath << "search/mag.png\" alt=\"\"/>\n"; + t << " <img id=\"MSearchSelect\" src=\"" << relPath << "search/mag.svg\" alt=\"\"/>\n"; if (!highlightSearch) { t << " <input type=\"text\" id=\"MSearchField\" name=\"query\" value=\"" @@ -415,7 +415,6 @@ static QCString substituteHtmlKeywords(const QCString &str, { // Build CSS/JavaScript tags depending on treeview, search engine settings QCString cssFile; - QStrList extraCssFile; QCString generatedBy; QCString treeViewCssJs; QCString searchCssJs; @@ -456,10 +455,10 @@ static QCString substituteHtmlKeywords(const QCString &str, } extraCssText = ""; - extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET); - for (uint i=0; i<extraCssFile.count(); ++i) + const StringVector &extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET); + for (const auto &extraFile : extraCssFile) { - QCString fileName(extraCssFile.at(i)); + QCString fileName = extraFile.c_str(); if (!fileName.isEmpty()) { QFileInfo fi(fileName); @@ -541,12 +540,10 @@ static QCString substituteHtmlKeywords(const QCString &str, mathJaxJs = "<script type=\"text/x-mathjax-config\">\n" " MathJax.Hub.Config({\n" " extensions: [\"tex2jax.js\""; - QStrList &mathJaxExtensions = Config_getList(MATHJAX_EXTENSIONS); - const char *s = mathJaxExtensions.first(); - while (s) + const StringVector &mathJaxExtensions = Config_getList(MATHJAX_EXTENSIONS); + for (const auto &s : mathJaxExtensions) { - mathJaxJs+= ", \""+QCString(s)+".js\""; - s = mathJaxExtensions.next(); + mathJaxJs+= ", \""+QCString(s.c_str())+".js\""; } if (mathJaxFormat.isEmpty()) { @@ -1019,7 +1016,7 @@ void HtmlGenerator::writeTabData() mgr.copyResource("nav_h.lum",dname); mgr.copyResource("nav_f.lum",dname); mgr.copyResource("bc_s.luma",dname); - mgr.copyResource("doxygen.luma",dname); + mgr.copyResource("doxygen.svg",dname); mgr.copyResource("closed.luma",dname); mgr.copyResource("open.luma",dname); mgr.copyResource("bdwn.luma",dname); @@ -1049,15 +1046,15 @@ void HtmlGenerator::writeSearchData(const char *dir) Doxygen::indexList->addImageFile("search/search_r.png"); if (serverBasedSearch) { - mgr.copyResource("mag.png",dir); - Doxygen::indexList->addImageFile("search/mag.png"); + mgr.copyResource("mag.svg",dir); + Doxygen::indexList->addImageFile("search/mag.svg"); } else { - mgr.copyResource("close.png",dir); - Doxygen::indexList->addImageFile("search/close.png"); - mgr.copyResource("mag_sel.png",dir); - Doxygen::indexList->addImageFile("search/mag_sel.png"); + mgr.copyResource("close.svg",dir); + Doxygen::indexList->addImageFile("search/close.svg"); + mgr.copyResource("mag_sel.svg",dir); + Doxygen::indexList->addImageFile("search/mag_sel.svg"); } QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search"; @@ -1184,7 +1181,7 @@ QCString HtmlGenerator::writeLogoAsString(const char *path) result += " \n<a href=\"http://www.doxygen.org/index.html\">\n" "<img class=\"footer\" src=\""; result += path; - result += "doxygen.png\" alt=\"doxygen\"/></a> "; + result += "doxygen.svg\" width=\"104\" height=\"31\" alt=\"doxygen\"/></a> "; result += getDoxygenVersion(); result += " "; return result; @@ -1261,10 +1258,10 @@ void HtmlGenerator::writeStyleInfo(int part) } Doxygen::indexList->addStyleSheetFile(cssfi.fileName().utf8()); } - static QStrList extraCssFile = Config_getList(HTML_EXTRA_STYLESHEET); - for (uint i=0; i<extraCssFile.count(); ++i) + const StringVector &extraCssFiles = Config_getList(HTML_EXTRA_STYLESHEET); + for (const auto &extraCss : extraCssFiles) { - QCString fileName(extraCssFile.at(i)); + QCString fileName = extraCss.c_str(); if (!fileName.isEmpty()) { QFileInfo fi(fileName); @@ -2768,11 +2765,10 @@ void HtmlGenerator::writeExternalSearchPage() t << "var tagMap = {" << endl; bool first=TRUE; // add search mappings - QStrList &extraSearchMappings = Config_getList(EXTRA_SEARCH_MAPPINGS); - char *ml=extraSearchMappings.first(); - while (ml) + const StringVector &extraSearchMappings = Config_getList(EXTRA_SEARCH_MAPPINGS); + for (const auto &ml : extraSearchMappings) { - QCString mapLine = ml; + QCString mapLine = ml.c_str(); int eqPos = mapLine.find('='); if (eqPos!=-1) // tag command contains a destination { @@ -2785,7 +2781,6 @@ void HtmlGenerator::writeExternalSearchPage() first=FALSE; } } - ml=extraSearchMappings.next(); } if (!first) t << endl; t << "};" << endl << endl; diff --git a/src/htmlhelp.cpp b/src/htmlhelp.cpp index 6eb2efa..f5856e5 100644 --- a/src/htmlhelp.cpp +++ b/src/htmlhelp.cpp @@ -173,7 +173,7 @@ void HtmlHelpIndex::writeFields(FTextStream &t) dict->sort(); IndexFieldSDict::Iterator ifli(*dict); IndexField *f; - QCString lastLevel1; + QCString prevLevel1; bool level2Started=FALSE; for (;(f=ifli.current());++ifli) { @@ -189,7 +189,6 @@ void HtmlHelpIndex::writeFields(FTextStream &t) level1 = f->name.copy(); } - //if (level1!=lastLevel1) { // finish old list at level 2 if (level2Started) t << " </UL>" << endl; level2Started=FALSE; @@ -208,10 +207,11 @@ void HtmlHelpIndex::writeFields(FTextStream &t) nextLevel1 = fnext->name.left(fnext->name.find('?')); --ifli; } - if (level1 != nextLevel1) + if (!(level1 == prevLevel1 || level1 == nextLevel1)) { level2 = ""; } + prevLevel1 = level1.copy(); // </Antony> if (level2.isEmpty()) @@ -259,7 +259,6 @@ void HtmlHelpIndex::writeFields(FTextStream &t) t << "<param name=\"Name\" value=\"" << m_help->recode(level2) << "\">" "</OBJECT>\n"; } - lastLevel1 = level1.copy(); } if (level2Started) t << " </UL>" << endl; } @@ -422,7 +421,7 @@ void HtmlHelp::initialize() s_languageDict.insert("chinese-traditional", new QCString("0x404 Chinese (Taiwan)")); // new LCIDs - s_languageDict.insert("indonesian", new QCString("0x412 Indonesian")); + s_languageDict.insert("indonesian", new QCString("0x421 Indonesian")); s_languageDict.insert("croatian", new QCString("0x41A Croatian")); s_languageDict.insert("romanian", new QCString("0x418 Romanian")); s_languageDict.insert("slovene", new QCString("0x424 Slovenian")); diff --git a/src/index.cpp b/src/index.cpp index db58129..12f35f2 100644 --- a/src/index.cpp +++ b/src/index.cpp @@ -1396,7 +1396,8 @@ static void writeSingleFileIndex(OutputList &ol,FileDef *fd) FALSE, // isExample 0, // example name TRUE, // single line - TRUE // link from index + TRUE, // link from index + Config_getBool(MARKDOWN_SUPPORT) ); //ol.docify(")"); } @@ -1768,7 +1769,8 @@ static void writeNamespaceIndex(OutputList &ol) FALSE, // isExample 0, // example name TRUE, // single line - TRUE // link from index + TRUE, // link from index + Config_getBool(MARKDOWN_SUPPORT) ); //ol.docify(")"); } @@ -1902,7 +1904,8 @@ static void writeAnnotatedClassList(OutputList &ol,ClassDef::CompoundType ct) FALSE, // isExample 0, // example name TRUE, // single line - TRUE // link from index + TRUE, // link from index + Config_getBool(MARKDOWN_SUPPORT) ); } ol.endIndexValue(cd->getOutputFileBase(),hasBrief); @@ -3908,14 +3911,14 @@ void writeGraphInfo(OutputList &ol) DotLegendGraph gd; gd.writeGraph(Config_getString(HTML_OUTPUT)); - bool &stripCommentsStateRef = Config_getBool(STRIP_CODE_COMMENTS); + bool stripCommentsStateRef = Config_getBool(STRIP_CODE_COMMENTS); bool oldStripCommentsState = stripCommentsStateRef; - bool &createSubdirs = Config_getBool(CREATE_SUBDIRS); + bool createSubdirs = Config_getBool(CREATE_SUBDIRS); bool oldCreateSubdirs = createSubdirs; // temporarily disable the stripping of comments for our own code example! - stripCommentsStateRef = FALSE; + stripCommentsStateRef = Config_updateBool(STRIP_CODE_COMMENTS,FALSE); // temporarily disable create subdirs for linking to our example - createSubdirs = FALSE; + createSubdirs = Config_updateBool(CREATE_SUBDIRS,FALSE); startFile(ol,"graph_legend",0,theTranslator->trLegendTitle().data()); startTitle(ol,0); @@ -3932,12 +3935,13 @@ void writeGraphInfo(OutputList &ol) //printf("legendDocs=%s\n",legendDocs.data()); } FileDef *fd = createFileDef("","graph_legend.dox"); - ol.generateDoc("graph_legend",1,fd,0,legendDocs,FALSE,FALSE); + ol.generateDoc("graph_legend",1,fd,0,legendDocs,FALSE,FALSE, + 0,FALSE,FALSE,FALSE); delete fd; // restore config settings - stripCommentsStateRef = oldStripCommentsState; - createSubdirs = oldCreateSubdirs; + Config_updateBool(STRIP_CODE_COMMENTS,oldStripCommentsState); + Config_updateBool(CREATE_SUBDIRS,oldCreateSubdirs); endFile(ol); ol.popGeneratorState(); @@ -3988,7 +3992,7 @@ static void writeGroupTreeNode(OutputList &ol, GroupDef *gd, int level, FTVHelp* numSubItems += gd->getNamespaces()->count(); numSubItems += gd->getClasses()->count(); numSubItems += gd->getFiles()->count(); - numSubItems += gd->getDirs().size(); + numSubItems += static_cast<int>(gd->getDirs().size()); numSubItems += gd->getPages()->count(); } @@ -4496,8 +4500,8 @@ static void writeIndex(OutputList &ol) ol.startHeaderSection(); ol.startTitleHead(0); ol.generateDoc(Doxygen::mainPage->docFile(),Doxygen::mainPage->docLine(), - Doxygen::mainPage,0,Doxygen::mainPage->title(), - TRUE,FALSE,0,TRUE,FALSE); + Doxygen::mainPage,0,Doxygen::mainPage->title(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); headerWritten = TRUE; } } @@ -4533,7 +4537,8 @@ static void writeIndex(OutputList &ol) ol.startTextBlock(); ol.generateDoc(defFileName,defLine,Doxygen::mainPage,0, - Doxygen::mainPage->documentation(),TRUE,FALSE); + Doxygen::mainPage->documentation(),TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endTextBlock(); ol.endPageDoc(); @@ -4570,7 +4575,8 @@ static void writeIndex(OutputList &ol) if (!Config_getString(PROJECT_NUMBER).isEmpty()) { ol.startProjectNumber(); - ol.generateDoc(defFileName,defLine,Doxygen::mainPage,0,Config_getString(PROJECT_NUMBER),FALSE,FALSE); + ol.generateDoc(defFileName,defLine,Doxygen::mainPage,0,Config_getString(PROJECT_NUMBER),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endProjectNumber(); } ol.endIndexSection(isTitlePageStart); @@ -4783,7 +4789,8 @@ static void writeIndex(OutputList &ol) ol.startContents(); ol.startTextBlock(); ol.generateDoc(defFileName,defLine,Doxygen::mainPage,0, - Doxygen::mainPage->documentation(),FALSE,FALSE + Doxygen::mainPage->documentation(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT) ); ol.endTextBlock(); endFile(ol); diff --git a/src/latexdocvisitor.cpp b/src/latexdocvisitor.cpp index b899935..19f01b0 100644 --- a/src/latexdocvisitor.cpp +++ b/src/latexdocvisitor.cpp @@ -1,13 +1,13 @@ /****************************************************************************** * - * + * * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -16,7 +16,7 @@ * */ #include "htmlattrib.h" -#include <qfileinfo.h> +#include <qfileinfo.h> #include "latexdocvisitor.h" #include "latexgen.h" #include "docparser.h" @@ -37,7 +37,7 @@ #include "plantuml.h" const int maxLevels=5; -static const char *secLabels[maxLevels] = +static const char *secLabels[maxLevels] = { "doxysection","doxysubsection","doxysubsubsection","doxyparagraph","doxysubparagraph" }; static const char *getSectionName(int level) @@ -176,8 +176,8 @@ QCString LatexDocVisitor::escapeMakeIndexChars(const char *s) LatexDocVisitor::LatexDocVisitor(FTextStream &t,CodeOutputInterface &ci, - const char *langExt,bool insideTabbing) - : DocVisitor(DocVisitor_Latex), m_t(t), m_ci(ci), m_insidePre(FALSE), + const char *langExt,bool insideTabbing) + : DocVisitor(DocVisitor_Latex), m_t(t), m_ci(ci), m_insidePre(FALSE), m_insideItem(FALSE), m_hide(FALSE), m_hideCaption(FALSE), m_insideTabbing(insideTabbing), m_langExt(langExt) { @@ -322,7 +322,7 @@ void LatexDocVisitor::visit(DocStyleChange *s) if (s->enable()) m_t << "\n\\footnotesize "; else m_t << "\n\\normalsize "; break; case DocStyleChange::Preformatted: - if (s->enable()) + if (s->enable()) { m_t << "\n\\begin{DoxyPre}"; m_insidePre=TRUE; @@ -349,7 +349,7 @@ void LatexDocVisitor::visit(DocVerbatim *s) SrcLangExt langExt = getLanguageFromFileName(lang); switch(s->type()) { - case DocVerbatim::Code: + case DocVerbatim::Code: { m_t << "\n\\begin{DoxyCode}{" << usedTableLevels() << "}\n"; LatexCodeGenerator::setDoxyCodeOpen(TRUE); @@ -360,28 +360,28 @@ void LatexDocVisitor::visit(DocVerbatim *s) m_t << "\\end{DoxyCode}\n"; } break; - case DocVerbatim::Verbatim: + case DocVerbatim::Verbatim: m_t << "\\begin{DoxyVerb}"; m_t << s->text(); m_t << "\\end{DoxyVerb}\n"; break; - case DocVerbatim::HtmlOnly: - case DocVerbatim::XmlOnly: - case DocVerbatim::ManOnly: + case DocVerbatim::HtmlOnly: + case DocVerbatim::XmlOnly: + case DocVerbatim::ManOnly: case DocVerbatim::RtfOnly: case DocVerbatim::DocbookOnly: - /* nothing */ + /* nothing */ break; - case DocVerbatim::LatexOnly: - m_t << s->text(); + case DocVerbatim::LatexOnly: + m_t << s->text(); break; - case DocVerbatim::Dot: + case DocVerbatim::Dot: { static int dotindex = 1; QCString fileName(4096); - fileName.sprintf("%s%d%s", - (Config_getString(LATEX_OUTPUT)+"/inline_dotgraph_").data(), + fileName.sprintf("%s%d%s", + (Config_getString(LATEX_OUTPUT)+"/inline_dotgraph_").data(), dotindex++, ".dot" ); @@ -403,13 +403,13 @@ void LatexDocVisitor::visit(DocVerbatim *s) } } break; - case DocVerbatim::Msc: + case DocVerbatim::Msc: { static int mscindex = 1; QCString baseName(4096); - baseName.sprintf("%s%d", - (Config_getString(LATEX_OUTPUT)+"/inline_mscgraph_").data(), + baseName.sprintf("%s%d", + (Config_getString(LATEX_OUTPUT)+"/inline_mscgraph_").data(), mscindex++ ); QFile file(baseName+".msc"); @@ -431,7 +431,7 @@ void LatexDocVisitor::visit(DocVerbatim *s) } } break; - case DocVerbatim::PlantUML: + case DocVerbatim::PlantUML: { QCString latexOutput = Config_getString(LATEX_OUTPUT); QCString baseName = PlantumlManager::instance()->writePlantUMLSource(latexOutput,s->exampleFile(),s->text(),PlantumlManager::PUML_EPS); @@ -446,11 +446,11 @@ void LatexDocVisitor::visit(DocAnchor *anc) { if (m_hide) return; m_t << "\\label{" << stripPath(anc->file()) << "_" << anc->anchor() << "}%" << endl; - if (!anc->file().isEmpty() && Config_getBool(PDF_HYPERLINKS)) + if (!anc->file().isEmpty() && Config_getBool(PDF_HYPERLINKS)) { - m_t << "\\Hypertarget{" << stripPath(anc->file()) << "_" << anc->anchor() + m_t << "\\Hypertarget{" << stripPath(anc->file()) << "_" << anc->anchor() << "}%" << endl; - } + } } void LatexDocVisitor::visit(DocInclude *inc) @@ -460,7 +460,7 @@ void LatexDocVisitor::visit(DocInclude *inc) switch(inc->type()) { case DocInclude::IncWithLines: - { + { m_t << "\n\\begin{DoxyCodeInclude}{" << usedTableLevels() << "}\n"; LatexCodeGenerator::setDoxyCodeOpen(TRUE); QFileInfo cfi( inc->file() ); @@ -482,8 +482,8 @@ void LatexDocVisitor::visit(DocInclude *inc) LatexCodeGenerator::setDoxyCodeOpen(FALSE); m_t << "\\end{DoxyCodeInclude}" << endl; } - break; - case DocInclude::Include: + break; + case DocInclude::Include: m_t << "\n\\begin{DoxyCodeInclude}{" << usedTableLevels() << "}\n"; LatexCodeGenerator::setDoxyCodeOpen(TRUE); Doxygen::parserManager->getCodeParser(inc->extension()) @@ -511,7 +511,7 @@ void LatexDocVisitor::visit(DocInclude *inc) case DocInclude::LatexInclude: m_t << inc->text(); break; - case DocInclude::VerbInclude: + case DocInclude::VerbInclude: m_t << "\n\\begin{DoxyVerbInclude}\n"; m_t << inc->text(); m_t << "\\end{DoxyVerbInclude}\n"; @@ -544,7 +544,7 @@ void LatexDocVisitor::visit(DocInclude *inc) extractBlock(inc->text(),inc->blockId()), langExt, inc->isExample(), - inc->exampleFile(), + inc->exampleFile(), fd, lineBlock(inc->text(),inc->blockId()), -1, // endLine @@ -557,8 +557,8 @@ void LatexDocVisitor::visit(DocInclude *inc) m_t << "\\end{DoxyCodeInclude}" << endl; } break; - case DocInclude::SnippetDoc: - case DocInclude::IncludeDoc: + case DocInclude::SnippetDoc: + case DocInclude::IncludeDoc: err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s" "Please create a bug report\n",__FILE__); break; @@ -569,7 +569,7 @@ void LatexDocVisitor::visit(DocIncOperator *op) { //printf("DocIncOperator: type=%d first=%d, last=%d text='%s'\n", // op->type(),op->isFirst(),op->isLast(),op->text().data()); - if (op->isFirst()) + if (op->isFirst()) { if (!m_hide) m_t << "\n\\begin{DoxyCodeInclude}{" << usedTableLevels() << "}\n"; LatexCodeGenerator::setDoxyCodeOpen(TRUE); @@ -579,10 +579,10 @@ void LatexDocVisitor::visit(DocIncOperator *op) QCString locLangExt = getFileNameExtension(op->includeFileName()); if (locLangExt.isEmpty()) locLangExt = m_langExt; SrcLangExt langExt = getLanguageFromFileName(locLangExt); - if (op->type()!=DocIncOperator::Skip) + if (op->type()!=DocIncOperator::Skip) { popEnabled(); - if (!m_hide) + if (!m_hide) { FileDef *fd = 0; if (!op->includeFileName().isEmpty()) @@ -606,7 +606,7 @@ void LatexDocVisitor::visit(DocIncOperator *op) pushEnabled(); m_hide=TRUE; } - if (op->isLast()) + if (op->isLast()) { popEnabled(); LatexCodeGenerator::setDoxyCodeOpen(FALSE); @@ -621,7 +621,8 @@ void LatexDocVisitor::visit(DocIncOperator *op) void LatexDocVisitor::visit(DocFormula *f) { if (m_hide) return; - const char *p=f->text(); + QCString s = f->text(); + const char *p = s.data(); char c; if (p) { @@ -653,7 +654,7 @@ void LatexDocVisitor::visit(DocSimpleSectSep *) void LatexDocVisitor::visit(DocCite *cite) { if (m_hide) return; - if (!cite->file().isEmpty()) + if (!cite->file().isEmpty()) { //startLink(cite->ref(),cite->file(),cite->anchor()); QCString anchor = cite->anchor(); @@ -705,11 +706,11 @@ void LatexDocVisitor::visitPre(DocAutoListItem *) m_t << "\n\\item "; } -void LatexDocVisitor::visitPost(DocAutoListItem *) +void LatexDocVisitor::visitPost(DocAutoListItem *) { } -void LatexDocVisitor::visitPre(DocPara *) +void LatexDocVisitor::visitPre(DocPara *) { } @@ -799,7 +800,7 @@ void LatexDocVisitor::visitPre(DocSimpleSect *s) case DocSimpleSect::User: m_t << "\\begin{DoxyParagraph}{"; break; - case DocSimpleSect::Rcs: + case DocSimpleSect::Rcs: m_t << "\\begin{DoxyParagraph}{"; break; case DocSimpleSect::Unknown: break; @@ -869,7 +870,7 @@ void LatexDocVisitor::visitPost(DocSimpleSect *s) case DocSimpleSect::User: m_t << "\n\\end{DoxyParagraph}\n"; break; - case DocSimpleSect::Rcs: + case DocSimpleSect::Rcs: m_t << "\n\\end{DoxyParagraph}\n"; break; default: @@ -906,7 +907,7 @@ void LatexDocVisitor::visitPre(DocSimpleListItem *) m_t << "\\item "; } -void LatexDocVisitor::visitPost(DocSimpleListItem *) +void LatexDocVisitor::visitPost(DocSimpleListItem *) { } @@ -922,25 +923,25 @@ void LatexDocVisitor::visitPre(DocSection *s) m_t << "}\\label{" << stripPath(s->file()) << "_" << s->anchor() << "}" << endl; } -void LatexDocVisitor::visitPost(DocSection *) +void LatexDocVisitor::visitPost(DocSection *) { } void LatexDocVisitor::visitPre(DocHtmlList *s) { if (m_hide) return; - if (s->type()==DocHtmlList::Ordered) + if (s->type()==DocHtmlList::Ordered) m_t << "\n\\begin{DoxyEnumerate}"; - else + else m_t << "\n\\begin{DoxyItemize}"; } -void LatexDocVisitor::visitPost(DocHtmlList *s) +void LatexDocVisitor::visitPost(DocHtmlList *s) { if (m_hide) return; - if (s->type()==DocHtmlList::Ordered) + if (s->type()==DocHtmlList::Ordered) m_t << "\n\\end{DoxyEnumerate}"; - else + else m_t << "\n\\end{DoxyItemize}"; } @@ -950,7 +951,7 @@ void LatexDocVisitor::visitPre(DocHtmlListItem *) m_t << "\n\\item "; } -void LatexDocVisitor::visitPost(DocHtmlListItem *) +void LatexDocVisitor::visitPost(DocHtmlListItem *) { } @@ -960,7 +961,7 @@ void LatexDocVisitor::visitPost(DocHtmlListItem *) // m_insidePre=TRUE; //} -//void LatexDocVisitor::visitPost(DocHtmlPre *) +//void LatexDocVisitor::visitPost(DocHtmlPre *) //{ // m_insidePre=FALSE; // m_t << "\\end{alltt}\\normalsize " << endl; @@ -980,7 +981,7 @@ void LatexDocVisitor::visitPre(DocHtmlDescList *dl) } } -void LatexDocVisitor::visitPost(DocHtmlDescList *dl) +void LatexDocVisitor::visitPost(DocHtmlDescList *dl) { if (m_hide) return; QCString val = dl->attribs().find("class"); @@ -1001,7 +1002,7 @@ void LatexDocVisitor::visitPre(DocHtmlDescTitle *) m_insideItem=TRUE; } -void LatexDocVisitor::visitPost(DocHtmlDescTitle *) +void LatexDocVisitor::visitPost(DocHtmlDescTitle *) { if (m_hide) return; m_insideItem=FALSE; @@ -1012,7 +1013,7 @@ void LatexDocVisitor::visitPre(DocHtmlDescData *) { } -void LatexDocVisitor::visitPost(DocHtmlDescData *) +void LatexDocVisitor::visitPost(DocHtmlDescData *) { } @@ -1120,7 +1121,7 @@ void LatexDocVisitor::visitPre(DocHtmlRow *r) setCurrentColumn(0); } -void LatexDocVisitor::visitPost(DocHtmlRow *row) +void LatexDocVisitor::visitPost(DocHtmlRow *row) { if (m_hide) return; @@ -1155,7 +1156,7 @@ void LatexDocVisitor::visitPost(DocHtmlRow *row) } m_t << "\\\\"; - + int col = 1; uint i; for (i=0;i<rowSpans().count();i++) @@ -1289,7 +1290,7 @@ void LatexDocVisitor::visitPre(DocHtmlCell *c) } } -void LatexDocVisitor::visitPost(DocHtmlCell *c) +void LatexDocVisitor::visitPost(DocHtmlCell *c) { if (m_hide) return; if (c->isHeading()) @@ -1317,7 +1318,7 @@ void LatexDocVisitor::visitPre(DocInternal *) //m_t << "}\n"; } -void LatexDocVisitor::visitPost(DocInternal *) +void LatexDocVisitor::visitPost(DocInternal *) { if (m_hide) return; //m_t << "\\end{DoxyInternal}" << endl; @@ -1335,7 +1336,7 @@ void LatexDocVisitor::visitPre(DocHRef *href) m_t << "{\\texttt{ "; } -void LatexDocVisitor::visitPost(DocHRef *) +void LatexDocVisitor::visitPost(DocHRef *) { if (m_hide) return; m_t << "}}"; @@ -1347,7 +1348,7 @@ void LatexDocVisitor::visitPre(DocHtmlHeader *header) m_t << "\\" << getSectionName(header->level()) << "*{"; } -void LatexDocVisitor::visitPost(DocHtmlHeader *) +void LatexDocVisitor::visitPost(DocHtmlHeader *) { if (m_hide) return; m_t << "}"; @@ -1372,7 +1373,7 @@ void LatexDocVisitor::visitPre(DocImage *img) } } -void LatexDocVisitor::visitPost(DocImage *img) +void LatexDocVisitor::visitPost(DocImage *img) { if (img->type()==DocImage::Latex) { @@ -1391,7 +1392,7 @@ void LatexDocVisitor::visitPre(DocDotFile *df) startDotFile(df->file(),df->width(),df->height(),df->hasCaption()); } -void LatexDocVisitor::visitPost(DocDotFile *df) +void LatexDocVisitor::visitPost(DocDotFile *df) { if (m_hide) return; endDotFile(df->hasCaption()); @@ -1402,7 +1403,7 @@ void LatexDocVisitor::visitPre(DocMscFile *df) startMscFile(df->file(),df->width(),df->height(),df->hasCaption()); } -void LatexDocVisitor::visitPost(DocMscFile *df) +void LatexDocVisitor::visitPost(DocMscFile *df) { if (m_hide) return; endMscFile(df->hasCaption()); @@ -1425,7 +1426,7 @@ void LatexDocVisitor::visitPre(DocLink *lnk) startLink(lnk->ref(),lnk->file(),lnk->anchor()); } -void LatexDocVisitor::visitPost(DocLink *lnk) +void LatexDocVisitor::visitPost(DocLink *lnk) { if (m_hide) return; endLink(lnk->ref(),lnk->file(),lnk->anchor()); @@ -1447,7 +1448,7 @@ void LatexDocVisitor::visitPre(DocRef *ref) if (!ref->hasLinkText()) filter(ref->targetTitle()); } -void LatexDocVisitor::visitPost(DocRef *ref) +void LatexDocVisitor::visitPost(DocRef *ref) { if (m_hide) return; if (ref->isSubPage()) @@ -1471,7 +1472,7 @@ void LatexDocVisitor::visitPre(DocSecRefItem *ref) } } -void LatexDocVisitor::visitPost(DocSecRefItem *ref) +void LatexDocVisitor::visitPost(DocSecRefItem *ref) { if (m_hide) return; static bool pdfHyperlinks = Config_getBool(PDF_HYPERLINKS); @@ -1490,7 +1491,7 @@ void LatexDocVisitor::visitPre(DocSecRefList *) m_t << "\\begin{DoxyCompactList}" << endl; } -void LatexDocVisitor::visitPost(DocSecRefList *) +void LatexDocVisitor::visitPost(DocSecRefList *) { if (m_hide) return; m_t << "\\end{DoxyCompactList}" << endl; @@ -1517,11 +1518,11 @@ void LatexDocVisitor::visitPre(DocParamSect *s) m_t << "\n\\begin{DoxyRetVals}{"; filter(theTranslator->trReturnValues()); break; - case DocParamSect::Exception: + case DocParamSect::Exception: m_t << "\n\\begin{DoxyExceptions}{"; filter(theTranslator->trExceptions()); break; - case DocParamSect::TemplateParam: + case DocParamSect::TemplateParam: m_t << "\n\\begin{DoxyTemplParams}{"; filter(theTranslator->trTemplateParameters()); break; @@ -1543,10 +1544,10 @@ void LatexDocVisitor::visitPost(DocParamSect *s) case DocParamSect::RetVal: m_t << "\\end{DoxyRetVals}\n"; break; - case DocParamSect::Exception: + case DocParamSect::Exception: m_t << "\\end{DoxyExceptions}\n"; break; - case DocParamSect::TemplateParam: + case DocParamSect::TemplateParam: m_t << "\\end{DoxyTemplParams}\n"; break; default: @@ -1601,11 +1602,11 @@ void LatexDocVisitor::visitPre(DocParamList *pl) { if (type->kind()==DocNode::Kind_Word) { - visit((DocWord*)type); + visit((DocWord*)type); } else if (type->kind()==DocNode::Kind_LinkedWord) { - visit((DocLinkedWord*)type); + visit((DocLinkedWord*)type); } else if (type->kind()==DocNode::Kind_Sep) { @@ -1626,11 +1627,11 @@ void LatexDocVisitor::visitPre(DocParamList *pl) m_insideItem=TRUE; if (param->kind()==DocNode::Kind_Word) { - visit((DocWord*)param); + visit((DocWord*)param); } else if (param->kind()==DocNode::Kind_LinkedWord) { - visit((DocLinkedWord*)param); + visit((DocLinkedWord*)param); } m_insideItem=FALSE; } @@ -1705,7 +1706,7 @@ void LatexDocVisitor::visitPre(DocInternalRef *ref) startLink(0,ref->file(),ref->anchor()); } -void LatexDocVisitor::visitPost(DocInternalRef *ref) +void LatexDocVisitor::visitPost(DocInternalRef *ref) { if (m_hide) return; endLink(0,ref->file(),ref->anchor()); @@ -1752,7 +1753,7 @@ void LatexDocVisitor::visitPost(DocParBlock *) } void LatexDocVisitor::filter(const char *str) -{ +{ filterLatexString(m_t,str,m_insideTabbing,m_insidePre,m_insideItem); } @@ -1833,7 +1834,7 @@ void LatexDocVisitor::startDotFile(const QCString &fileName, if ((i=baseName.findRev('/'))!=-1) { baseName=baseName.right(baseName.length()-i-1); - } + } if ((i=baseName.find('.'))!=-1) { baseName=baseName.left(i); @@ -1862,7 +1863,7 @@ void LatexDocVisitor::startMscFile(const QCString &fileName, if ((i=baseName.findRev('/'))!=-1) { baseName=baseName.right(baseName.length()-i-1); - } + } if ((i=baseName.find('.'))!=-1) { baseName=baseName.left(i); @@ -1870,7 +1871,7 @@ void LatexDocVisitor::startMscFile(const QCString &fileName, baseName.prepend("msc_"); QCString outDir = Config_getString(LATEX_OUTPUT); - writeMscGraphFromFile(fileName,outDir,baseName,MSC_EPS); + writeMscGraphFromFile(fileName,outDir,baseName,MSC_EPS); visitPreStart(m_t,hasCaption, baseName, width, height); } @@ -1888,7 +1889,7 @@ void LatexDocVisitor::writeMscFile(const QCString &baseName, DocVerbatim *s) if ((i=shortName.findRev('/'))!=-1) { shortName=shortName.right(shortName.length()-i-1); - } + } QCString outDir = Config_getString(LATEX_OUTPUT); writeMscGraphFromFile(baseName+".msc",outDir,shortName,MSC_EPS); visitPreStart(m_t, s->hasCaption(), shortName, s->width(),s->height()); diff --git a/src/latexgen.cpp b/src/latexgen.cpp index 52a8acf..cb42863 100644 --- a/src/latexgen.cpp +++ b/src/latexgen.cpp @@ -511,10 +511,10 @@ static void writeDefaultHeaderPart1(FTextStream &t) "\\usepackage{fixltx2e}\n" // for \textsubscript "\\usepackage{calc}\n" "\\usepackage{doxygen}\n"; - QStrList extraLatexStyle = Config_getList(LATEX_EXTRA_STYLESHEET); - for (uint i=0; i<extraLatexStyle.count(); ++i) + const StringVector &extraLatexStyles = Config_getList(LATEX_EXTRA_STYLESHEET); + for (const auto &extraStyle : extraLatexStyles) { - QCString fileName(extraLatexStyle.at(i)); + QCString fileName = extraStyle.c_str(); if (!fileName.isEmpty()) { QFileInfo fi(fileName); @@ -560,11 +560,13 @@ static void writeDefaultHeaderPart1(FTextStream &t) { t << "\\usepackage[" << fontenc << "]{fontenc}\n"; } - t << "\\usepackage[scaled=.90]{helvet}\n" - "\\usepackage{courier}\n" - "\\usepackage{amssymb}\n" + QCString font = theTranslator->latexFont(); + if (!font.isEmpty()) + { + t << font; + } + t << "\\usepackage{amssymb}\n" "\\usepackage{sectsty}\n" - "\\renewcommand{\\familydefault}{\\sfdefault}\n" "\\allsectionsfont{%\n" " \\fontseries{bc}\\selectfont%\n" " \\color{darkgray}%\n" @@ -914,8 +916,8 @@ void LatexGenerator::startProjectNumber() void LatexGenerator::startIndexSection(IndexSections is) { - bool &compactLatex = Config_getBool(COMPACT_LATEX); - QCString &latexHeader = Config_getString(LATEX_HEADER); + bool compactLatex = Config_getBool(COMPACT_LATEX); + QCString latexHeader = Config_getString(LATEX_HEADER); switch (is) { case isTitlePageStart: diff --git a/src/layout.cpp b/src/layout.cpp index f84fec0..fd31803 100644 --- a/src/layout.cpp +++ b/src/layout.cpp @@ -1,13 +1,13 @@ /****************************************************************************** * - * + * * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -63,7 +63,7 @@ static bool elemIsVisible(const QXmlAttributes &attrib,bool defVal=TRUE) const ConfigValues::Info *opt = ConfigValues::instance().get(id); if (opt && opt->type==ConfigValues::Info::Bool) { - return ConfigValues::instance().*((ConfigValues::InfoBool*)opt)->item; + return ConfigValues::instance().*(opt->value.b); } else if (!opt) { @@ -84,7 +84,7 @@ LayoutNavEntry *LayoutNavEntry::find(LayoutNavEntry::Kind kind, LayoutNavEntry *entry; for (li.toFirst();(entry=li.current());++li) { - // depth first search, needed to find the entry furthest from the + // depth first search, needed to find the entry furthest from the // root in case an entry is in the tree twice result = entry->find(kind,file); if (result) return result; @@ -99,7 +99,7 @@ LayoutNavEntry *LayoutNavEntry::find(LayoutNavEntry::Kind kind, QCString LayoutNavEntry::url() const { QCString url = baseFile().stripWhiteSpace(); - if ((kind()!=LayoutNavEntry::User && kind()!=LayoutNavEntry::UserGroup) || + if ((kind()!=LayoutNavEntry::User && kind()!=LayoutNavEntry::UserGroup) || (kind()==LayoutNavEntry::UserGroup && url.left(9)=="usergroup")) { url+=Doxygen::htmlFileExtension; @@ -111,7 +111,7 @@ QCString LayoutNavEntry::url() const bool found=FALSE; if (resolveLink(0,url.mid(5).stripWhiteSpace(),TRUE,&d,anchor)) { - if (d && d->isLinkable()) + if (d && d->isLinkable()) { url=d->getOutputFileBase()+Doxygen::htmlFileExtension; if (!anchor.isEmpty()) @@ -137,14 +137,14 @@ class LayoutParser : public QXmlDefaultHandler private: class StartElementHandler { - typedef void (LayoutParser::*Handler)(const QXmlAttributes &attrib); + typedef void (LayoutParser::*Handler)(const QXmlAttributes &attrib); public: - StartElementHandler(LayoutParser *parent, Handler h) + StartElementHandler(LayoutParser *parent, Handler h) : m_parent(parent), m_handler(h) {} virtual ~StartElementHandler() {} - virtual void operator()(const QXmlAttributes &attrib) - { - (m_parent->*m_handler)(attrib); + virtual void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(attrib); } protected: StartElementHandler() : m_parent(0), m_handler(0) {} @@ -156,13 +156,13 @@ class LayoutParser : public QXmlDefaultHandler class StartElementHandlerKind : public StartElementHandler { typedef void (LayoutParser::*Handler)(LayoutDocEntry::Kind kind, - const QXmlAttributes &attrib); + const QXmlAttributes &attrib); public: - StartElementHandlerKind(LayoutParser *parent, LayoutDocEntry::Kind k,Handler h) + StartElementHandlerKind(LayoutParser *parent, LayoutDocEntry::Kind k,Handler h) : m_parent(parent), m_kind(k), m_handler(h) {} - void operator()(const QXmlAttributes &attrib) - { - (m_parent->*m_handler)(m_kind,attrib); + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(m_kind,attrib); } private: LayoutParser *m_parent; @@ -174,14 +174,14 @@ class LayoutParser : public QXmlDefaultHandler { typedef void (LayoutParser::*Handler)(LayoutDocEntry::Kind kind, const QXmlAttributes &attrib, - const QCString &title); + const QCString &title); public: StartElementHandlerSection(LayoutParser *parent, LayoutDocEntry::Kind k,Handler h, - const QCString &title) + const QCString &title) : m_parent(parent), m_kind(k), m_handler(h), m_title(title) {} - void operator()(const QXmlAttributes &attrib) - { - (m_parent->*m_handler)(m_kind,attrib,m_title); + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(m_kind,attrib,m_title); } private: LayoutParser *m_parent; @@ -195,19 +195,19 @@ class LayoutParser : public QXmlDefaultHandler typedef void (LayoutParser::*Handler)(const QXmlAttributes &attrib, MemberListType type, const QCString &title, - const QCString &subtitle); + const QCString &subtitle); public: - StartElementHandlerMember(LayoutParser *parent, + StartElementHandlerMember(LayoutParser *parent, Handler h, MemberListType type, const QCString &tl, const QCString &ss = QCString() - ) + ) : m_parent(parent), m_handler(h), m_type(type), m_title(tl), m_subscript(ss) {} - void operator()(const QXmlAttributes &attrib) - { - (m_parent->*m_handler)(attrib,m_type,m_title,m_subscript); + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(attrib,m_type,m_title,m_subscript); } private: LayoutParser *m_parent; @@ -221,17 +221,17 @@ class LayoutParser : public QXmlDefaultHandler { typedef void (LayoutParser::*Handler)(LayoutNavEntry::Kind kind, const QXmlAttributes &attrib, - const QCString &title); + const QCString &title); public: StartElementHandlerNavEntry(LayoutParser *parent, - LayoutNavEntry::Kind kind, + LayoutNavEntry::Kind kind, Handler h, const QCString &tl - ) + ) : m_parent(parent), m_kind(kind), m_handler(h), m_title(tl) {} - void operator()(const QXmlAttributes &attrib) - { - (m_parent->*m_handler)(m_kind,attrib,m_title); + void operator()(const QXmlAttributes &attrib) + { + (m_parent->*m_handler)(m_kind,attrib,m_title); } private: LayoutParser *m_parent; @@ -242,7 +242,7 @@ class LayoutParser : public QXmlDefaultHandler class EndElementHandler { - typedef void (LayoutParser::*Handler)(); + typedef void (LayoutParser::*Handler)(); public: EndElementHandler(LayoutParser *parent, Handler h) : m_parent(parent), m_handler(h) {} void operator()() { (m_parent->*m_handler)(); } @@ -266,51 +266,51 @@ class LayoutParser : public QXmlDefaultHandler m_rootNav = 0; //bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN); - //bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL); + //bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL); //bool javaOpt = Config_getBool(OPTIMIZE_OUTPUT_JAVA); bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE); // start & end handlers - m_sHandler.insert("doxygenlayout", + m_sHandler.insert("doxygenlayout", new StartElementHandler(this,&LayoutParser::startLayout)); - m_eHandler.insert("doxygenlayout", + m_eHandler.insert("doxygenlayout", new EndElementHandler(this,&LayoutParser::endLayout)); // class layout handlers - m_sHandler.insert("navindex", + m_sHandler.insert("navindex", new StartElementHandler(this,&LayoutParser::startNavIndex)); - m_sHandler.insert("navindex/tab", + m_sHandler.insert("navindex/tab", new StartElementHandler(this,&LayoutParser::startNavEntry)); - m_eHandler.insert("navindex/tab", + m_eHandler.insert("navindex/tab", new EndElementHandler(this,&LayoutParser::endNavEntry)); - m_eHandler.insert("navindex", + m_eHandler.insert("navindex", new EndElementHandler(this,&LayoutParser::endNavIndex)); // class layout handlers - m_sHandler.insert("class", + m_sHandler.insert("class", new StartElementHandler(this,&LayoutParser::startClass)); - m_sHandler.insert("class/briefdescription", + m_sHandler.insert("class/briefdescription", new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/detaileddescription", + m_sHandler.insert("class/detaileddescription", new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, theTranslator->trDetailedDescription())); - m_sHandler.insert("class/authorsection", + m_sHandler.insert("class/authorsection", new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/includes", + m_sHandler.insert("class/includes", new StartElementHandlerKind(this,LayoutDocEntry::ClassIncludes,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/inheritancegraph", + m_sHandler.insert("class/inheritancegraph", new StartElementHandlerKind(this,LayoutDocEntry::ClassInheritanceGraph,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/collaborationgraph", + m_sHandler.insert("class/collaborationgraph", new StartElementHandlerKind(this,LayoutDocEntry::ClassCollaborationGraph,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/allmemberslink", + m_sHandler.insert("class/allmemberslink", new StartElementHandlerKind(this,LayoutDocEntry::ClassAllMembersLink,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/usedfiles", + m_sHandler.insert("class/usedfiles", new StartElementHandlerKind(this,LayoutDocEntry::ClassUsedFiles,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/memberdecl", + m_sHandler.insert("class/memberdecl", new StartElementHandler(this,&LayoutParser::startMemberDecl)); - m_sHandler.insert("class/memberdecl/membergroups", + m_sHandler.insert("class/memberdecl/membergroups", new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("class/memberdecl/nestedclasses", + m_sHandler.insert("class/memberdecl/nestedclasses", new StartElementHandlerSection(this,LayoutDocEntry::ClassNestedClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_2_OPTIONS( theTranslator->trCompounds(), @@ -323,118 +323,118 @@ class LayoutParser : public QXmlDefaultHandler m_sHandler.insert("class/memberdecl/interfaces", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_interfaces,theTranslator->trInterfaces())); - m_sHandler.insert("class/memberdecl/publictypes", + m_sHandler.insert("class/memberdecl/publictypes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_pubTypes,theTranslator->trPublicTypes())); - m_sHandler.insert("class/memberdecl/publicslots", + m_sHandler.insert("class/memberdecl/publicslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pubSlots,theTranslator->trPublicSlots())); - m_sHandler.insert("class/memberdecl/signals", + MemberListType_pubSlots,theTranslator->trPublicSlots())); + m_sHandler.insert("class/memberdecl/signals", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_signals,theTranslator->trSignals())); - m_sHandler.insert("class/memberdecl/publicmethods", + MemberListType_signals,theTranslator->trSignals())); + m_sHandler.insert("class/memberdecl/publicmethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_pubMethods, COMPILE_FOR_2_OPTIONS( theTranslator->trPublicMembers(), SrcLangExt_ObjC,theTranslator->trInstanceMethods(), SrcLangExt_Slice,theTranslator->trOperations() - ))); - m_sHandler.insert("class/memberdecl/publicstaticmethods", + ))); + m_sHandler.insert("class/memberdecl/publicstaticmethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_pubStaticMethods, COMPILE_FOR_1_OPTION( theTranslator->trStaticPublicMembers(), SrcLangExt_ObjC,theTranslator->trClassMethods() - ))); - m_sHandler.insert("class/memberdecl/publicattributes", + ))); + m_sHandler.insert("class/memberdecl/publicattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_pubAttribs, COMPILE_FOR_1_OPTION( theTranslator->trPublicAttribs(), SrcLangExt_Slice,theTranslator->trDataMembers() - ))); - m_sHandler.insert("class/memberdecl/publicstaticattributes", + ))); + m_sHandler.insert("class/memberdecl/publicstaticattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pubStaticAttribs,theTranslator->trStaticPublicAttribs())); - m_sHandler.insert("class/memberdecl/protectedtypes", + MemberListType_pubStaticAttribs,theTranslator->trStaticPublicAttribs())); + m_sHandler.insert("class/memberdecl/protectedtypes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_proTypes,theTranslator->trProtectedTypes())); - m_sHandler.insert("class/memberdecl/protectedslots", + MemberListType_proTypes,theTranslator->trProtectedTypes())); + m_sHandler.insert("class/memberdecl/protectedslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_proSlots,theTranslator->trProtectedSlots())); - m_sHandler.insert("class/memberdecl/protectedmethods", + MemberListType_proSlots,theTranslator->trProtectedSlots())); + m_sHandler.insert("class/memberdecl/protectedmethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_proMethods,theTranslator->trProtectedMembers())); - m_sHandler.insert("class/memberdecl/protectedstaticmethods", + MemberListType_proMethods,theTranslator->trProtectedMembers())); + m_sHandler.insert("class/memberdecl/protectedstaticmethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_proStaticMethods,theTranslator->trStaticProtectedMembers())); - m_sHandler.insert("class/memberdecl/protectedattributes", + m_sHandler.insert("class/memberdecl/protectedattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_proAttribs,theTranslator->trProtectedAttribs())); - m_sHandler.insert("class/memberdecl/protectedstaticattributes", + MemberListType_proAttribs,theTranslator->trProtectedAttribs())); + m_sHandler.insert("class/memberdecl/protectedstaticattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_proStaticAttribs,theTranslator->trStaticProtectedAttribs())); - m_sHandler.insert("class/memberdecl/packagetypes", + MemberListType_proStaticAttribs,theTranslator->trStaticProtectedAttribs())); + m_sHandler.insert("class/memberdecl/packagetypes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pacTypes,theTranslator->trPackageTypes())); - m_sHandler.insert("class/memberdecl/packagemethods", + MemberListType_pacTypes,theTranslator->trPackageTypes())); + m_sHandler.insert("class/memberdecl/packagemethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pacMethods,theTranslator->trPackageMembers())); - m_sHandler.insert("class/memberdecl/packagestaticmethods", + MemberListType_pacMethods,theTranslator->trPackageMembers())); + m_sHandler.insert("class/memberdecl/packagestaticmethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pacStaticMethods,theTranslator->trStaticPackageMembers())); - m_sHandler.insert("class/memberdecl/packageattributes", + MemberListType_pacStaticMethods,theTranslator->trStaticPackageMembers())); + m_sHandler.insert("class/memberdecl/packageattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pacAttribs,theTranslator->trPackageAttribs())); - m_sHandler.insert("class/memberdecl/packagestaticattributes", + MemberListType_pacAttribs,theTranslator->trPackageAttribs())); + m_sHandler.insert("class/memberdecl/packagestaticattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_pacStaticAttribs,theTranslator->trStaticPackageAttribs())); - m_sHandler.insert("class/memberdecl/properties", + MemberListType_pacStaticAttribs,theTranslator->trStaticPackageAttribs())); + m_sHandler.insert("class/memberdecl/properties", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_properties,theTranslator->trProperties())); - m_sHandler.insert("class/memberdecl/events", + MemberListType_properties,theTranslator->trProperties())); + m_sHandler.insert("class/memberdecl/events", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_events,theTranslator->trEvents())); - m_sHandler.insert("class/memberdecl/privatetypes", + MemberListType_events,theTranslator->trEvents())); + m_sHandler.insert("class/memberdecl/privatetypes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_priTypes,theTranslator->trPrivateTypes())); - m_sHandler.insert("class/memberdecl/privateslots", + MemberListType_priTypes,theTranslator->trPrivateTypes())); + m_sHandler.insert("class/memberdecl/privateslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_priSlots,theTranslator->trPrivateSlots())); - m_sHandler.insert("class/memberdecl/privatemethods", + MemberListType_priSlots,theTranslator->trPrivateSlots())); + m_sHandler.insert("class/memberdecl/privatemethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_priMethods,theTranslator->trPrivateMembers())); - m_sHandler.insert("class/memberdecl/privatestaticmethods", + MemberListType_priMethods,theTranslator->trPrivateMembers())); + m_sHandler.insert("class/memberdecl/privatestaticmethods", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_priStaticMethods,theTranslator->trStaticPrivateMembers())); - m_sHandler.insert("class/memberdecl/privateattributes", + MemberListType_priStaticMethods,theTranslator->trStaticPrivateMembers())); + m_sHandler.insert("class/memberdecl/privateattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_priAttribs,theTranslator->trPrivateAttribs())); - m_sHandler.insert("class/memberdecl/privatestaticattributes", + MemberListType_priAttribs,theTranslator->trPrivateAttribs())); + m_sHandler.insert("class/memberdecl/privatestaticattributes", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, - MemberListType_priStaticAttribs,theTranslator->trStaticPrivateAttribs())); - m_sHandler.insert("class/memberdecl/friends", + MemberListType_priStaticAttribs,theTranslator->trStaticPrivateAttribs())); + m_sHandler.insert("class/memberdecl/friends", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_friends,theTranslator->trFriends())); - m_sHandler.insert("class/memberdecl/related", + m_sHandler.insert("class/memberdecl/related", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_related,theTranslator->trRelatedFunctions(), - theTranslator->trRelatedSubscript())); - m_eHandler.insert("class/memberdecl", + theTranslator->trRelatedSubscript())); + m_eHandler.insert("class/memberdecl", new EndElementHandler(this,&LayoutParser::endMemberDecl)); - m_sHandler.insert("class/memberdef", + m_sHandler.insert("class/memberdef", new StartElementHandler(this,&LayoutParser::startMemberDef)); - m_sHandler.insert("class/memberdef/inlineclasses", + m_sHandler.insert("class/memberdef/inlineclasses", new StartElementHandlerSection(this,LayoutDocEntry::ClassInlineClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_1_OPTION( theTranslator->trClassDocumentation(), SrcLangExt_Fortran,theTranslator->trTypeDocumentation() ))); - m_sHandler.insert("class/memberdef/typedefs", + m_sHandler.insert("class/memberdef/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_typedefMembers,theTranslator->trMemberTypedefDocumentation())); - m_sHandler.insert("class/memberdef/enums", + m_sHandler.insert("class/memberdef/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_enumMembers,theTranslator->trMemberEnumerationDocumentation())); m_sHandler.insert("class/memberdef/services", @@ -443,10 +443,10 @@ class LayoutParser : public QXmlDefaultHandler m_sHandler.insert("class/memberdef/interfaces", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_interfaceMembers,theTranslator->trInterfaces())); - m_sHandler.insert("class/memberdef/constructors", + m_sHandler.insert("class/memberdef/constructors", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_constructors,theTranslator->trConstructorDocumentation())); - m_sHandler.insert("class/memberdef/functions", + m_sHandler.insert("class/memberdef/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_functionMembers, COMPILE_FOR_3_OPTIONS( @@ -455,41 +455,41 @@ class LayoutParser : public QXmlDefaultHandler SrcLangExt_Fortran,theTranslator->trMemberFunctionDocumentationFortran(), SrcLangExt_Slice,theTranslator->trOperationDocumentation() ))); - m_sHandler.insert("class/memberdef/related", + m_sHandler.insert("class/memberdef/related", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_relatedMembers,theTranslator->trRelatedFunctionDocumentation())); - m_sHandler.insert("class/memberdef/variables", + m_sHandler.insert("class/memberdef/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_variableMembers, COMPILE_FOR_1_OPTION( theTranslator->trMemberDataDocumentation(), SrcLangExt_Slice,theTranslator->trDataMemberDocumentation() - ))); - m_sHandler.insert("class/memberdef/properties", + ))); + m_sHandler.insert("class/memberdef/properties", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_propertyMembers,theTranslator->trPropertyDocumentation())); - m_sHandler.insert("class/memberdef/events", + m_sHandler.insert("class/memberdef/events", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_eventMembers,theTranslator->trEventDocumentation())); - m_eHandler.insert("class/memberdef", + m_eHandler.insert("class/memberdef", new EndElementHandler(this,&LayoutParser::endMemberDef)); - m_eHandler.insert("class", + m_eHandler.insert("class", new EndElementHandler(this,&LayoutParser::endClass)); // namespace layout handlers - m_sHandler.insert("namespace", + m_sHandler.insert("namespace", new StartElementHandler(this,&LayoutParser::startNamespace)); - m_sHandler.insert("namespace/briefdescription", + m_sHandler.insert("namespace/briefdescription", new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("namespace/detaileddescription", + m_sHandler.insert("namespace/detaileddescription", new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, theTranslator->trDetailedDescription())); - m_sHandler.insert("namespace/authorsection", + m_sHandler.insert("namespace/authorsection", new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("namespace/memberdecl", + m_sHandler.insert("namespace/memberdecl", new StartElementHandler(this,&LayoutParser::startMemberDecl)); - m_sHandler.insert("namespace/memberdecl/nestednamespaces", + m_sHandler.insert("namespace/memberdecl/nestednamespaces", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceNestedNamespaces,&LayoutParser::startSectionEntry, COMPILE_FOR_5_OPTIONS( theTranslator->trNamespaces(), @@ -503,37 +503,37 @@ class LayoutParser : public QXmlDefaultHandler m_sHandler.insert("namespace/memberdecl/constantgroups", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceNestedConstantGroups,&LayoutParser::startSectionEntry, theTranslator->trConstantGroups())); - m_sHandler.insert("namespace/memberdecl/interfaces", + m_sHandler.insert("namespace/memberdecl/interfaces", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceInterfaces,&LayoutParser::startSectionEntry, theTranslator->trSliceInterfaces())); - m_sHandler.insert("namespace/memberdecl/classes", + m_sHandler.insert("namespace/memberdecl/classes", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_2_OPTIONS( theTranslator->trCompounds(), SrcLangExt_VHDL,theTranslator->trVhdlType(VhdlDocGen::ENTITY,FALSE), SrcLangExt_Fortran,theTranslator->trDataTypes() ))); - m_sHandler.insert("namespace/memberdecl/structs", + m_sHandler.insert("namespace/memberdecl/structs", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceStructs,&LayoutParser::startSectionEntry, theTranslator->trStructs())); - m_sHandler.insert("namespace/memberdecl/exceptions", + m_sHandler.insert("namespace/memberdecl/exceptions", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceExceptions,&LayoutParser::startSectionEntry, theTranslator->trExceptions())); - m_sHandler.insert("namespace/memberdecl/membergroups", + m_sHandler.insert("namespace/memberdecl/membergroups", new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("namespace/memberdecl/typedefs", + m_sHandler.insert("namespace/memberdecl/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decTypedefMembers,theTranslator->trTypedefs())); - m_sHandler.insert("namespace/memberdecl/sequences", + m_sHandler.insert("namespace/memberdecl/sequences", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decSequenceMembers,theTranslator->trSequences())); - m_sHandler.insert("namespace/memberdecl/dictionaries", + m_sHandler.insert("namespace/memberdecl/dictionaries", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decDictionaryMembers,theTranslator->trDictionaries())); - m_sHandler.insert("namespace/memberdecl/enums", + m_sHandler.insert("namespace/memberdecl/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decEnumMembers,theTranslator->trEnumerations())); - m_sHandler.insert("namespace/memberdecl/functions", + m_sHandler.insert("namespace/memberdecl/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decFuncMembers, COMPILE_FOR_2_OPTIONS( @@ -541,89 +541,89 @@ class LayoutParser : public QXmlDefaultHandler SrcLangExt_Fortran,theTranslator->trSubprograms(), SrcLangExt_VHDL,theTranslator->trFunctionAndProc() ))); - m_sHandler.insert("namespace/memberdecl/variables", + m_sHandler.insert("namespace/memberdecl/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decVarMembers, sliceOpt ? theTranslator->trConstants() : theTranslator->trVariables())); - m_eHandler.insert("namespace/memberdecl", + m_eHandler.insert("namespace/memberdecl", new EndElementHandler(this,&LayoutParser::endMemberDecl)); - m_sHandler.insert("namespace/memberdef", + m_sHandler.insert("namespace/memberdef", new StartElementHandler(this,&LayoutParser::startMemberDef)); - m_sHandler.insert("namespace/memberdef/inlineclasses", + m_sHandler.insert("namespace/memberdef/inlineclasses", new StartElementHandlerSection(this,LayoutDocEntry::NamespaceInlineClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_1_OPTION( theTranslator->trClassDocumentation(), SrcLangExt_Fortran,theTranslator->trTypeDocumentation() ))); - m_sHandler.insert("namespace/memberdef/typedefs", + m_sHandler.insert("namespace/memberdef/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docTypedefMembers,theTranslator->trTypedefDocumentation())); - m_sHandler.insert("namespace/memberdef/sequences", + m_sHandler.insert("namespace/memberdef/sequences", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docSequenceMembers,theTranslator->trSequenceDocumentation())); - m_sHandler.insert("namespace/memberdef/dictionaries", + m_sHandler.insert("namespace/memberdef/dictionaries", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docDictionaryMembers, theTranslator->trDictionaryDocumentation())); - m_sHandler.insert("namespace/memberdef/enums", + m_sHandler.insert("namespace/memberdef/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docEnumMembers,theTranslator->trEnumerationTypeDocumentation())); - m_sHandler.insert("namespace/memberdef/functions", + m_sHandler.insert("namespace/memberdef/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docFuncMembers, COMPILE_FOR_1_OPTION( theTranslator->trFunctionDocumentation(), SrcLangExt_Fortran,theTranslator->trSubprogramDocumentation() ))); - m_sHandler.insert("namespace/memberdef/variables", + m_sHandler.insert("namespace/memberdef/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docVarMembers, sliceOpt ? theTranslator->trConstantDocumentation() : theTranslator->trVariableDocumentation())); - m_eHandler.insert("namespace/memberdef", + m_eHandler.insert("namespace/memberdef", new EndElementHandler(this,&LayoutParser::endMemberDef)); - m_eHandler.insert("namespace", + m_eHandler.insert("namespace", new EndElementHandler(this,&LayoutParser::endNamespace)); // file layout handlers - m_sHandler.insert("file", + m_sHandler.insert("file", new StartElementHandler(this,&LayoutParser::startFile)); - m_sHandler.insert("file/briefdescription", + m_sHandler.insert("file/briefdescription", new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/detaileddescription", + m_sHandler.insert("file/detaileddescription", new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, theTranslator->trDetailedDescription())); - m_sHandler.insert("file/authorsection", + m_sHandler.insert("file/authorsection", new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/includes", + m_sHandler.insert("file/includes", new StartElementHandlerKind(this,LayoutDocEntry::FileIncludes,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/includegraph", + m_sHandler.insert("file/includegraph", new StartElementHandlerKind(this,LayoutDocEntry::FileIncludeGraph,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/includedbygraph", + m_sHandler.insert("file/includedbygraph", new StartElementHandlerKind(this,LayoutDocEntry::FileIncludedByGraph,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/sourcelink", + m_sHandler.insert("file/sourcelink", new StartElementHandlerKind(this,LayoutDocEntry::FileSourceLink,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/memberdecl/membergroups", + m_sHandler.insert("file/memberdecl/membergroups", new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("file/memberdecl", + m_sHandler.insert("file/memberdecl", new StartElementHandler(this,&LayoutParser::startMemberDecl)); - m_sHandler.insert("file/memberdecl/interfaces", + m_sHandler.insert("file/memberdecl/interfaces", new StartElementHandlerSection(this,LayoutDocEntry::FileInterfaces,&LayoutParser::startSectionEntry, theTranslator->trSliceInterfaces())); - m_sHandler.insert("file/memberdecl/classes", + m_sHandler.insert("file/memberdecl/classes", new StartElementHandlerSection(this,LayoutDocEntry::FileClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_2_OPTIONS( theTranslator->trCompounds(), SrcLangExt_VHDL,theTranslator->trVhdlType(VhdlDocGen::ENTITY,FALSE), SrcLangExt_Fortran,theTranslator->trDataTypes() ))); - m_sHandler.insert("file/memberdecl/structs", + m_sHandler.insert("file/memberdecl/structs", new StartElementHandlerSection(this,LayoutDocEntry::FileStructs,&LayoutParser::startSectionEntry, theTranslator->trStructs())); - m_sHandler.insert("file/memberdecl/exceptions", + m_sHandler.insert("file/memberdecl/exceptions", new StartElementHandlerSection(this,LayoutDocEntry::FileExceptions,&LayoutParser::startSectionEntry, theTranslator->trExceptions())); - m_sHandler.insert("file/memberdecl/namespaces", + m_sHandler.insert("file/memberdecl/namespaces", new StartElementHandlerSection(this,LayoutDocEntry::FileNamespaces,&LayoutParser::startSectionEntry, COMPILE_FOR_4_OPTIONS( theTranslator->trNamespaces(), @@ -635,22 +635,22 @@ class LayoutParser : public QXmlDefaultHandler m_sHandler.insert("file/memberdecl/constantgroups", new StartElementHandlerSection(this,LayoutDocEntry::FileConstantGroups,&LayoutParser::startSectionEntry, theTranslator->trConstantGroups())); - m_sHandler.insert("file/memberdecl/defines", + m_sHandler.insert("file/memberdecl/defines", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decDefineMembers,theTranslator->trDefines())); - m_sHandler.insert("file/memberdecl/typedefs", + m_sHandler.insert("file/memberdecl/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decTypedefMembers,theTranslator->trTypedefs())); - m_sHandler.insert("file/memberdecl/sequences", + m_sHandler.insert("file/memberdecl/sequences", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decSequenceMembers,theTranslator->trSequences())); - m_sHandler.insert("file/memberdecl/dictionaries", + m_sHandler.insert("file/memberdecl/dictionaries", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decDictionaryMembers,theTranslator->trDictionaries())); - m_sHandler.insert("file/memberdecl/enums", + m_sHandler.insert("file/memberdecl/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decEnumMembers,theTranslator->trEnumerations())); - m_sHandler.insert("file/memberdecl/functions", + m_sHandler.insert("file/memberdecl/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decFuncMembers, COMPILE_FOR_2_OPTIONS( @@ -658,115 +658,115 @@ class LayoutParser : public QXmlDefaultHandler SrcLangExt_Fortran,theTranslator->trSubprograms(), SrcLangExt_VHDL,theTranslator->trFunctionAndProc() ))); - m_sHandler.insert("file/memberdecl/variables", + m_sHandler.insert("file/memberdecl/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decVarMembers, sliceOpt ? theTranslator->trConstants() : theTranslator->trVariables())); - m_eHandler.insert("file/memberdecl", + m_eHandler.insert("file/memberdecl", new EndElementHandler(this,&LayoutParser::endMemberDecl)); - m_sHandler.insert("file/memberdef", + m_sHandler.insert("file/memberdef", new StartElementHandler(this,&LayoutParser::startMemberDef)); - m_sHandler.insert("file/memberdef/inlineclasses", + m_sHandler.insert("file/memberdef/inlineclasses", new StartElementHandlerSection(this,LayoutDocEntry::FileInlineClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_1_OPTION( theTranslator->trClassDocumentation(), SrcLangExt_Fortran,theTranslator->trTypeDocumentation() ))); - m_sHandler.insert("file/memberdef/defines", + m_sHandler.insert("file/memberdef/defines", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docDefineMembers,theTranslator->trDefineDocumentation())); - m_sHandler.insert("file/memberdef/typedefs", + m_sHandler.insert("file/memberdef/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docTypedefMembers,theTranslator->trTypedefDocumentation())); - m_sHandler.insert("file/memberdef/sequences", + m_sHandler.insert("file/memberdef/sequences", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docSequenceMembers,theTranslator->trSequenceDocumentation())); - m_sHandler.insert("file/memberdef/dictionaries", + m_sHandler.insert("file/memberdef/dictionaries", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docDictionaryMembers, theTranslator->trDictionaryDocumentation())); - m_sHandler.insert("file/memberdef/enums", + m_sHandler.insert("file/memberdef/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docEnumMembers, theTranslator->trEnumerationTypeDocumentation())); - m_sHandler.insert("file/memberdef/functions", + m_sHandler.insert("file/memberdef/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docFuncMembers, COMPILE_FOR_1_OPTION( theTranslator->trFunctionDocumentation(), SrcLangExt_Fortran,theTranslator->trSubprogramDocumentation() ))); - m_sHandler.insert("file/memberdef/variables", + m_sHandler.insert("file/memberdef/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docVarMembers,theTranslator->trVariableDocumentation())); - m_eHandler.insert("file/memberdef", + m_eHandler.insert("file/memberdef", new EndElementHandler(this,&LayoutParser::endMemberDef)); - m_eHandler.insert("file", + m_eHandler.insert("file", new EndElementHandler(this,&LayoutParser::endFile)); // group layout handlers - m_sHandler.insert("group", + m_sHandler.insert("group", new StartElementHandler(this,&LayoutParser::startGroup)); - m_sHandler.insert("group/briefdescription", + m_sHandler.insert("group/briefdescription", new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("group/detaileddescription", + m_sHandler.insert("group/detaileddescription", new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, theTranslator->trDetailedDescription())); - m_sHandler.insert("group/authorsection", + m_sHandler.insert("group/authorsection", new StartElementHandlerKind(this,LayoutDocEntry::AuthorSection,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("group/groupgraph", + m_sHandler.insert("group/groupgraph", new StartElementHandlerKind(this,LayoutDocEntry::GroupGraph,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("group/memberdecl/membergroups", + m_sHandler.insert("group/memberdecl/membergroups", new StartElementHandlerKind(this,LayoutDocEntry::MemberGroups,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("group/memberdecl", + m_sHandler.insert("group/memberdecl", new StartElementHandler(this,&LayoutParser::startMemberDecl)); - m_sHandler.insert("group/memberdecl/classes", + m_sHandler.insert("group/memberdecl/classes", new StartElementHandlerSection(this,LayoutDocEntry::GroupClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_2_OPTIONS( theTranslator->trCompounds(), SrcLangExt_VHDL,theTranslator->trVhdlType(VhdlDocGen::ENTITY,FALSE), SrcLangExt_Fortran,theTranslator->trDataTypes() ))); - m_sHandler.insert("group/memberdecl/namespaces", + m_sHandler.insert("group/memberdecl/namespaces", new StartElementHandlerSection(this,LayoutDocEntry::GroupNamespaces,&LayoutParser::startSectionEntry, COMPILE_FOR_2_OPTIONS( theTranslator->trNamespaces(), SrcLangExt_Java,theTranslator->trPackages(), SrcLangExt_Fortran,theTranslator->trModules() ))); - m_sHandler.insert("group/memberdecl/dirs", + m_sHandler.insert("group/memberdecl/dirs", new StartElementHandlerSection(this,LayoutDocEntry::GroupDirs,&LayoutParser::startSectionEntry, theTranslator->trDirectories() )); - m_sHandler.insert("group/memberdecl/nestedgroups", + m_sHandler.insert("group/memberdecl/nestedgroups", new StartElementHandlerSection(this,LayoutDocEntry::GroupNestedGroups,&LayoutParser::startSectionEntry, theTranslator->trModules() )); - m_sHandler.insert("group/memberdecl/files", + m_sHandler.insert("group/memberdecl/files", new StartElementHandlerSection(this,LayoutDocEntry::GroupFiles,&LayoutParser::startSectionEntry, theTranslator->trFile(TRUE,FALSE) )); - m_sHandler.insert("group/memberdecl/defines", + m_sHandler.insert("group/memberdecl/defines", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decDefineMembers,theTranslator->trDefines())); - m_sHandler.insert("group/memberdecl/typedefs", + m_sHandler.insert("group/memberdecl/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decTypedefMembers,theTranslator->trTypedefs())); - m_sHandler.insert("group/memberdecl/sequences", + m_sHandler.insert("group/memberdecl/sequences", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decSequenceMembers,theTranslator->trSequences())); - m_sHandler.insert("group/memberdecl/dictionaries", + m_sHandler.insert("group/memberdecl/dictionaries", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decDictionaryMembers,theTranslator->trDictionaries())); - m_sHandler.insert("group/memberdecl/enums", + m_sHandler.insert("group/memberdecl/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decEnumMembers,theTranslator->trEnumerations())); - m_sHandler.insert("group/memberdecl/enumvalues", + m_sHandler.insert("group/memberdecl/enumvalues", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decEnumValMembers,theTranslator->trEnumerationValues())); - m_sHandler.insert("group/memberdecl/functions", + m_sHandler.insert("group/memberdecl/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decFuncMembers, COMPILE_FOR_2_OPTIONS( @@ -774,116 +774,116 @@ class LayoutParser : public QXmlDefaultHandler SrcLangExt_Fortran,theTranslator->trSubprograms(), SrcLangExt_VHDL,theTranslator->trFunctionAndProc() ))); - m_sHandler.insert("group/memberdecl/variables", + m_sHandler.insert("group/memberdecl/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decVarMembers,theTranslator->trVariables())); - m_sHandler.insert("group/memberdecl/signals", + m_sHandler.insert("group/memberdecl/signals", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decSignalMembers,theTranslator->trSignals())); - m_sHandler.insert("group/memberdecl/publicslots", + m_sHandler.insert("group/memberdecl/publicslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decPubSlotMembers,theTranslator->trPublicSlots())); - m_sHandler.insert("group/memberdecl/protectedslots", + m_sHandler.insert("group/memberdecl/protectedslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decProSlotMembers,theTranslator->trProtectedSlots())); - m_sHandler.insert("group/memberdecl/privateslots", + m_sHandler.insert("group/memberdecl/privateslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decPriSlotMembers,theTranslator->trPrivateSlots())); - m_sHandler.insert("group/memberdecl/events", + m_sHandler.insert("group/memberdecl/events", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decEventMembers,theTranslator->trEvents())); - m_sHandler.insert("group/memberdecl/properties", + m_sHandler.insert("group/memberdecl/properties", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decPropMembers,theTranslator->trProperties())); - m_sHandler.insert("group/memberdecl/friends", + m_sHandler.insert("group/memberdecl/friends", new StartElementHandlerMember(this,&LayoutParser::startMemberDeclEntry, MemberListType_decFriendMembers,theTranslator->trFriends())); - m_eHandler.insert("group/memberdecl", + m_eHandler.insert("group/memberdecl", new EndElementHandler(this,&LayoutParser::endMemberDecl)); - m_sHandler.insert("group/memberdef", + m_sHandler.insert("group/memberdef", new StartElementHandler(this,&LayoutParser::startMemberDef)); - m_sHandler.insert("group/memberdef/pagedocs", + m_sHandler.insert("group/memberdef/pagedocs", new StartElementHandlerKind(this,LayoutDocEntry::GroupPageDocs,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("group/memberdef/inlineclasses", + m_sHandler.insert("group/memberdef/inlineclasses", new StartElementHandlerSection(this,LayoutDocEntry::GroupInlineClasses,&LayoutParser::startSectionEntry, COMPILE_FOR_1_OPTION( theTranslator->trClassDocumentation(), SrcLangExt_Fortran,theTranslator->trTypeDocumentation() ))); - m_sHandler.insert("group/memberdef/defines", + m_sHandler.insert("group/memberdef/defines", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docDefineMembers,theTranslator->trDefineDocumentation())); - m_sHandler.insert("group/memberdef/typedefs", + m_sHandler.insert("group/memberdef/typedefs", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docTypedefMembers,theTranslator->trTypedefDocumentation())); - m_sHandler.insert("group/memberdef/sequences", + m_sHandler.insert("group/memberdef/sequences", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docSequenceMembers,theTranslator->trSequenceDocumentation())); - m_sHandler.insert("group/memberdef/dictionaries", + m_sHandler.insert("group/memberdef/dictionaries", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docDictionaryMembers, theTranslator->trDictionaryDocumentation())); - m_sHandler.insert("group/memberdef/enums", + m_sHandler.insert("group/memberdef/enums", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docEnumMembers,theTranslator->trEnumerationTypeDocumentation())); - m_sHandler.insert("group/memberdef/enumvalues", + m_sHandler.insert("group/memberdef/enumvalues", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docEnumValMembers,theTranslator->trEnumerationValueDocumentation())); - m_sHandler.insert("group/memberdef/functions", + m_sHandler.insert("group/memberdef/functions", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docFuncMembers, COMPILE_FOR_1_OPTION( theTranslator->trFunctionDocumentation(), SrcLangExt_Fortran,theTranslator->trSubprogramDocumentation() ))); - m_sHandler.insert("group/memberdef/variables", + m_sHandler.insert("group/memberdef/variables", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docVarMembers,theTranslator->trVariableDocumentation())); - m_sHandler.insert("group/memberdef/signals", + m_sHandler.insert("group/memberdef/signals", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, - MemberListType_docSignalMembers,theTranslator->trSignals())); - m_sHandler.insert("group/memberdef/publicslots", + MemberListType_docSignalMembers,theTranslator->trSignals())); + m_sHandler.insert("group/memberdef/publicslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docPubSlotMembers,theTranslator->trPublicSlots())); - m_sHandler.insert("group/memberdef/protectedslots", + m_sHandler.insert("group/memberdef/protectedslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docProSlotMembers,theTranslator->trProtectedSlots())); - m_sHandler.insert("group/memberdef/privateslots", + m_sHandler.insert("group/memberdef/privateslots", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docPriSlotMembers,theTranslator->trPrivateSlots())); - m_sHandler.insert("group/memberdef/events", + m_sHandler.insert("group/memberdef/events", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docEventMembers,theTranslator->trEvents())); - m_sHandler.insert("group/memberdef/properties", + m_sHandler.insert("group/memberdef/properties", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docPropMembers,theTranslator->trProperties())); - m_sHandler.insert("group/memberdef/friends", + m_sHandler.insert("group/memberdef/friends", new StartElementHandlerMember(this,&LayoutParser::startMemberDefEntry, MemberListType_docFriendMembers,theTranslator->trFriends())); - m_eHandler.insert("group/memberdef", + m_eHandler.insert("group/memberdef", new EndElementHandler(this,&LayoutParser::endMemberDef)); - m_eHandler.insert("group", + m_eHandler.insert("group", new EndElementHandler(this,&LayoutParser::endGroup)); // directory layout handlers - m_sHandler.insert("directory", + m_sHandler.insert("directory", new StartElementHandler(this,&LayoutParser::startDirectory)); - m_sHandler.insert("directory/briefdescription", + m_sHandler.insert("directory/briefdescription", new StartElementHandlerKind(this,LayoutDocEntry::BriefDesc,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("directory/detaileddescription", + m_sHandler.insert("directory/detaileddescription", new StartElementHandlerSection(this,LayoutDocEntry::DetailedDesc,&LayoutParser::startSectionEntry, theTranslator->trDetailedDescription())); - m_sHandler.insert("directory/directorygraph", + m_sHandler.insert("directory/directorygraph", new StartElementHandlerKind(this,LayoutDocEntry::DirGraph,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("directory/memberdecl", + m_sHandler.insert("directory/memberdecl", new StartElementHandler(this,&LayoutParser::startMemberDecl)); - m_sHandler.insert("directory/memberdecl/dirs", + m_sHandler.insert("directory/memberdecl/dirs", new StartElementHandlerKind(this,LayoutDocEntry::DirSubDirs,&LayoutParser::startSimpleEntry)); - m_sHandler.insert("directory/memberdecl/files", + m_sHandler.insert("directory/memberdecl/files", new StartElementHandlerKind(this,LayoutDocEntry::DirFiles,&LayoutParser::startSimpleEntry)); - m_eHandler.insert("directory/memberdecl", + m_eHandler.insert("directory/memberdecl", new EndElementHandler(this,&LayoutParser::endMemberDecl)); - m_eHandler.insert("directory", + m_eHandler.insert("directory", new EndElementHandler(this,&LayoutParser::endDirectory)); } @@ -964,7 +964,7 @@ class LayoutParser : public QXmlDefaultHandler if (m_rootNav && !m_rootNav->find(LayoutNavEntry::MainPage)) { // no MainPage node... add one as the first item of the root node... - new LayoutNavEntry(m_rootNav,LayoutNavEntry::MainPage, TRUE, + new LayoutNavEntry(m_rootNav,LayoutNavEntry::MainPage, TRUE, /*Config_getBool(GENERATE_TREEVIEW) ? "main" :*/ "index", theTranslator->trMainPage(),"",TRUE); } @@ -974,8 +974,8 @@ class LayoutParser : public QXmlDefaultHandler { static bool javaOpt = Config_getBool(OPTIMIZE_OUTPUT_JAVA); static bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN); - static bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL); - static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE); + static bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL); + static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE); static bool hasGraphicalHierarchy = Config_getBool(HAVE_DOT) && Config_getBool(GRAPHICAL_HIERARCHY); static bool extractAll = Config_getBool(EXTRACT_ALL); @@ -1213,7 +1213,7 @@ class LayoutParser : public QXmlDefaultHandler } i++; } - if (mapping[i].typeStr==0) + if (mapping[i].typeStr==0) { if (type.isEmpty()) { @@ -1230,7 +1230,7 @@ class LayoutParser : public QXmlDefaultHandler QCString title = attrib.value("title").utf8(); bool isVisible = elemIsVisible(attrib); if (title.isEmpty()) // use default title - { + { title = mapping[i].mainName; // use title for main row if (m_rootNav!=LayoutDocManager::instance().rootNavEntry() && !mapping[i].subName.isEmpty()) { @@ -1384,7 +1384,7 @@ class LayoutParser : public QXmlDefaultHandler } // reimplemented from QXmlDefaultHandler - bool startElement( const QString&, const QString&, + bool startElement( const QString&, const QString&, const QString& name, const QXmlAttributes& attrib ) { //printf("startElement [%s]::[%s]\n",m_scope.data(),name.data()); @@ -1568,7 +1568,7 @@ void writeDefaultLayoutFile(const char *fileName) //---------------------------------------------------------------------------------- // Convert input to a title. -// The format of input can be a simple title "A title" or in case there are different +// The format of input can be a simple title "A title" or in case there are different // titles for some programming languages they can take the following form: // "A title|16=Another title|8=Yet Another title" // where the number is a value of SrcLangExt in decimal notation (i.e. 16=Java, 8=IDL). diff --git a/src/mangen.cpp b/src/mangen.cpp index 6709748..1faa296 100644 --- a/src/mangen.cpp +++ b/src/mangen.cpp @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -41,7 +41,7 @@ static QCString getExtension() QCString ext = Config_getString(MAN_EXTENSION); if (ext.isEmpty()) { - ext = "3"; + ext = "3"; } else { @@ -49,7 +49,7 @@ static QCString getExtension() { if (ext.length()==1) { - ext = "3"; + ext = "3"; } else // strip . { @@ -91,8 +91,8 @@ ManGenerator::~ManGenerator() void ManGenerator::init() { - QCString &manOutput = Config_getString(MAN_OUTPUT); - + QCString manOutput = Config_getString(MAN_OUTPUT); + QDir d(manOutput); if (!d.exists() && !d.mkdir(manOutput)) { @@ -139,7 +139,7 @@ static QCString buildFileName(const char *name) } QCString manExtension = "." + getExtension(); - if (fileName.right(manExtension.length())!=manExtension) + if (fileName.right(manExtension.length())!=manExtension) { fileName+=manExtension; } @@ -161,11 +161,11 @@ void ManGenerator::endFile() void ManGenerator::endTitleHead(const char *,const char *name) { - t << ".TH \"" << name << "\" " << getExtension() << " \"" + t << ".TH \"" << name << "\" " << getExtension() << " \"" << dateToString(FALSE) << "\" \""; if (!Config_getString(PROJECT_NUMBER).isEmpty()) t << "Version " << Config_getString(PROJECT_NUMBER) << "\" \""; - if (Config_getString(PROJECT_NAME).isEmpty()) + if (Config_getString(PROJECT_NAME).isEmpty()) t << "Doxygen"; else t << Config_getString(PROJECT_NAME); @@ -284,7 +284,7 @@ void ManGenerator::docify(const char *str) { const char *p=str; char c=0; - while ((c=*p++)) + while ((c=*p++)) { switch(c) { @@ -318,8 +318,8 @@ void ManGenerator::codify(const char *str) case '.': t << "\\&."; break; // see bug652277 case '\t': spacesToNextTabStop = Config_getInt(TAB_SIZE) - (m_col%Config_getInt(TAB_SIZE)); - t << Doxygen::spaces.left(spacesToNextTabStop); - m_col+=spacesToNextTabStop; + t << Doxygen::spaces.left(spacesToNextTabStop); + m_col+=spacesToNextTabStop; break; case '\n': t << "\n"; m_firstCol=TRUE; m_col=0; break; case '\\': t << "\\"; m_col++; break; @@ -346,21 +346,21 @@ void ManGenerator::writeChar(char c) m_paragraph=FALSE; } -void ManGenerator::startDescList(SectionTypes) +void ManGenerator::startDescList(SectionTypes) { - if (!m_firstCol) - { t << endl << ".PP" << endl; - m_firstCol=TRUE; m_paragraph=TRUE; + if (!m_firstCol) + { t << endl << ".PP" << endl; + m_firstCol=TRUE; m_paragraph=TRUE; m_col=0; } m_paragraph=FALSE; startBold(); } -void ManGenerator::startTitle() -{ - if (!m_firstCol) t << endl; - t << ".SH \""; +void ManGenerator::startTitle() +{ + if (!m_firstCol) t << endl; + t << ".SH \""; m_firstCol=FALSE; m_paragraph=FALSE; } @@ -370,40 +370,40 @@ void ManGenerator::endTitle() t << "\""; } -void ManGenerator::startItemListItem() -{ - if (!m_firstCol) t << endl; - t << ".TP" << endl; +void ManGenerator::startItemListItem() +{ + if (!m_firstCol) t << endl; + t << ".TP" << endl; m_firstCol=TRUE; m_paragraph=FALSE; m_col=0; -} +} void ManGenerator::endItemListItem() { } -void ManGenerator::startCodeFragment() -{ +void ManGenerator::startCodeFragment() +{ newParagraph(); - t << ".nf" << endl; + t << ".nf" << endl; m_firstCol=TRUE; m_paragraph=FALSE; } -void ManGenerator::endCodeFragment() -{ +void ManGenerator::endCodeFragment() +{ if (!m_firstCol) t << endl; - t << ".fi" << endl; + t << ".fi" << endl; m_firstCol=TRUE; m_paragraph=FALSE; m_col=0; } -void ManGenerator::startMemberDoc(const char *,const char *,const char *,const char *,int,int,bool) -{ +void ManGenerator::startMemberDoc(const char *,const char *,const char *,const char *,int,int,bool) +{ if (!m_firstCol) t << endl; - t << ".SS \""; + t << ".SS \""; m_firstCol=FALSE; m_paragraph=FALSE; } @@ -413,7 +413,7 @@ void ManGenerator::startDoxyAnchor(const char *,const char *manName, const char *) { // something to be done? - if( !Config_getBool(MAN_LINKS) ) + if( !Config_getBool(MAN_LINKS) ) { return; // no } @@ -426,14 +426,14 @@ void ManGenerator::startDoxyAnchor(const char *,const char *manName, //printf("Converting man link '%s'->'%s'->'%s'\n", // name,baseName.data(),buildFileName(baseName).data()); - + // - remove dangerous characters and append suffix, then add dir prefix QCString fileName=m_dir+"/"+buildFileName( baseName ); QFile linkfile( fileName ); // - only create file if it doesn't exist already - if ( !linkfile.open( IO_ReadOnly ) ) + if ( !linkfile.open( IO_ReadOnly ) ) { - if ( linkfile.open( IO_WriteOnly ) ) + if ( linkfile.open( IO_WriteOnly ) ) { FTextStream linkstream; linkstream.setDevice(&linkfile); @@ -449,10 +449,10 @@ void ManGenerator::endMemberDoc(bool) t << "\"\n"; } -void ManGenerator::startSubsection() -{ +void ManGenerator::startSubsection() +{ if (!m_firstCol) t << endl; - t << ".SS \""; + t << ".SS \""; m_firstCol=FALSE; m_paragraph=FALSE; } @@ -463,10 +463,10 @@ void ManGenerator::endSubsection() } -void ManGenerator::startSubsubsection() -{ +void ManGenerator::startSubsubsection() +{ if (!m_firstCol) t << endl; - t << "\n.SS \""; + t << "\n.SS \""; m_firstCol=FALSE; m_paragraph=FALSE; } @@ -476,10 +476,10 @@ void ManGenerator::endSubsubsection() t << "\""; } -void ManGenerator::writeSynopsis() -{ +void ManGenerator::writeSynopsis() +{ if (!m_firstCol) t << endl; - t << ".SH SYNOPSIS\n.br\n.PP\n"; + t << ".SH SYNOPSIS\n.br\n.PP\n"; m_firstCol=TRUE; m_paragraph=FALSE; } @@ -534,31 +534,31 @@ void ManGenerator::endAnonTypeScope(int indentLevel) } -void ManGenerator::startMemberItem(const char *,int,const char *) -{ +void ManGenerator::startMemberItem(const char *,int,const char *) +{ if (m_firstCol && !m_insideTabbing) t << ".in +1c\n"; - t << "\n.ti -1c\n.RI \""; + t << "\n.ti -1c\n.RI \""; m_firstCol=FALSE; } -void ManGenerator::endMemberItem() -{ - t << "\"\n.br"; +void ManGenerator::endMemberItem() +{ + t << "\"\n.br"; } -void ManGenerator::startMemberList() -{ +void ManGenerator::startMemberList() +{ if (!m_insideTabbing) { - t << "\n.in +1c"; m_firstCol=FALSE; + t << "\n.in +1c"; m_firstCol=FALSE; } } -void ManGenerator::endMemberList() -{ +void ManGenerator::endMemberList() +{ if (!m_insideTabbing) { - t << "\n.in -1c"; m_firstCol=FALSE; + t << "\n.in -1c"; m_firstCol=FALSE; } } @@ -595,7 +595,7 @@ void ManGenerator::endMemberGroup(bool) void ManGenerator::startSection(const char *,const char *,SectionType type) { - if( !m_inHeader ) + if( !m_inHeader ) { switch(type) { @@ -634,9 +634,9 @@ void ManGenerator::endSection(const char *,SectionType type) void ManGenerator::startExamples() { - if (!m_firstCol) - { t << endl << ".PP" << endl; - m_firstCol=TRUE; m_paragraph=TRUE; + if (!m_firstCol) + { t << endl << ".PP" << endl; + m_firstCol=TRUE; m_paragraph=TRUE; m_col=0; } m_paragraph=FALSE; @@ -652,9 +652,9 @@ void ManGenerator::endExamples() void ManGenerator::startDescTable(const char *title) { - if (!m_firstCol) - { t << endl << ".PP" << endl; - m_firstCol=TRUE; m_paragraph=TRUE; + if (!m_firstCol) + { t << endl << ".PP" << endl; + m_firstCol=TRUE; m_paragraph=TRUE; m_col=0; } m_paragraph=FALSE; @@ -672,9 +672,9 @@ void ManGenerator::endDescTable() void ManGenerator::startParamList(ParamListTypes,const char *title) { - if (!m_firstCol) - { t << endl << ".PP" << endl; - m_firstCol=TRUE; m_paragraph=TRUE; + if (!m_firstCol) + { t << endl << ".PP" << endl; + m_firstCol=TRUE; m_paragraph=TRUE; m_col=0; } m_paragraph=FALSE; @@ -692,16 +692,16 @@ void ManGenerator::writeDoc(DocNode *n,const Definition *ctx,const MemberDef *) { ManDocVisitor *visitor = new ManDocVisitor(t,*this,ctx?ctx->getDefFileExtension():QCString("")); n->accept(visitor); - delete visitor; + delete visitor; m_firstCol=FALSE; m_paragraph = FALSE; } void ManGenerator::startConstraintList(const char *header) { - if (!m_firstCol) - { t << endl << ".PP" << endl; - m_firstCol=TRUE; m_paragraph=TRUE; + if (!m_firstCol) + { t << endl << ".PP" << endl; + m_firstCol=TRUE; m_paragraph=TRUE; m_col=0; } m_paragraph=FALSE; @@ -748,16 +748,16 @@ void ManGenerator::endConstraintList() } -void ManGenerator::startInlineHeader() +void ManGenerator::startInlineHeader() { - if (!m_firstCol) + if (!m_firstCol) { t << endl << ".PP" << endl << ".in -1c" << endl; } - t << ".RI \"\\fB"; + t << ".RI \"\\fB"; } -void ManGenerator::endInlineHeader() +void ManGenerator::endInlineHeader() { t << "\\fP\"" << endl << ".in +1c" << endl; m_firstCol = FALSE; @@ -765,7 +765,7 @@ void ManGenerator::endInlineHeader() void ManGenerator::startMemberDocSimple(bool isEnum) { - if (!m_firstCol) + if (!m_firstCol) { t << endl << ".PP" << endl; } diff --git a/src/markdown.cpp b/src/markdown.cpp index b04ab2a..2863669 100644 --- a/src/markdown.cpp +++ b/src/markdown.cpp @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright (C) 1997-2015 by Dimitri van Heesch. + * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby @@ -35,9 +35,9 @@ #include <qglobal.h> #include <qregexp.h> #include <qfileinfo.h> -#include <qdict.h> -#include <qvector.h> -//#define USE_ORIGINAL_TABLES + +#include <unordered_map> +#include <functional> #include "markdown.h" #include "growbuf.h" @@ -46,13 +46,96 @@ #include "doxygen.h" #include "commentscan.h" #include "entry.h" -#include "bufstr.h" #include "commentcnv.h" #include "config.h" #include "section.h" #include "message.h" #include "portable.h" +#if !defined(NDEBUG) +#define ENABLE_TRACING +#endif + +#ifdef ENABLE_TRACING +#define IOSTREAM stdout +#define DATA_BUFSIZE 20 +#if defined(_WIN32) && !defined(CYGWIN) +#define PRETTY_FUNC __FUNCSIG__ +#else +#define PRETTY_FUNC __PRETTY_FUNCTION__ +#endif + +class Trace +{ + public: + Trace(const char *func) : m_func(func) + { + if (Debug::isFlagSet(Debug::Markdown)) + { + fprintf(IOSTREAM,"> %s\n",func); + s_indent++; + } + } + Trace(const char *func,const char *data) : m_func(func) + { + if (Debug::isFlagSet(Debug::Markdown)) + { + indent(); + char data_s[DATA_BUFSIZE*2+1] = ""; // worst case each input char outputs 2 chars + 0 terminator. + int j=0; + if (data) + { + for (int i=0;i<DATA_BUFSIZE;i++) + { + char c=data[i]; + if (c==0) break; + else if (c=='\n') { data_s[j++]='\\'; data_s[j++]='n'; } + else if (c=='\t') { data_s[j++]='\\'; data_s[j++]='t'; } + else if (c=='\r') { data_s[j++]='\\'; data_s[j++]='r'; } + else if (c=='\\') { data_s[j++]='\\'; data_s[j++]='\\'; } + else data_s[j++]=c; + } + } + data_s[j++]=0; + fprintf(IOSTREAM,"> %s data=[%s…]\n",func,data_s); + s_indent++; + } + } + ~Trace() + { + if (Debug::isFlagSet(Debug::Markdown)) + { + s_indent--; + indent(); + fprintf(IOSTREAM,"< %s\n",m_func); + } + } + void trace(const char *fmt,...) + { + if (Debug::isFlagSet(Debug::Markdown)) + { + indent(); + fprintf(IOSTREAM,": %s: ",m_func); + va_list args; + va_start(args,fmt); + vfprintf(IOSTREAM, fmt, args); + va_end(args); + } + } + private: + void indent() { for (int i=0;i<s_indent;i++) fputs(" ",IOSTREAM); } + const char *m_func; + static int s_indent; +}; + +int Trace::s_indent = 0; +#define TRACE(data) Trace trace_(PRETTY_FUNC,data); +#define TRACE_MORE(...) trace_.trace(__VA_ARGS__); +#else +#define TRACE(data) do {} while(false) +#define TRACE_MORE(...) do {} while(false) +#endif + //----------- // is character at position i in data part of an identifier? @@ -82,13 +165,6 @@ //---------- -struct LinkRef -{ - LinkRef(const QCString &l,const QCString &t) : link(l), title(t) {} - QCString link; - QCString title; -}; - struct TableCell { TableCell() : colSpan(false) {} @@ -96,30 +172,51 @@ struct TableCell bool colSpan; }; -typedef int (*action_t)(GrowBuf &out,const char *data,int offset,int size); +Markdown::Markdown(const char *fileName,int lineNr,int indentLevel) + : m_fileName(fileName), m_lineNr(lineNr), m_indentLevel(indentLevel) +{ + using namespace std::placeholders; + // setup callback table for special characters + m_actions[(unsigned int)'_'] = std::bind(&Markdown::processEmphasis, this,_1,_2,_3); + m_actions[(unsigned int)'*'] = std::bind(&Markdown::processEmphasis, this,_1,_2,_3); + m_actions[(unsigned int)'~'] = std::bind(&Markdown::processEmphasis, this,_1,_2,_3); + m_actions[(unsigned int)'`'] = std::bind(&Markdown::processCodeSpan, this,_1,_2,_3); + m_actions[(unsigned int)'\\']= std::bind(&Markdown::processSpecialCommand,this,_1,_2,_3); + m_actions[(unsigned int)'@'] = std::bind(&Markdown::processSpecialCommand,this,_1,_2,_3); + m_actions[(unsigned int)'['] = std::bind(&Markdown::processLink, this,_1,_2,_3); + m_actions[(unsigned int)'!'] = std::bind(&Markdown::processLink, this,_1,_2,_3); + m_actions[(unsigned int)'<'] = std::bind(&Markdown::processHtmlTag, this,_1,_2,_3); + m_actions[(unsigned int)'-'] = std::bind(&Markdown::processNmdash, this,_1,_2,_3); + m_actions[(unsigned int)'"'] = std::bind(&Markdown::processQuoted, this,_1,_2,_3); + (void)m_lineNr; // not used yet +} enum Alignment { AlignNone, AlignLeft, AlignCenter, AlignRight }; -//---------- - -static QDict<LinkRef> g_linkRefs(257); -static action_t g_actions[256]; -static Entry *g_current; -static QCString g_fileName; -static int g_lineNr; -static int g_indentLevel=0; // 0 is outside markdown, -1=page level -static const uchar g_utf8_nbsp[3] = { 0xc2, 0xa0, 0}; // UTF-8 nbsp -static const char *g_doxy_nsbp = "&_doxy_nbsp;"; // doxygen escape command for UTF-8 nbsp -//---------- - +//---------- contants ------- +// +const uchar g_utf8_nbsp[3] = { 0xc2, 0xa0, 0}; // UTF-8 nbsp +const char *g_doxy_nsbp = "&_doxy_nbsp;"; // doxygen escape command for UTF-8 nbsp const int codeBlockIndent = 4; -static void processInline(GrowBuf &out,const char *data,int size); +//---------- helpers ------- + +// test if the next characters in data represent a new line (which can be character \n or string \ilinebr). +// returns 0 if no newline is found, or the number of characters that make up the newline if found. +inline int isNewline(const char *data) +{ + // normal newline + if (data[0] == '\n') return 1; + // artificial new line from ^^ in ALIASES + if (data[0] == '\\' && qstrncmp(data+1,"ilinebr",7)==0) return 8; + return 0; +} // escape characters that have a special meaning later on. static QCString escapeSpecialChars(const QCString &s) { + TRACE(s.data()); if (s.isEmpty()) return ""; bool insideQuote=FALSE; GrowBuf growBuf; @@ -145,6 +242,7 @@ static QCString escapeSpecialChars(const QCString &s) static void convertStringFragment(QCString &result,const char *data,int size) { + TRACE(result.data()); if (size<0) size=0; result.resize(size+1); memcpy(result.rawData(),data,size); @@ -194,8 +292,9 @@ static Alignment markersToAlignment(bool leftMarker,bool rightMarker) // \xmlonly..\endxmlonly // \rtfonly..\endrtfonly // \manonly..\endmanonly -static QCString isBlockCommand(const char *data,int offset,int size) +QCString Markdown::isBlockCommand(const char *data,int offset,int size) { + TRACE(data); bool openBracket = offset>0 && data[-1]=='{'; bool isEscaped = offset>0 && (data[-1]=='\\' || data[-1]=='@'); if (isEscaped) return QCString(); @@ -248,8 +347,9 @@ static QCString isBlockCommand(const char *data,int offset,int size) /** looks for the next emph char, skipping other constructs, and * stopping when either it is found, or we are at the end of a paragraph. */ -static int findEmphasisChar(const char *data, int size, char c, int c_size) +int Markdown::findEmphasisChar(const char *data, int size, char c, int c_size) { + TRACE(data); int i = 1; while (i<size) @@ -346,8 +446,9 @@ static int findEmphasisChar(const char *data, int size, char c, int c_size) } /** process single emphasis */ -static int processEmphasis1(GrowBuf &out, const char *data, int size, char c) +int Markdown::processEmphasis1(const char *data, int size, char c) { + TRACE(data); int i = 0, len; /* skipping one symbol if coming from emph3 */ @@ -367,9 +468,9 @@ static int processEmphasis1(GrowBuf &out, const char *data, int size, char c) } if (data[i]==c && data[i-1]!=' ' && data[i-1]!='\n') { - out.addStr("<em>"); - processInline(out,data,i); - out.addStr("</em>"); + m_out.addStr("<em>"); + processInline(data,i); + m_out.addStr("</em>"); return i+1; } } @@ -377,8 +478,9 @@ static int processEmphasis1(GrowBuf &out, const char *data, int size, char c) } /** process double emphasis */ -static int processEmphasis2(GrowBuf &out, const char *data, int size, char c) +int Markdown::processEmphasis2(const char *data, int size, char c) { + TRACE(data); int i = 0, len; while (i<size) @@ -393,11 +495,11 @@ static int processEmphasis2(GrowBuf &out, const char *data, int size, char c) data[i-1]!='\n' ) { - if (c == '~') out.addStr("<strike>"); - else out.addStr("<strong>"); - processInline(out,data,i); - if (c == '~') out.addStr("</strike>"); - else out.addStr("</strong>"); + if (c == '~') m_out.addStr("<strike>"); + else m_out.addStr("<strong>"); + processInline(data,i); + if (c == '~') m_out.addStr("</strike>"); + else m_out.addStr("</strong>"); return i + 2; } i++; @@ -408,8 +510,9 @@ static int processEmphasis2(GrowBuf &out, const char *data, int size, char c) /** Parsing triple emphasis. * Finds the first closing tag, and delegates to the other emph */ -static int processEmphasis3(GrowBuf &out, const char *data, int size, char c) +int Markdown::processEmphasis3(const char *data, int size, char c) { + TRACE(data); int i = 0, len; while (i<size) @@ -429,15 +532,15 @@ static int processEmphasis3(GrowBuf &out, const char *data, int size, char c) if (i+2<size && data[i+1]==c && data[i+2]==c) { - out.addStr("<em><strong>"); - processInline(out,data,i); - out.addStr("</strong></em>"); + m_out.addStr("<em><strong>"); + processInline(data,i); + m_out.addStr("</strong></em>"); return i+3; } else if (i+1<size && data[i+1]==c) { // double symbol found, handing over to emph1 - len = processEmphasis1(out, data-2, size+2, c); + len = processEmphasis1(data-2, size+2, c); if (len==0) { return 0; @@ -450,7 +553,7 @@ static int processEmphasis3(GrowBuf &out, const char *data, int size, char c) else { // single symbol found, handing over to emph2 - len = processEmphasis2(out, data-1, size+1, c); + len = processEmphasis2(data-1, size+1, c); if (len==0) { return 0; @@ -465,8 +568,9 @@ static int processEmphasis3(GrowBuf &out, const char *data, int size, char c) } /** Process ndash and mdashes */ -static int processNmdash(GrowBuf &out,const char *data,int off,int size) +int Markdown::processNmdash(const char *data,int off,int size) { + TRACE(data); // precondition: data[0]=='-' int i=1; int count=1; @@ -486,12 +590,12 @@ static int processNmdash(GrowBuf &out,const char *data,int off,int size) if (count==2 && (data[2]=='>')) return 0; // end HTML comment if (count==2 && (off<8 || qstrncmp(data-8,"operator",8)!=0)) // -- => ndash { - out.addStr("–"); + m_out.addStr("–"); return 2; } else if (count==3) // --- => ndash { - out.addStr("—"); + m_out.addStr("—"); return 3; } // not an ndash or mdash @@ -499,8 +603,9 @@ static int processNmdash(GrowBuf &out,const char *data,int off,int size) } /** Process quoted section "...", can contain one embedded newline */ -static int processQuoted(GrowBuf &out,const char *data,int,int size) +int Markdown::processQuoted(const char *data,int,int size) { + TRACE(data); int i=1; int nl=0; while (i<size && data[i]!='"' && nl<2) @@ -510,7 +615,7 @@ static int processQuoted(GrowBuf &out,const char *data,int,int size) } if (i<size && data[i]=='"' && nl<2) { - out.addStr(data,i+1); + m_out.addStr(data,i+1); return i+1; } // not a quoted section @@ -520,8 +625,9 @@ static int processQuoted(GrowBuf &out,const char *data,int,int size) /** Process a HTML tag. Note that <pre>..</pre> are treated specially, in * the sense that all code inside is written unprocessed */ -static int processHtmlTagWrite(GrowBuf &out,const char *data,int offset,int size,bool doWrite) +int Markdown::processHtmlTagWrite(const char *data,int offset,int size,bool doWrite) { + TRACE(data); if (offset>0 && data[-1]=='\\') return 0; // escaped < // find the end of the html tag @@ -543,7 +649,7 @@ static int processHtmlTagWrite(GrowBuf &out,const char *data,int offset,int size tolower(data[i+2])=='p' && tolower(data[i+3])=='r' && tolower(data[i+4])=='e' && tolower(data[i+5])=='>') { // found </pre> tag, copy from start to end of tag - if (doWrite) out.addStr(data,i+6); + if (doWrite) m_out.addStr(data,i+6); //printf("found <pre>..</pre> [%d..%d]\n",0,i+6); return i+6; } @@ -566,13 +672,13 @@ static int processHtmlTagWrite(GrowBuf &out,const char *data,int offset,int size if (data[i]=='/' && i<size-1 && data[i+1]=='>') // <bla/> { //printf("Found htmlTag={%s}\n",QCString(data).left(i+2).data()); - if (doWrite) out.addStr(data,i+2); + if (doWrite) m_out.addStr(data,i+2); return i+2; } else if (data[i]=='>') // <bla> { //printf("Found htmlTag={%s}\n",QCString(data).left(i+1).data()); - if (doWrite) out.addStr(data,i+1); + if (doWrite) m_out.addStr(data,i+1); return i+1; } else if (data[i]==' ') // <bla attr=... @@ -592,7 +698,7 @@ static int processHtmlTagWrite(GrowBuf &out,const char *data,int offset,int size else if (!insideAttr && data[i]=='>') // found end of tag { //printf("Found htmlTag={%s}\n",QCString(data).left(i+1).data()); - if (doWrite) out.addStr(data,i+1); + if (doWrite) m_out.addStr(data,i+1); return i+1; } i++; @@ -603,13 +709,16 @@ static int processHtmlTagWrite(GrowBuf &out,const char *data,int offset,int size //printf("Not a valid html tag\n"); return 0; } -static int processHtmlTag(GrowBuf &out,const char *data,int offset,int size) + +int Markdown::processHtmlTag(const char *data,int offset,int size) { - return processHtmlTagWrite(out,data,offset,size,true); + TRACE(data); + return processHtmlTagWrite(data,offset,size,true); } -static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) +int Markdown::processEmphasis(const char *data,int offset,int size) { + TRACE(data); if ((offset>0 && !isOpenEmphChar(-1)) || // invalid char before * or _ (size>1 && data[0]!=data[1] && !(isIdChar(1) || extraChar(1) || data[1]=='[')) || // invalid char after * or _ (size>2 && data[0]==data[1] && !(isIdChar(2) || extraChar(2) || data[2]=='['))) // invalid char after ** or __ @@ -623,7 +732,7 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) { // whitespace cannot follow an opening emphasis if (data[1]==' ' || data[1]=='\n' || - (ret = processEmphasis1(out, data+1, size-1, c)) == 0) + (ret = processEmphasis1(data+1, size-1, c)) == 0) { return 0; } @@ -632,7 +741,7 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) if (size>3 && data[1]==c && data[2]!=c) // __bla or **bla { if (data[2]==' ' || data[2]=='\n' || - (ret = processEmphasis2(out, data+2, size-2, c)) == 0) + (ret = processEmphasis2(data+2, size-2, c)) == 0) { return 0; } @@ -641,7 +750,7 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) if (size>4 && c!='~' && data[1]==c && data[2]==c && data[3]!=c) // ___bla or ***bla { if (data[3]==' ' || data[3]=='\n' || - (ret = processEmphasis3(out, data+3, size-3, c)) == 0) + (ret = processEmphasis3(data+3, size-3, c)) == 0) { return 0; } @@ -650,29 +759,32 @@ static int processEmphasis(GrowBuf &out,const char *data,int offset,int size) return 0; } -static void writeMarkdownImage(GrowBuf &out, const char *fmt, bool explicitTitle, QCString title, QCString content, QCString link, FileDef *fd) +void Markdown::writeMarkdownImage(const char *fmt, bool explicitTitle, + const QCString &title, const QCString &content, + const QCString &link, const FileDef *fd) { - out.addStr("@image{inline} "); - out.addStr(fmt); - out.addStr(" "); - out.addStr(link.mid(fd ? 0 : 5)); + m_out.addStr("@image{inline} "); + m_out.addStr(fmt); + m_out.addStr(" "); + m_out.addStr(link.mid(fd ? 0 : 5)); if (!explicitTitle && !content.isEmpty()) { - out.addStr(" \""); - out.addStr(content); - out.addStr("\""); + m_out.addStr(" \""); + m_out.addStr(content); + m_out.addStr("\""); } else if ((content.isEmpty() || explicitTitle) && !title.isEmpty()) { - out.addStr(" \""); - out.addStr(title); - out.addStr("\""); + m_out.addStr(" \""); + m_out.addStr(title); + m_out.addStr("\""); } - out.addStr("\n"); + m_out.addStr("\n"); } -static int processLink(GrowBuf &out,const char *data,int,int size) +int Markdown::processLink(const char *data,int,int size) { + TRACE(data); QCString content; QCString link; QCString title; @@ -826,11 +938,12 @@ static int processLink(GrowBuf &out,const char *data,int,int size) link=content; } // lookup reference - LinkRef *lr = g_linkRefs.find(link.lower()); - if (lr) // found it + QCString link_lower = link.lower(); + auto lr_it=m_linkRefs.find(link_lower.str()); + if (lr_it!=m_linkRefs.end()) // found it { - link = lr->link; - title = lr->title; + link = lr_it->second.link; + title = lr_it->second.title; //printf("processLink: ref: link={%s} title={%s}\n",link.data(),title.data()); } else // reference not found! @@ -842,12 +955,13 @@ static int processLink(GrowBuf &out,const char *data,int,int size) } else if (i<size && data[i]!=':' && !content.isEmpty()) // minimal link ref notation [some id] { - LinkRef *lr = g_linkRefs.find(content.lower()); + QCString content_lower = content.lower(); + auto lr_it = m_linkRefs.find(content_lower.str()); //printf("processLink: minimal link {%s} lr=%p",content.data(),lr); - if (lr) // found it + if (lr_it!=m_linkRefs.end()) // found it { - link = lr->link; - title = lr->title; + link = lr_it->second.link; + title = lr_it->second.title; explicitTitle=TRUE; i=contentEnd; } @@ -871,9 +985,9 @@ static int processLink(GrowBuf &out,const char *data,int,int size) int toc_level = Config_getInt(TOC_INCLUDE_HEADINGS); if (toc_level > 0 && toc_level <=5) { - out.addStr("@tableofcontents{html:"); - out.addStr(QCString().setNum(toc_level)); - out.addStr("}"); + m_out.addStr("@tableofcontents{html:"); + m_out.addStr(QCString().setNum(toc_level)); + m_out.addStr("}"); } } else if (isImageLink) @@ -884,25 +998,25 @@ static int processLink(GrowBuf &out,const char *data,int,int size) (fd=findFileDef(Doxygen::imageNameLinkedMap,link,ambig))) // assume doxygen symbol link or local image link { - writeMarkdownImage(out, "html", explicitTitle, title, content, link, fd); - writeMarkdownImage(out, "latex", explicitTitle, title, content, link, fd); - writeMarkdownImage(out, "rtf", explicitTitle, title, content, link, fd); - writeMarkdownImage(out, "docbook", explicitTitle, title, content, link, fd); + writeMarkdownImage("html", explicitTitle, title, content, link, fd); + writeMarkdownImage("latex", explicitTitle, title, content, link, fd); + writeMarkdownImage("rtf", explicitTitle, title, content, link, fd); + writeMarkdownImage("docbook", explicitTitle, title, content, link, fd); } else { - out.addStr("<img src=\""); - out.addStr(link); - out.addStr("\" alt=\""); - out.addStr(content); - out.addStr("\""); + m_out.addStr("<img src=\""); + m_out.addStr(link); + m_out.addStr("\" alt=\""); + m_out.addStr(content); + m_out.addStr("\""); if (!title.isEmpty()) { - out.addStr(" title=\""); - out.addStr(substitute(title.simplifyWhiteSpace(),"\"",""")); - out.addStr("\""); + m_out.addStr(" title=\""); + m_out.addStr(substitute(title.simplifyWhiteSpace(),"\"",""")); + m_out.addStr("\""); } - out.addStr("/>"); + m_out.addStr("/>"); } } else @@ -914,14 +1028,14 @@ static int processLink(GrowBuf &out,const char *data,int,int size) { if (lp==-1) // link to markdown page { - out.addStr("@ref "); + m_out.addStr("@ref "); if (!(Portable::isAbsolutePath(link) || isURL(link))) { QFileInfo forg(link); if (!(forg.exists() && forg.isReadable())) { - QFileInfo fi(g_fileName); - QCString mdFile = g_fileName.left(g_fileName.length()-fi.fileName().length()) + link; + QFileInfo fi(m_fileName); + QCString mdFile = m_fileName.left(m_fileName.length()-fi.fileName().length()) + link; QFileInfo fmd(mdFile); if (fmd.exists() && fmd.isReadable()) { @@ -930,33 +1044,33 @@ static int processLink(GrowBuf &out,const char *data,int,int size) } } } - out.addStr(link); - out.addStr(" \""); + m_out.addStr(link); + m_out.addStr(" \""); if (explicitTitle && !title.isEmpty()) { - out.addStr(title); + m_out.addStr(title); } else { - out.addStr(content); + m_out.addStr(content); } - out.addStr("\""); + m_out.addStr("\""); } else if (link.find('/')!=-1 || link.find('.')!=-1 || link.find('#')!=-1) { // file/url link - out.addStr("<a href=\""); - out.addStr(link); - out.addStr("\""); + m_out.addStr("<a href=\""); + m_out.addStr(link); + m_out.addStr("\""); if (!title.isEmpty()) { - out.addStr(" title=\""); - out.addStr(substitute(title.simplifyWhiteSpace(),"\"",""")); - out.addStr("\""); + m_out.addStr(" title=\""); + m_out.addStr(substitute(title.simplifyWhiteSpace(),"\"",""")); + m_out.addStr("\""); } - out.addStr(">"); + m_out.addStr(">"); content = content.simplifyWhiteSpace(); - processInline(out,content,content.length()); - out.addStr("</a>"); + processInline(content,content.length()); + m_out.addStr("</a>"); } else // avoid link to e.g. F[x](y) { @@ -968,8 +1082,9 @@ static int processLink(GrowBuf &out,const char *data,int,int size) } /** '`' parsing a code span (assuming codespan != 0) */ -static int processCodeSpan(GrowBuf &out, const char *data, int /*offset*/, int size) +int Markdown::processCodeSpan(const char *data, int /*offset*/, int size) { + TRACE(data); int end, nb = 0, i, f_begin, f_end; /* counting the number of backticks in the delimiter */ @@ -996,9 +1111,9 @@ static int processCodeSpan(GrowBuf &out, const char *data, int /*offset*/, int s { // look for quoted strings like 'some word', but skip strings like `it's cool` QCString textFragment; convertStringFragment(textFragment,data+nb,end-nb); - out.addStr("‘"); - out.addStr(textFragment); - out.addStr("’"); + m_out.addStr("‘"); + m_out.addStr(textFragment); + m_out.addStr("’"); return end+1; } else @@ -1034,32 +1149,35 @@ static int processCodeSpan(GrowBuf &out, const char *data, int /*offset*/, int s { QCString codeFragment; convertStringFragment(codeFragment,data+f_begin,f_end-f_begin); - out.addStr("<tt>"); - //out.addStr(convertToHtml(codeFragment,TRUE)); - out.addStr(escapeSpecialChars(codeFragment)); - out.addStr("</tt>"); + m_out.addStr("<tt>"); + //m_out.addStr(convertToHtml(codeFragment,TRUE)); + m_out.addStr(escapeSpecialChars(codeFragment)); + m_out.addStr("</tt>"); } return end; } -static void addStrEscapeUtf8Nbsp(GrowBuf &out,const char *s,int len) +void Markdown::addStrEscapeUtf8Nbsp(const char *s,int len) { + TRACE(s); if (Portable::strnstr(s,g_doxy_nsbp,len)==0) // no escape needed -> fast { - out.addStr(s,len); + m_out.addStr(s,len); } else // escape needed -> slow { - out.addStr(substitute(QCString(s).left(len),g_doxy_nsbp,(const char *)g_utf8_nbsp)); + m_out.addStr(substitute(QCString(s).left(len),g_doxy_nsbp,(const char *)g_utf8_nbsp)); } } -static int processSpecialCommand(GrowBuf &out, const char *data, int offset, int size) +int Markdown::processSpecialCommand(const char *data, int offset, int size) { + TRACE(data); int i=1; QCString endBlockName = isBlockCommand(data,offset,size); if (!endBlockName.isEmpty()) { + TRACE_MORE("endBlockName=%s\n",qPrint(endBlockName)); int l = endBlockName.length(); while (i<size-l) { @@ -1069,7 +1187,8 @@ static int processSpecialCommand(GrowBuf &out, const char *data, int offset, int if (qstrncmp(&data[i+1],endBlockName,l)==0) { //printf("found end at %d\n",i); - addStrEscapeUtf8Nbsp(out,data,i+1+l); + addStrEscapeUtf8Nbsp(data,i+1+l); + TRACE_MORE("result=%d\n",i+1+l); return i+1+l; } } @@ -1081,34 +1200,39 @@ static int processSpecialCommand(GrowBuf &out, const char *data, int offset, int char c=data[1]; if (c=='[' || c==']' || c=='*' || c=='!' || c=='(' || c==')' || c=='`' || c=='_') { - out.addChar(data[1]); + m_out.addChar(data[1]); + TRACE_MORE("result=2\n"); return 2; } else if (c=='-' && size>3 && data[2]=='-' && data[3]=='-') // \--- { - out.addStr(&data[1],3); + m_out.addStr(&data[1],3); + TRACE_MORE("result=4\n"); return 4; } else if (c=='-' && size>2 && data[2]=='-') // \-- { - out.addStr(&data[1],2); + m_out.addStr(&data[1],2); + TRACE_MORE("result=3\n"); return 3; } } + TRACE_MORE("result=0\n"); return 0; } -static void processInline(GrowBuf &out,const char *data,int size) +void Markdown::processInline(const char *data,int size) { + TRACE(data); int i=0, end=0; - action_t action = 0; + Action_t action; while (i<size) { - while (end<size && ((action=g_actions[(uchar)data[end]])==0)) end++; - out.addStr(data+i,end-i); + while (end<size && ((action=m_actions[(uchar)data[end]])==0)) end++; + m_out.addStr(data+i,end-i); if (end>=size) break; i=end; - end = action(out,data+i,i,size-i); + end = action(data+i,i,size-i); if (end<=0) { end=i+1-end; @@ -1122,8 +1246,9 @@ static void processInline(GrowBuf &out,const char *data,int size) } /** returns whether the line is a setext-style hdr underline */ -static int isHeaderline(const char *data, int size, bool allowAdjustLevel) +int Markdown::isHeaderline(const char *data, int size, bool allowAdjustLevel) { + TRACE(data); int i=0, c=0; while (i<size && data[i]==' ') i++; @@ -1133,30 +1258,31 @@ static int isHeaderline(const char *data, int size, bool allowAdjustLevel) while (i<size && data[i]=='=') i++,c++; while (i<size && data[i]==' ') i++; int level = (c>1 && (i>=size || data[i]=='\n')) ? 1 : 0; - if (allowAdjustLevel && level==1 && g_indentLevel==-1) + if (allowAdjustLevel && level==1 && m_indentLevel==-1) { // In case a page starts with a header line we use it as title, promoting it to @page. // We set g_indentLevel to -1 to promoting the other sections if they have a deeper // nesting level than the page header, i.e. @section..@subsection becomes @page..@section. // In case a section at the same level is found (@section..@section) however we need // to undo this (and the result will be @page..@section). - g_indentLevel=0; + m_indentLevel=0; } - return g_indentLevel+level; + return m_indentLevel+level; } // test of level 2 header if (data[i]=='-') { while (i<size && data[i]=='-') i++,c++; while (i<size && data[i]==' ') i++; - return (c>1 && (i>=size || data[i]=='\n')) ? g_indentLevel+2 : 0; + return (c>1 && (i>=size || data[i]=='\n')) ? m_indentLevel+2 : 0; } return 0; } /** returns TRUE if this line starts a block quote */ -static bool isBlockQuote(const char *data,int size,int indent) +bool isBlockQuote(const char *data,int size,int indent) { + TRACE(data); int i = 0; while (i<size && data[i]==' ') i++; if (i<indent+codeBlockIndent) // could be a quotation @@ -1183,6 +1309,7 @@ static bool isBlockQuote(const char *data,int size,int indent) static int isLinkRef(const char *data,int size, QCString &refid,QCString &link,QCString &title) { + TRACE(data); //printf("isLinkRef data={%s}\n",data); // format: start with [some text]: int i = 0; @@ -1272,6 +1399,7 @@ static int isLinkRef(const char *data,int size, static int isHRuler(const char *data,int size) { + TRACE(data); int i=0; if (size>0 && data[size-1]=='\n') size--; // ignore newline character while (i<size && data[i]==' ') i++; @@ -1299,6 +1427,7 @@ static int isHRuler(const char *data,int size) static QCString extractTitleId(QCString &title, int level) { + TRACE(title.data()); //static QRegExp r1("^[a-z_A-Z][a-z_A-Z0-9\\-]*:"); static QRegExp r2("\\{#[a-z_A-Z][a-z_A-Z0-9\\-]*\\}"); int l=0; @@ -1312,7 +1441,7 @@ static QCString extractTitleId(QCString &title, int level) } if ((level > 0) && (level <= Config_getInt(TOC_INCLUDE_HEADINGS))) { - static int autoId = 0; + static AtomicInt autoId { 0 }; QCString id; id.sprintf("autotoc_md%d",autoId++); //printf("auto-generated id='%s' title='%s'\n",id.data(),title.data()); @@ -1323,9 +1452,10 @@ static QCString extractTitleId(QCString &title, int level) } -static int isAtxHeader(const char *data,int size, +int Markdown::isAtxHeader(const char *data,int size, QCString &header,QCString &id,bool allowAdjustLevel) { + TRACE(data); int i = 0, end; int level = 0, blanks=0; @@ -1357,7 +1487,7 @@ static int isAtxHeader(const char *data,int size, header=header.left(i+1); } - if (allowAdjustLevel && level==1 && g_indentLevel==-1) + if (allowAdjustLevel && level==1 && m_indentLevel==-1) { // in case we find a `# Section` on a markdown page that started with the same level // header, we no longer need to artificially decrease the paragraph level. @@ -1377,13 +1507,14 @@ static int isAtxHeader(const char *data,int size, // @section autotoc_md1 Heading 2 // ------------------- - g_indentLevel=0; + m_indentLevel=0; } - return level+g_indentLevel; + return level+m_indentLevel; } static int isEmptyLine(const char *data,int size) { + TRACE(data); int i=0; while (i<size) { @@ -1404,6 +1535,7 @@ static int isEmptyLine(const char *data,int size) // such as -, -#, *, +, 1., and <li> static int computeIndentExcludingListMarkers(const char *data,int size) { + TRACE(data); int i=0; int indent=0; bool isDigit=FALSE; @@ -1472,6 +1604,7 @@ static int computeIndentExcludingListMarkers(const char *data,int size) static bool isFencedCodeBlock(const char *data,int size,int refIndent, QCString &lang,int &start,int &end,int &offset) { + TRACE(data); // rules: at least 3 ~~~, end of the block same amount of ~~~'s, otherwise // return FALSE int i=0; @@ -1499,8 +1632,11 @@ static bool isFencedCodeBlock(const char *data,int size,int refIndent, while (i<size && data[i]==' ') i++; if (i==size || data[i]=='\n') { - offset=i; - return endTildes==startTildes; + if (endTildes==startTildes) + { + offset=i; + return TRUE; + } } } i++; @@ -1510,6 +1646,7 @@ static bool isFencedCodeBlock(const char *data,int size,int refIndent, static bool isCodeBlock(const char *data,int offset,int size,int &indent) { + TRACE(data); //printf("<isCodeBlock(offset=%d,size=%d,indent=%d)\n",offset,size,indent); // determine the indent of this line int i=0; @@ -1586,6 +1723,7 @@ static bool isCodeBlock(const char *data,int offset,int size,int &indent) */ int findTableColumns(const char *data,int size,int &start,int &end,int &columns) { + TRACE(data); int i=0,n=0; int eol; // find start character of the table line @@ -1594,8 +1732,12 @@ int findTableColumns(const char *data,int size,int &start,int &end,int &columns) start = i; // find end character of the table line - while (i<size && data[i]!='\n') i++; - eol=i+1; + //while (i<size && data[i]!='\n') i++; + //eol=i+1; + int j = 0; + while (i<size && (j = isNewline(data + i))==0) i++; + eol=i+j; + i--; while (i>0 && data[i]==' ') i--; if (i>0 && data[i-1]!='\\' && data[i]=='|') i--,n++; // trailing or escaped | does not count @@ -1625,6 +1767,7 @@ int findTableColumns(const char *data,int size,int &start,int &end,int &columns) /** Returns TRUE iff data points to the start of a table block */ static bool isTableBlock(const char *data,int size) { + TRACE(data); int cc0,start,end; // the first line should have at least two columns separated by '|' @@ -1661,8 +1804,9 @@ static bool isTableBlock(const char *data,int size) return cc1==cc2; } -static int writeTableBlock(GrowBuf &out,const char *data,int size) +int Markdown::writeTableBlock(const char *data,int size) { + TRACE(data); int i=0,j,k; int columns,start,end,cc; @@ -1671,17 +1815,10 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) int headerStart = start; int headerEnd = end; -#ifdef USE_ORIGINAL_TABLES - out.addStr("<table>"); - - // write table header, in range [start..end] - out.addStr("<tr>"); -#endif - // read cell alignments int ret = findTableColumns(data+i,size-i,start,end,cc); k=0; - Alignment *columnAlignment = new Alignment[columns]; + std::vector<int> columnAlignment(columns); bool leftMarker=FALSE,rightMarker=FALSE; bool startFound=FALSE; @@ -1718,100 +1855,27 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) // proceed to next line i+=ret; -#ifdef USE_ORIGINAL_TABLES - - int m=headerStart; - for (k=0;k<columns;k++) - { - out.addStr("<th"); - switch (columnAlignment[k]) - { - case AlignLeft: out.addStr(" align=\"left\""); break; - case AlignRight: out.addStr(" align=\"right\""); break; - case AlignCenter: out.addStr(" align=\"center\""); break; - case AlignNone: break; - } - out.addStr(">"); - while (m<=headerEnd && (data[m]!='|' || (m>0 && data[m-1]=='\\'))) - { - out.addChar(data[m++]); - } - m++; - } - out.addStr("\n</th>\n"); - - // write table cells - while (i<size) - { - int ret = findTableColumns(data+i,size-i,start,end,cc); - //printf("findTableColumns cc=%d\n",cc); - if (cc!=columns) break; // end of table - - out.addStr("<tr>"); - j=start+i; - int columnStart=j; - k=0; - while (j<=end+i) - { - if (j==columnStart) - { - out.addStr("<td"); - switch (columnAlignment[k]) - { - case AlignLeft: out.addStr(" align=\"left\""); break; - case AlignRight: out.addStr(" align=\"right\""); break; - case AlignCenter: out.addStr(" align=\"center\""); break; - case AlignNone: break; - } - out.addStr(">"); - } - if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) - { - columnStart=j+1; - k++; - } - else - { - out.addChar(data[j]); - } - j++; - } - out.addChar('\n'); - - // proceed to next line - i+=ret; - } - - out.addStr("</table> "); -#else // Store the table cell information by row then column. This // allows us to handle row spanning. - QVector<QVector<TableCell> > tableContents; - tableContents.setAutoDelete(TRUE); + std::vector<std::vector<TableCell> > tableContents; int m=headerStart; - QVector<TableCell> *headerContents = new QVector<TableCell>(columns); - headerContents->setAutoDelete(TRUE); + std::vector<TableCell> headerContents(columns); for (k=0;k<columns;k++) { - headerContents->insert(k, new TableCell); while (m<=headerEnd && (data[m]!='|' || (m>0 && data[m-1]=='\\'))) { - headerContents->at(k)->cellText += data[m++]; + headerContents[k].cellText += data[m++]; } m++; // do the column span test before stripping white space // || is spanning columns, | | is not - headerContents->at(k)->colSpan = headerContents->at(k)->cellText.isEmpty(); - headerContents->at(k)->cellText = headerContents->at(k)->cellText.stripWhiteSpace(); + headerContents[k].colSpan = headerContents[k].cellText.isEmpty(); + headerContents[k].cellText = headerContents[k].cellText.stripWhiteSpace(); } - // qvector doesn't have an append like std::vector, so we gotta do - // extra work - tableContents.resize(1); - tableContents.insert(0, headerContents); + tableContents.push_back(headerContents); // write table cells - int rowNum = 1; while (i<size) { ret = findTableColumns(data+i,size-i,start,end,cc); @@ -1819,41 +1883,34 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) j=start+i; k=0; - QVector<TableCell> *rowContents = new QVector<TableCell>(columns); - rowContents->setAutoDelete(TRUE); - rowContents->insert(k, new TableCell); + std::vector<TableCell> rowContents(columns); while (j<=end+i) { if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) { // do the column span test before stripping white space // || is spanning columns, | | is not - rowContents->at(k)->colSpan = rowContents->at(k)->cellText.isEmpty(); - rowContents->at(k)->cellText = rowContents->at(k)->cellText.stripWhiteSpace(); + rowContents[k].colSpan = rowContents[k].cellText.isEmpty(); + rowContents[k].cellText = rowContents[k].cellText.stripWhiteSpace(); k++; - rowContents->insert(k, new TableCell); } // if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) else { - rowContents->at(k)->cellText += data[j]; + rowContents[k].cellText += data[j]; } // else { if (j<=end+i && (data[j]=='|' && (j==0 || data[j-1]!='\\'))) } j++; } // while (j<=end+i) // do the column span test before stripping white space // || is spanning columns, | | is not - rowContents->at(k)->colSpan = rowContents->at(k)->cellText.isEmpty(); - rowContents->at(k)->cellText = rowContents->at(k)->cellText.stripWhiteSpace(); - // qvector doesn't have an append like std::vector, so we gotta do - // extra work - tableContents.resize(tableContents.size()+1); - tableContents.insert(rowNum++, rowContents); + rowContents[k].colSpan = rowContents[k].cellText.isEmpty(); + rowContents[k].cellText = rowContents[k].cellText.stripWhiteSpace(); + tableContents.push_back(rowContents); // proceed to next line i+=ret; } - - out.addStr("<table class=\"markdownTable\">"); + m_out.addStr("<table class=\"markdownTable\">"); QCString cellTag("th"), cellClass("class=\"markdownTableHead"); for (unsigned row = 0; row < tableContents.size(); row++) { @@ -1861,58 +1918,57 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) { if (row % 2) { - out.addStr("<tr class=\"markdownTableRowOdd\">"); + m_out.addStr("<tr class=\"markdownTableRowOdd\">"); } else { - out.addStr("<tr class=\"markdownTableRowEven\">"); + m_out.addStr("<tr class=\"markdownTableRowEven\">"); } } else { - out.addStr(" <tr class=\"markdownTableHead\">"); + m_out.addStr(" <tr class=\"markdownTableHead\">"); } for (int c = 0; c < columns; c++) { // save the cell text for use after column span computation - QCString cellText(tableContents[row]->at(c)->cellText); + QCString cellText(tableContents[row][c].cellText); // Row span handling. Spanning rows will contain a caret ('^'). // If the current cell contains just a caret, this is part of an // earlier row's span and the cell should not be added to the // output. - if (tableContents[row]->at(c)->cellText == "^") + if (tableContents[row][c].cellText == "^") continue; unsigned rowSpan = 1, spanRow = row+1; while ((spanRow < tableContents.size()) && - (tableContents[spanRow]->at(c)->cellText == "^")) + (tableContents[spanRow][c].cellText == "^")) { spanRow++; rowSpan++; } - out.addStr(" <" + cellTag + " " + cellClass); + m_out.addStr(" <" + cellTag + " " + cellClass); // use appropriate alignment style switch (columnAlignment[c]) { - case AlignLeft: out.addStr("Left\""); break; - case AlignRight: out.addStr("Right\""); break; - case AlignCenter: out.addStr("Center\""); break; - case AlignNone: out.addStr("None\""); break; + case AlignLeft: m_out.addStr("Left\""); break; + case AlignRight: m_out.addStr("Right\""); break; + case AlignCenter: m_out.addStr("Center\""); break; + case AlignNone: m_out.addStr("None\""); break; } if (rowSpan > 1) { QCString spanStr; spanStr.setNum(rowSpan); - out.addStr(" rowspan=\"" + spanStr + "\""); + m_out.addStr(" rowspan=\"" + spanStr + "\""); } // Column span handling, assumes that column spans will have // empty strings, which would indicate the sequence "||", used // to signify spanning columns. unsigned colSpan = 1; - while ((c < columns-1) && - tableContents[row]->at(c+1)->colSpan) + while ((c < columns-1) && tableContents[row][c+1].colSpan) { c++; colSpan++; @@ -1921,26 +1977,25 @@ static int writeTableBlock(GrowBuf &out,const char *data,int size) { QCString spanStr; spanStr.setNum(colSpan); - out.addStr(" colspan=\"" + spanStr + "\""); + m_out.addStr(" colspan=\"" + spanStr + "\""); } // need at least one space on either side of the cell text in // order for doxygen to do other formatting - out.addStr("> " + cellText + "</" + cellTag + ">"); + m_out.addStr("> " + cellText + "\\ilinebr </" + cellTag + ">"); } cellTag = "td"; cellClass = "class=\"markdownTableBody"; - out.addStr(" </tr>\n"); + m_out.addStr(" </tr>\n"); } - out.addStr("</table>\n"); -#endif + m_out.addStr("</table>\n"); - delete[] columnAlignment; return i; } static int hasLineBreak(const char *data,int size) { + TRACE(data); int i=0; int j=0; // search for end of line and also check if it is not a completely blank @@ -1955,14 +2010,15 @@ static int hasLineBreak(const char *data,int size) } -void writeOneLineHeaderOrRuler(GrowBuf &out,const char *data,int size) +void Markdown::writeOneLineHeaderOrRuler(const char *data,int size) { + TRACE(data); int level; QCString header; QCString id; if (isHRuler(data,size)) { - out.addStr("\n<hr>\n"); + m_out.addStr("\n<hr>\n"); } else if ((level=isAtxHeader(data,size,header,id,TRUE))) { @@ -1971,44 +2027,45 @@ void writeOneLineHeaderOrRuler(GrowBuf &out,const char *data,int size) { switch(level) { - case 1: out.addStr("@section "); + case 1: m_out.addStr("@section "); break; - case 2: out.addStr("@subsection "); + case 2: m_out.addStr("@subsection "); break; - case 3: out.addStr("@subsubsection "); + case 3: m_out.addStr("@subsubsection "); break; - default: out.addStr("@paragraph "); + default: m_out.addStr("@paragraph "); break; } - out.addStr(id); - out.addStr(" "); - out.addStr(header); - out.addStr("\n"); + m_out.addStr(id); + m_out.addStr(" "); + m_out.addStr(header); + m_out.addStr("\n"); } else { if (!id.isEmpty()) { - out.addStr("\\anchor "+id+"\n"); + m_out.addStr("\\anchor "+id+"\n"); } hTag.sprintf("h%d",level); - out.addStr("<"+hTag+">"); - out.addStr(header); - out.addStr("</"+hTag+">\n"); + m_out.addStr("<"+hTag+">"); + m_out.addStr(header); + m_out.addStr("</"+hTag+">\n"); } } else // nothing interesting -> just output the line { - out.addStr(data,size); + m_out.addStr(data,size); if (hasLineBreak(data,size)) { - out.addStr("<br>\n"); + m_out.addStr("<br>\n"); } } } -static int writeBlockQuote(GrowBuf &out,const char *data,int size) +int Markdown::writeBlockQuote(const char *data,int size) { + TRACE(data); int l; int i=0; int curLevel=0; @@ -2038,36 +2095,37 @@ static int writeBlockQuote(GrowBuf &out,const char *data,int size) { for (l=curLevel;l<level;l++) { - out.addStr("<blockquote>\n"); + m_out.addStr("<blockquote>\n"); } } else if (level<curLevel) // quote level decreased => add end markers { for (l=level;l<curLevel;l++) { - out.addStr("</blockquote>\n"); + m_out.addStr("</blockquote>\n"); } } curLevel=level; if (level==0) break; // end of quote block // copy line without quotation marks - out.addStr(data+indent,end-indent); + m_out.addStr(data+indent,end-indent); // proceed with next line i=end; } // end of comment within blockquote => add end markers for (l=0;l<curLevel;l++) { - out.addStr("</blockquote>\n"); + m_out.addStr("</blockquote>\n"); } return i; } -static int writeCodeBlock(GrowBuf &out,const char *data,int size,int refIndent) +int Markdown::writeCodeBlock(const char *data,int size,int refIndent) { + TRACE(data); int i=0,end; //printf("writeCodeBlock: data={%s}\n",QCString(data).left(size).data()); - out.addStr("@verbatim\n"); + m_out.addStr("@verbatim\n"); int emptyLines=0; while (i<size) { @@ -2089,11 +2147,11 @@ static int writeCodeBlock(GrowBuf &out,const char *data,int size,int refIndent) while (emptyLines>0) // write skipped empty lines { // add empty line - out.addStr("\n"); + m_out.addStr("\n"); emptyLines--; } // add code line minus the indent - out.addStr(data+i+refIndent+codeBlockIndent,end-i-refIndent-codeBlockIndent); + m_out.addStr(data+i+refIndent+codeBlockIndent,end-i-refIndent-codeBlockIndent); i=end; } else // end of code block @@ -2101,11 +2159,11 @@ static int writeCodeBlock(GrowBuf &out,const char *data,int size,int refIndent) break; } } - out.addStr("@endverbatim\n"); + m_out.addStr("@endverbatim\n"); while (emptyLines>0) // write skipped empty lines { // add empty line - out.addStr("\n"); + m_out.addStr("\n"); emptyLines--; } //printf("i=%d\n",i); @@ -2114,13 +2172,16 @@ static int writeCodeBlock(GrowBuf &out,const char *data,int size,int refIndent) // start searching for the end of the line start at offset \a i // keeping track of possible blocks that need to be skipped. -static void findEndOfLine(GrowBuf &out,const char *data,int size, +void Markdown::findEndOfLine(const char *data,int size, int &pi,int&i,int &end) { + TRACE(data); // find end of the line int nb=0; end=i+1; - while (end<=size && data[end-1]!='\n') + //while (end<=size && data[end-1]!='\n') + int j=0; + while (end<=size && (j=isNewline(data+end-1))==0) { // while looking for the end of the line we might encounter a block // that needs to be passed unprocessed. @@ -2142,7 +2203,7 @@ static void findEndOfLine(GrowBuf &out,const char *data,int size, if (qstrncmp(&data[end+1],endBlockName,l)==0) { // found end marker, skip over this block - //printf("feol.block out={%s}\n",QCString(data+i).left(end+l+1-i).data()); + //printf("feol.block m_out={%s}\n",QCString(data+i).left(end+l+1-i).data()); end = end + l + 2; break; } @@ -2158,7 +2219,7 @@ static void findEndOfLine(GrowBuf &out,const char *data,int size, tolower(data[end+2])=='e' && data[end+3]=='>') // <pre> tag { // skip part until including </pre> - end = end + processHtmlTagWrite(out,data+end-1,end-1,size-end+1,false) + 2; + end = end + processHtmlTagWrite(data+end-1,end-1,size-end+1,false) + 2; break; } else @@ -2181,27 +2242,30 @@ static void findEndOfLine(GrowBuf &out,const char *data,int size, end++; } } + if (j>0) end+=j-1; //printf("findEndOfLine pi=%d i=%d end=%d {%s}\n",pi,i,end,QCString(data+i).left(end-i).data()); } -static void writeFencedCodeBlock(GrowBuf &out,const char *data,const char *lng, +void Markdown::writeFencedCodeBlock(const char *data,const char *lng, int blockStart,int blockEnd) { + TRACE(data); QCString lang = lng; if (!lang.isEmpty() && lang.at(0)=='.') lang=lang.mid(1); - out.addStr("@code"); + m_out.addStr("@code"); if (!lang.isEmpty()) { - out.addStr("{"+lang+"}"); + m_out.addStr("{"+lang+"}"); } - addStrEscapeUtf8Nbsp(out,data+blockStart,blockEnd-blockStart); - out.addStr("\n"); - out.addStr("@endcode\n"); + addStrEscapeUtf8Nbsp(data+blockStart,blockEnd-blockStart); + m_out.addStr("\n"); + m_out.addStr("@endcode\n"); } -static QCString processQuotations(const QCString &s,int refIndent) +QCString Markdown::processQuotations(const QCString &s,int refIndent) { - GrowBuf out; + TRACE(s.data()); + m_out.clear(); const char *data = s.data(); int size = s.length(); int i=0,end=0,pi=-1; @@ -2209,14 +2273,14 @@ static QCString processQuotations(const QCString &s,int refIndent) QCString lang; while (i<size) { - findEndOfLine(out,data,size,pi,i,end); + findEndOfLine(data,size,pi,i,end); // line is now found at [i..end) if (pi!=-1) { if (isFencedCodeBlock(data+pi,size-pi,refIndent,lang,blockStart,blockEnd,blockOffset)) { - writeFencedCodeBlock(out,data+pi,lang,blockStart,blockEnd); + writeFencedCodeBlock(data+pi,lang,blockStart,blockEnd); i=pi+blockOffset; pi=-1; end=i+1; @@ -2224,15 +2288,15 @@ static QCString processQuotations(const QCString &s,int refIndent) } else if (isBlockQuote(data+pi,i-pi,refIndent)) { - i = pi+writeBlockQuote(out,data+pi,size-pi); + i = pi+writeBlockQuote(data+pi,size-pi); pi=-1; end=i+1; continue; } else { - //printf("quote out={%s}\n",QCString(data+pi).left(i-pi).data()); - out.addStr(data+pi,i-pi); + //printf("quote m_out={%s}\n",QCString(data+pi).left(i-pi).data()); + m_out.addStr(data+pi,i-pi); } } pi=i; @@ -2242,24 +2306,25 @@ static QCString processQuotations(const QCString &s,int refIndent) { if (isBlockQuote(data+pi,size-pi,refIndent)) { - writeBlockQuote(out,data+pi,size-pi); + writeBlockQuote(data+pi,size-pi); } else { - out.addStr(data+pi,size-pi); + m_out.addStr(data+pi,size-pi); } } - out.addChar(0); + m_out.addChar(0); //printf("Process quotations\n---- input ----\n%s\n---- output ----\n%s\n------------\n", - // s.data(),out.get()); + // s.data(),m_out.get()); - return out.get(); + return m_out.get(); } -static QCString processBlocks(const QCString &s,int indent) +QCString Markdown::processBlocks(const QCString &s,int indent) { - GrowBuf out; + TRACE(s.data()); + m_out.clear(); const char *data = s.data(); int size = s.length(); int i=0,end=0,pi=-1,ref,level; @@ -2275,14 +2340,14 @@ static QCString processBlocks(const QCString &s,int indent) end++; } -#if 0 // commented out, since starting with a comment block is probably a usage error +#if 0 // commented m_out, since starting with a comment block is probably a usage error // see also http://stackoverflow.com/q/20478611/784672 // special case when the documentation starts with a code block // since the first line is skipped when looking for a code block later on. if (end>codeBlockIndent && isCodeBlock(data,0,end,blockIndent)) { - i=writeCodeBlock(out,data,size,blockIndent); + i=writeCodeBlock(m_out,data,size,blockIndent); end=i+1; pi=-1; } @@ -2291,7 +2356,7 @@ static QCString processBlocks(const QCString &s,int indent) // process each line while (i<size) { - findEndOfLine(out,data,size,pi,i,end); + findEndOfLine(data,size,pi,i,end); // line is now found at [i..end) //printf("findEndOfLine: pi=%d i=%d end=%d\n",pi,i,end); @@ -2314,22 +2379,22 @@ static QCString processBlocks(const QCString &s,int indent) { if (!id.isEmpty()) { - out.addStr(level==1?"@section ":"@subsection "); - out.addStr(id); - out.addStr(" "); - out.addStr(header); - out.addStr("\n\n"); + m_out.addStr(level==1?"@section ":"@subsection "); + m_out.addStr(id); + m_out.addStr(" "); + m_out.addStr(header); + m_out.addStr("\n\n"); } else { - out.addStr(level==1?"<h1>":"<h2>"); - out.addStr(header); - out.addStr(level==1?"\n</h1>\n":"\n</h2>\n"); + m_out.addStr(level==1?"<h1>":"<h2>"); + m_out.addStr(header); + m_out.addStr(level==1?"\n</h1>\n":"\n</h2>\n"); } } else { - out.addStr("\n<hr>\n"); + m_out.addStr("\n<hr>\n"); } pi=-1; i=end; @@ -2340,7 +2405,7 @@ static QCString processBlocks(const QCString &s,int indent) { //printf("found link ref: id='%s' link='%s' title='%s'\n", // id.data(),link.data(),title.data()); - g_linkRefs.insert(id.lower(),new LinkRef(link,title)); + m_linkRefs.insert({id.lower().str(),LinkRef(link,title)}); i=ref+pi; pi=-1; end=i+1; @@ -2349,7 +2414,7 @@ static QCString processBlocks(const QCString &s,int indent) { //printf("Found FencedCodeBlock lang='%s' start=%d end=%d code={%s}\n", // lang.data(),blockStart,blockEnd,QCString(data+pi+blockStart).left(blockEnd-blockStart).data()); - writeFencedCodeBlock(out,data+pi,lang,blockStart,blockEnd); + writeFencedCodeBlock(data+pi,lang,blockStart,blockEnd); i=pi+blockOffset; pi=-1; end=i+1; @@ -2358,21 +2423,21 @@ static QCString processBlocks(const QCString &s,int indent) else if (isCodeBlock(data+i,i,end-i,blockIndent)) { // skip previous line (it is empty anyway) - i+=writeCodeBlock(out,data+i,size-i,blockIndent); + i+=writeCodeBlock(data+i,size-i,blockIndent); pi=-1; end=i+1; continue; } else if (isTableBlock(data+pi,size-pi)) { - i=pi+writeTableBlock(out,data+pi,size-pi); + i=pi+writeTableBlock(data+pi,size-pi); pi=-1; end=i+1; continue; } else { - writeOneLineHeaderOrRuler(out,data+pi,i-pi); + writeOneLineHeaderOrRuler(data+pi,i-pi); } } pi=i; @@ -2385,21 +2450,22 @@ static QCString processBlocks(const QCString &s,int indent) { //printf("found link ref: id='%s' link='%s' title='%s'\n", // id.data(),link.data(),title.data()); - g_linkRefs.insert(id.lower(),new LinkRef(link,title)); + m_linkRefs.insert({id.lower().str(),LinkRef(link,title)}); } else { - writeOneLineHeaderOrRuler(out,data+pi,size-pi); + writeOneLineHeaderOrRuler(data+pi,size-pi); } } - out.addChar(0); - return out.get(); + m_out.addChar(0); + return m_out.get(); } /** returns TRUE if input string docs starts with \@page or \@mainpage command */ static bool isExplicitPage(const QCString &docs) { + TRACE(docs.data()); int i=0; const char *data = docs.data(); if (data) @@ -2420,8 +2486,9 @@ static bool isExplicitPage(const QCString &docs) return FALSE; } -static QCString extractPageTitle(QCString &docs,QCString &id) +QCString Markdown::extractPageTitle(QCString &docs,QCString &id) { + TRACE(docs.data()); int ln=0; // first first non-empty line QCString title; @@ -2467,11 +2534,13 @@ static QCString extractPageTitle(QCString &docs,QCString &id) return title; } -static QCString detab(const QCString &s,int &refIndent) +QCString Markdown::detab(const QCString &s,int &refIndent) { - static int tabSize = Config_getInt(TAB_SIZE); + TRACE(s.data()); + int tabSize = Config_getInt(TAB_SIZE); int size = s.length(); - GrowBuf out(size); + m_out.clear(); + m_out.reserve(size); const char *data = s.data(); int i=0; int col=0; @@ -2487,15 +2556,15 @@ static QCString detab(const QCString &s,int &refIndent) int stop = tabSize - (col%tabSize); //printf("expand at %d stop=%d\n",col,stop); col+=stop; - while (stop--) out.addChar(' '); + while (stop--) m_out.addChar(' '); } break; case '\n': // reset column counter - out.addChar(c); + m_out.addChar(c); col=0; break; case ' ': // increment column counter - out.addChar(c); + m_out.addChar(c); col++; break; default: // non-whitespace => update minIndent @@ -2504,90 +2573,86 @@ static QCString detab(const QCString &s,int &refIndent) // special handling of the UTF-8 nbsp character 0xC2 0xA0 if ((uchar)c == 0xC2 && (uchar)(data[i]) == 0xA0) { - out.addStr(g_doxy_nsbp); + m_out.addStr(g_doxy_nsbp); i++; } else { - out.addChar(c); - out.addChar(data[i++]); // >= 2 bytes + m_out.addChar(c); + m_out.addChar(data[i++]); // >= 2 bytes if (((uchar)c&0xE0)==0xE0 && i<size) { - out.addChar(data[i++]); // 3 bytes + m_out.addChar(data[i++]); // 3 bytes } if (((uchar)c&0xF0)==0xF0 && i<size) { - out.addChar(data[i++]); // 4 byres + m_out.addChar(data[i++]); // 4 byres } } } else { - out.addChar(c); + m_out.addChar(c); } if (col<minIndent) minIndent=col; col++; } } if (minIndent!=maxIndent) refIndent=minIndent; else refIndent=0; - out.addChar(0); + m_out.addChar(0); //printf("detab refIndent=%d\n",refIndent); - return out.get(); + return m_out.get(); } //--------------------------------------------------------------------------- -QCString processMarkdown(const QCString &fileName,const int lineNr,Entry *e,const QCString &input) +QCString Markdown::process(const QCString &input, int &startNewlines) { - static bool init=FALSE; - if (!init) - { - // setup callback table for special characters - g_actions[(unsigned int)'_']=processEmphasis; - g_actions[(unsigned int)'*']=processEmphasis; - g_actions[(unsigned int)'~']=processEmphasis; - g_actions[(unsigned int)'`']=processCodeSpan; - g_actions[(unsigned int)'\\']=processSpecialCommand; - g_actions[(unsigned int)'@']=processSpecialCommand; - g_actions[(unsigned int)'[']=processLink; - g_actions[(unsigned int)'!']=processLink; - g_actions[(unsigned int)'<']=processHtmlTag; - g_actions[(unsigned int)'-']=processNmdash; - g_actions[(unsigned int)'"']=processQuoted; - init=TRUE; - } - - g_linkRefs.setAutoDelete(TRUE); - g_linkRefs.clear(); - g_current = e; - g_fileName = fileName; - g_lineNr = lineNr; - static GrowBuf out; if (input.isEmpty()) return input; - out.clear(); int refIndent; + // for replace tabs by spaces QCString s = input; if (s.at(s.length()-1)!='\n') s += "\n"; // see PR #6766 s = detab(s,refIndent); //printf("======== DeTab =========\n---- output -----\n%s\n---------\n",s.data()); + // then process quotation blocks (as these may contain other blocks) s = processQuotations(s,refIndent); //printf("======== Quotations =========\n---- output -----\n%s\n---------\n",s.data()); + // then process block items (headers, rules, and code blocks, references) s = processBlocks(s,refIndent); //printf("======== Blocks =========\n---- output -----\n%s\n---------\n",s.data()); + // finally process the inline markup (links, emphasis and code spans) - processInline(out,s,s.length()); - out.addChar(0); - Debug::print(Debug::Markdown,0,"======== Markdown =========\n---- input ------- \n%s\n---- output -----\n%s\n=========\n",qPrint(input),qPrint(out.get())); - return substitute(out.get(),g_doxy_nsbp," "); + m_out.clear(); + processInline(s,s.length()); + m_out.addChar(0); + Debug::print(Debug::Markdown,0,"======== Markdown =========\n---- input ------- \n%s\n---- output -----\n%s\n=========\n",qPrint(input),qPrint(m_out.get())); + + // post processing + QCString result = substitute(m_out.get(),g_doxy_nsbp," "); + const char *p = result.data(); + if (p) + { + while (*p==' ') p++; // skip over spaces + while (*p=='\n') {startNewlines++;p++;}; // skip over newlines + if (qstrncmp(p,"<br>",4)==0) p+=4; // skip over <br> + } + if (p>result.data()) + { + // strip part of the input + result = result.mid(p-result.data()); + } + return result; } //--------------------------------------------------------------------------- QCString markdownFileNameToId(const QCString &fileName) { + TRACE(fileName.data()); QCString baseFn = stripFromPath(QFileInfo(fileName).absFilePath().utf8()); int i = baseFn.findRev('.'); if (i!=-1) baseFn = baseFn.left(i); @@ -2597,35 +2662,6 @@ QCString markdownFileNameToId(const QCString &fileName) //--------------------------------------------------------------------------- -QCString processMarkdownForCommentBlock(const QCString &comment, - const QCString &fileName, - int lineNr) -{ - if (!comment.isEmpty() && Doxygen::markdownSupport) - { - QCString result = processMarkdown(fileName,lineNr,0,comment); - const char *p = result.data(); - if (p) - { - while (*p==' ') p++; // skip over spaces - while (*p=='\n') p++; // skip over newlines - if (qstrncmp(p,"<br>",4)==0) p+=4; // skip over <br> - } - if (p>result.data()) - { - // strip part of the input - result = result.mid(p-result.data()); - } - return result; - } - else - { - return comment; - } -} - -//--------------------------------------------------------------------------- - struct MarkdownOutlineParser::Private { CommentScanner commentScanner; @@ -2642,8 +2678,7 @@ MarkdownOutlineParser::~MarkdownOutlineParser() void MarkdownOutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool /*sameTranslationUnit*/, - QStrList & /*filesInSameTranslationUnit*/) + ClangTUParser* /*clangParser*/) { std::shared_ptr<Entry> current = std::make_shared<Entry>(); current->lang = SrcLangExt_Markdown; @@ -2652,12 +2687,14 @@ void MarkdownOutlineParser::parseInput(const char *fileName, current->docLine = 1; QCString docs = fileBuf; QCString id; - QCString title=extractPageTitle(docs,id).stripWhiteSpace(); + Markdown markdown(fileName,1,0); + QCString title=markdown.extractPageTitle(docs,id).stripWhiteSpace(); if (id.startsWith("autotoc_md")) id = ""; - g_indentLevel=title.isEmpty() ? 0 : -1; + int indentLevel=title.isEmpty() ? 0 : -1; + markdown.setIndentLevel(indentLevel); QCString titleFn = QFileInfo(fileName).baseName().utf8(); QCString fn = QFileInfo(fileName).fileName().utf8(); - static QCString mdfileAsMainPage = Config_getString(USE_MDFILE_AS_MAINPAGE); + QCString mdfileAsMainPage = Config_getString(USE_MDFILE_AS_MAINPAGE); bool wasEmpty = id.isEmpty(); if (wasEmpty) id = markdownFileNameToId(fileName); if (!isExplicitPage(docs)) @@ -2686,15 +2723,12 @@ void MarkdownOutlineParser::parseInput(const char *fileName, } int lineNr=1; - // even without markdown support enabled, we still - // parse markdown files as such - bool markdownEnabled = Doxygen::markdownSupport; - Doxygen::markdownSupport = TRUE; - Protection prot=Public; bool needsEntry = FALSE; int position=0; - QCString processedDocs = processMarkdownForCommentBlock(docs,fileName,lineNr); + int startNewlines; + QCString processedDocs = markdown.process(docs,startNewlines); + lineNr += startNewlines; while (p->commentScanner.parseCommentBlock( this, current.get(), @@ -2706,7 +2740,8 @@ void MarkdownOutlineParser::parseInput(const char *fileName, FALSE, // inBodyDocs prot, // protection position, - needsEntry)) + needsEntry, + true)) { if (needsEntry) { @@ -2721,19 +2756,11 @@ void MarkdownOutlineParser::parseInput(const char *fileName, { root->moveToSubEntryAndKeep(current); } - - // restore setting - Doxygen::markdownSupport = markdownEnabled; - g_indentLevel=0; } void MarkdownOutlineParser::parsePrototype(const char *text) { - OutlineParserInterface &intf = Doxygen::parserManager->getOutlineParser("*.cpp"); - if (&intf!=this) - { - intf.parsePrototype(text); - } + Doxygen::parserManager->getOutlineParser("*.cpp")->parsePrototype(text); } //------------------------------------------------------------------------ diff --git a/src/markdown.h b/src/markdown.h index bc1e9bb..1210967 100644 --- a/src/markdown.h +++ b/src/markdown.h @@ -3,8 +3,8 @@ * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -16,39 +16,87 @@ #ifndef MARKDOWN_H #define MARKDOWN_H +#include <functional> + #include <qcstring.h> #include "parserintf.h" +#include "growbuf.h" class Entry; /** processes string \a s and converts markdown into doxygen/html commands. */ -QCString processMarkdown(const QCString &fileName,const int lineNr,Entry *e,const QCString &s); +//QCString processMarkdown(const QCString &fileName,const int lineNr,Entry *e,const QCString &s); QCString markdownFileNameToId(const QCString &fileName); -/** Performs markdown processing for a comment block if markdown processing is enabled. - * @param[in] comment A string representing the actual comment block. - * Note that leading *'s should already be stripped from the comment block. - * @param[in] fileName The name of the file in which the comment is found. - * Mainly used for producing warnings. - * @param[in] lineNr The line number at which the comment block was found. - * @returns The processed comment block - */ -QCString processMarkdownForCommentBlock(const QCString &comment, - const QCString &fileName, - int lineNr); +/// Helper class to process markdown formatted text +class Markdown +{ + public: + Markdown(const char *fileName,int lineNr,int indentLevel=0); + QCString process(const QCString &input, int &startNewlines); + QCString extractPageTitle(QCString &docs,QCString &id); + void setIndentLevel(int level) { m_indentLevel = level; } + + private: + QCString detab(const QCString &s,int &refIndent); + QCString processQuotations(const QCString &s,int refIndent); + QCString processBlocks(const QCString &s,int indent); + QCString isBlockCommand(const char *data,int offset,int size); + void findEndOfLine(const char *data,int size,int &pi,int&i,int &end); + int processHtmlTagWrite(const char *data,int offset,int size,bool doWrite); + int processHtmlTag(const char *data,int offset,int size); + int processEmphasis(const char *data,int offset,int size); + int processEmphasis1(const char *data, int size, char c); + int processEmphasis2(const char *data, int size, char c); + int processEmphasis3(const char *data, int size, char c); + int processNmdash(const char *data,int off,int size); + int processQuoted(const char *data,int,int size); + int processCodeSpan(const char *data, int /*offset*/, int size); + void addStrEscapeUtf8Nbsp(const char *s,int len); + int processSpecialCommand(const char *data, int offset, int size); + int processLink(const char *data,int,int size); + int findEmphasisChar(const char *data, int size, char c, int c_size); + void processInline(const char *data,int size); + void writeMarkdownImage(const char *fmt, bool explicitTitle, + const QCString &title, const QCString &content, + const QCString &link, const FileDef *fd); + int isHeaderline(const char *data, int size, bool allowAdjustLevel); + int isAtxHeader(const char *data,int size, + QCString &header,QCString &id,bool allowAdjustLevel); + void writeOneLineHeaderOrRuler(const char *data,int size); + void writeFencedCodeBlock(const char *data,const char *lng, + int blockStart,int blockEnd); + int writeBlockQuote(const char *data,int size); + int writeCodeBlock(const char *data,int size,int refIndent); + int writeTableBlock(const char *data,int size); + + private: + struct LinkRef + { + LinkRef(const char *l,const char *t) : link(l), title(t) {} + QCString link; + QCString title; + }; + using Action_t = std::function<int(const char *,int,int)>; + + std::unordered_map<std::string,LinkRef> m_linkRefs; + QCString m_fileName; + int m_lineNr = 0; + int m_indentLevel=0; // 0 is outside markdown, -1=page level + GrowBuf m_out; + Markdown::Action_t m_actions[256]; +}; + class MarkdownOutlineParser : public OutlineParserInterface { public: MarkdownOutlineParser(); virtual ~MarkdownOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} - void parseInput(const char *fileName, - const char *fileBuf, + void parseInput(const char *fileName, + const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &) const { return FALSE; } void parsePrototype(const char *text); private: diff --git a/src/memberdef.cpp b/src/memberdef.cpp index d857fa6..7645a01 100644 --- a/src/memberdef.cpp +++ b/src/memberdef.cpp @@ -2606,8 +2606,8 @@ void MemberDefImpl::writeDeclaration(OutputList &ol, ) { DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(), - getOuterScope()?getOuterScope():d,this,briefDescription(), - TRUE,FALSE,0,TRUE,FALSE); + getOuterScope()?getOuterScope():d,this,briefDescription(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (rootNode && !rootNode->isEmpty()) { @@ -2733,7 +2733,7 @@ void MemberDefImpl::getLabels(QStrList &sl,const Definition *container) const isFriend() || isRelated() || (isInline() && inlineInfo) || isSignal() || isSlot() || - isStatic() || + isStatic() || isExternal() || (getClassDef() && getClassDef()!=container && container->definitionType()==TypeClass) || (m_impl->memSpec & ~Entry::Inline)!=0 ) @@ -2745,7 +2745,7 @@ void MemberDefImpl::getLabels(QStrList &sl,const Definition *container) const //ol.docify(" ["); SrcLangExt lang = getLanguage(); bool optVhdl = lang==SrcLangExt_VHDL; - bool extractPrivate = Config_getBool(EXTRACT_PRIVATE); + static bool extractPrivate = Config_getBool(EXTRACT_PRIVATE); if (optVhdl) { sl.append(theTranslator->trVhdlType(getMemberSpecifiers(),TRUE)); @@ -2756,7 +2756,8 @@ void MemberDefImpl::getLabels(QStrList &sl,const Definition *container) const else if (isRelated()) sl.append("related"); else { - if (Config_getBool(INLINE_INFO) && isInline()) sl.append("inline"); + if (isExternal()) sl.append("extern"); + if (inlineInfo && isInline()) sl.append("inline"); if (isExplicit()) sl.append("explicit"); if (isMutable()) sl.append("mutable"); if (isStatic()) sl.append("static"); @@ -3146,7 +3147,8 @@ void MemberDefImpl::_writeEnumValues(OutputList &ol,const Definition *container, { ol.generateDoc(fmd->briefFile(),fmd->briefLine(), getOuterScope()?getOuterScope():container, - fmd,fmd->briefDescription(),TRUE,FALSE); + fmd,fmd->briefDescription(),TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } // FIXME:PARA //if (!fmd->briefDescription().isEmpty() && @@ -3158,7 +3160,8 @@ void MemberDefImpl::_writeEnumValues(OutputList &ol,const Definition *container, { ol.generateDoc(fmd->docFile(),fmd->docLine(), getOuterScope()?getOuterScope():container, - fmd,fmd->documentation()+"\n",TRUE,FALSE); + fmd,fmd->documentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } ol.endDescTableData(); ol.endDescTableRow(); @@ -3706,7 +3709,8 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml, ol.startParagraph(); ol.generateDoc(briefFile(),briefLine(), scopedContainer,this, - brief,FALSE,FALSE,0,TRUE,FALSE); + brief,FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endParagraph(); } @@ -3722,14 +3726,16 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml, } else { - ol.generateDoc(docFile(),docLine(),scopedContainer,this,detailed+"\n",TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),scopedContainer,this,detailed+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } if (!inbodyDocumentation().isEmpty()) { ol.generateDoc(inbodyFile(),inbodyLine(), - scopedContainer,this, - inbodyDocumentation()+"\n",TRUE,FALSE); + scopedContainer,this, + inbodyDocumentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } } else if (!brief.isEmpty() && (Config_getBool(REPEAT_BRIEF) || @@ -3737,7 +3743,8 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml, { if (!inbodyDocumentation().isEmpty()) { - ol.generateDoc(inbodyFile(),inbodyLine(),scopedContainer,this,inbodyDocumentation()+"\n",TRUE,FALSE); + ol.generateDoc(inbodyFile(),inbodyLine(),scopedContainer,this,inbodyDocumentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } } @@ -3754,7 +3761,7 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml, { QCString docsWithoutDir = a.docs; QCString direction = extractDirection(docsWithoutDir); - paramDocs+="@param"+direction+" "+a.name+" "+a.docs; + paramDocs+="@param"+direction+" "+a.name+" "+docsWithoutDir; } } // feed the result to the documentation parser @@ -3764,7 +3771,8 @@ void MemberDefImpl::writeDocumentation(const MemberList *ml, this, // memberDef paramDocs, // docStr TRUE, // indexWords - FALSE // isExample + FALSE, // isExample + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT) ); } @@ -3958,7 +3966,8 @@ void MemberDefImpl::writeMemberDocSimple(OutputList &ol, const Definition *conta { ol.generateDoc(briefFile(),briefLine(), getOuterScope()?getOuterScope():container,this, - brief,FALSE,FALSE,0,TRUE,FALSE); + brief,FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } /* write detailed description */ @@ -3966,7 +3975,8 @@ void MemberDefImpl::writeMemberDocSimple(OutputList &ol, const Definition *conta { ol.generateDoc(docFile(),docLine(), getOuterScope()?getOuterScope():container,this, - detailed+"\n",FALSE,FALSE,0,FALSE,FALSE); + detailed+"\n",FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } @@ -4157,6 +4167,7 @@ void MemberDefImpl::warnIfUndocumentedParams() const if (!Config_getBool(EXTRACT_ALL) && Config_getBool(WARN_IF_UNDOCUMENTED) && Config_getBool(WARN_NO_PARAMDOC) && + isFunction() && !isDeleted() && !isReference() && !Doxygen::suppressDocWarnings) @@ -4169,7 +4180,7 @@ void MemberDefImpl::warnIfUndocumentedParams() const qPrint(qualifiedName())); } if (!m_impl->hasDocumentedReturnType && - isFunction() && hasDocumentation() && !returnType.isEmpty()) + hasDocumentation() && !returnType.isEmpty()) { warn_doc_error(getDefFileName(),getDefLine(), "return type of member %s is not documented", diff --git a/src/memberlist.cpp b/src/memberlist.cpp index b5377a4..b8e5e89 100644 --- a/src/memberlist.cpp +++ b/src/memberlist.cpp @@ -517,7 +517,8 @@ void MemberList::writePlainDeclarations(OutputList &ol, md->briefFile(),md->briefLine(), cd,md, md->briefDescription(), - TRUE,FALSE,0,TRUE,FALSE + TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT) ); if (rootNode && !rootNode->isEmpty()) { @@ -684,7 +685,8 @@ void MemberList::writeDeclarations(OutputList &ol, if (!st.isEmpty()) { ol.startMemberSubtitle(); - ol.generateDoc("[generated]",-1,ctx,0,subtitle,FALSE,FALSE,0,FALSE,FALSE); + ol.generateDoc("[generated]",-1,ctx,0,subtitle,FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberSubtitle(); } } @@ -727,7 +729,8 @@ void MemberList::writeDeclarations(OutputList &ol, { //printf("Member group has docs!\n"); ol.startMemberGroupDocs(); - ol.generateDoc(mg->docFile(),mg->docLine(),ctx,0,mg->documentation()+"\n",FALSE,FALSE); + ol.generateDoc(mg->docFile(),mg->docLine(),ctx,0,mg->documentation()+"\n",FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberGroupDocs(); } ol.startMemberGroup(); diff --git a/src/message.cpp b/src/message.cpp index a787357..96c54a1 100644 --- a/src/message.cpp +++ b/src/message.cpp @@ -18,6 +18,9 @@ #include "debug.h" #include "portable.h" #include "message.h" +#include "doxygen.h" + +#include <mutex> static QCString outputFormat; static const char *warning_str = "warning: "; @@ -31,6 +34,11 @@ static const char *error_str = "error: "; static FILE *warnFile = stderr; + +#if MULTITHREADED_INPUT +static std::mutex g_mutex; +#endif + void initWarningFormat() { // int filePos = Config_getString(WARN_FORMAT).find("$file"); @@ -104,9 +112,12 @@ void msg(const char *fmt, ...) { if (!Config_getBool(QUIET)) { +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_mutex); +#endif if (Debug::isFlagSet(Debug::Time)) { - printf("%.3f sec: ",((double)Debug::elapsedTime())/1000.0); + printf("%.3f sec: ",((double)Debug::elapsedTime())); } va_list args; va_start(args, fmt); @@ -143,8 +154,13 @@ static void format_warn(const char *file,int line,const char *text) } msgText += '\n'; - // print resulting message - fwrite(msgText.data(),1,msgText.length(),warnFile); + { +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_mutex); +#endif + // print resulting message + fwrite(msgText.data(),1,msgText.length(),warnFile); + } if (warnAsError) { exit(1); @@ -240,14 +256,19 @@ extern void err_full(const char *file,int line,const char *fmt, ...) void term(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vfprintf(warnFile, (QCString(error_str) + fmt).data(), args); - va_end(args); - if (warnFile != stderr) { - for (int i = 0; i < (int)strlen(error_str); i++) fprintf(warnFile, " "); - fprintf(warnFile, "%s\n", "Exiting..."); +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_mutex); +#endif + va_list args; + va_start(args, fmt); + vfprintf(warnFile, (QCString(error_str) + fmt).data(), args); + va_end(args); + if (warnFile != stderr) + { + for (int i = 0; i < (int)strlen(error_str); i++) fprintf(warnFile, " "); + fprintf(warnFile, "%s\n", "Exiting..."); + } } exit(1); } @@ -263,6 +284,9 @@ void printlex(int dbg, bool enter, const char *lexName, const char *fileName) enter_txt_uc = "Finished"; } +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_mutex); +#endif if (dbg) { if (fileName) diff --git a/src/namespacedef.cpp b/src/namespacedef.cpp index 51454e0..6e0b45c 100644 --- a/src/namespacedef.cpp +++ b/src/namespacedef.cpp @@ -698,7 +698,8 @@ void NamespaceDefImpl::writeDetailedDescription(OutputList &ol,const QCString &t ol.startTextBlock(); if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF)) { - ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE); + ol.generateDoc(briefFile(),briefLine(),this,0,briefDescription(),FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } if (!briefDescription().isEmpty() && Config_getBool(REPEAT_BRIEF) && !documentation().isEmpty()) @@ -715,7 +716,8 @@ void NamespaceDefImpl::writeDetailedDescription(OutputList &ol,const QCString &t } if (!documentation().isEmpty()) { - ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,documentation()+"\n",TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); } ol.endTextBlock(); } @@ -726,7 +728,8 @@ void NamespaceDefImpl::writeBriefDescription(OutputList &ol) if (hasBriefDescription()) { DocRoot *rootNode = validatingParseDoc(briefFile(),briefLine(),this,0, - briefDescription(),TRUE,FALSE,0,TRUE,FALSE); + briefDescription(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (rootNode && !rootNode->isEmpty()) { ol.startParagraph(); @@ -1440,7 +1443,8 @@ void NamespaceSDict::writeDeclaration(OutputList &ol,const char *title, if (!nd->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC)) { ol.startMemberDescription(nd->getOutputFileBase()); - ol.generateDoc(nd->briefFile(),nd->briefLine(),nd,0,nd->briefDescription(),FALSE,FALSE,0,TRUE); + ol.generateDoc(nd->briefFile(),nd->briefLine(),nd,0,nd->briefDescription(),FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberDescription(); } ol.endMemberDeclaration(0,0); diff --git a/src/outputlist.cpp b/src/outputlist.cpp index 07d6491..e942465 100644 --- a/src/outputlist.cpp +++ b/src/outputlist.cpp @@ -115,7 +115,8 @@ void OutputList::generateDoc(const char *fileName,int startLine, const Definition *ctx,const MemberDef * md, const QCString &docStr,bool indexWords, bool isExample,const char *exampleName, - bool singleLine,bool linkFromIndex) + bool singleLine,bool linkFromIndex, + bool markdownSupport) { int count=0; if (docStr.isEmpty()) return; @@ -132,7 +133,7 @@ void OutputList::generateDoc(const char *fileName,int startLine, DocRoot *root=0; root = validatingParseDoc(fileName,startLine, ctx,md,docStr,indexWords,isExample,exampleName, - singleLine,linkFromIndex); + singleLine,linkFromIndex,markdownSupport); if (count>0) writeDoc(root,ctx,md); delete root; } diff --git a/src/outputlist.h b/src/outputlist.h index 58e4425..9393a59 100644 --- a/src/outputlist.h +++ b/src/outputlist.h @@ -59,8 +59,9 @@ class OutputList : public OutputDocInterface void generateDoc(const char *fileName,int startLine, const Definition *ctx,const MemberDef *md,const QCString &docStr, - bool indexWords,bool isExample,const char *exampleName=0, - bool singleLine=FALSE,bool linkFromIndex=FALSE); + bool indexWords,bool isExample,const char *exampleName /*=0*/, + bool singleLine /*=FALSE*/,bool linkFromIndex /*=FALSE*/, + bool markdownSupport /*=FALSE*/); void writeDoc(DocRoot *root,const Definition *ctx,const MemberDef *md); void parseText(const QCString &textStr); diff --git a/src/pagedef.cpp b/src/pagedef.cpp index 011b647..09152de 100644 --- a/src/pagedef.cpp +++ b/src/pagedef.cpp @@ -3,8 +3,8 @@ * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -102,18 +102,18 @@ void PageDefImpl::findSectionsInDocumentation() docFindSections(documentation(),this,docFile()); } -GroupDef *PageDefImpl::getGroupDef() const -{ +GroupDef *PageDefImpl::getGroupDef() const +{ GroupList *groups = partOfGroups(); - return groups!=0 ? groups->getFirst() : 0; + return groups!=0 ? groups->getFirst() : 0; } -QCString PageDefImpl::getOutputFileBase() const -{ - if (getGroupDef()) +QCString PageDefImpl::getOutputFileBase() const +{ + if (getGroupDef()) return getGroupDef()->getOutputFileBase(); - else - return m_fileName; + else + return m_fileName; } void PageDefImpl::setFileName(const char *name) @@ -142,7 +142,7 @@ void PageDefImpl::addInnerCompound(const Definition *const_def) bool PageDefImpl::hasParentPage() const { - return getOuterScope() && + return getOuterScope() && getOuterScope()->definitionType()==Definition::TypePage; } @@ -180,9 +180,9 @@ void PageDefImpl::writeDocumentation(OutputList &ol) //printf("PageDefImpl::writeDocumentation: %s\n",getOutputFileBase().data()); ol.pushGeneratorState(); - //1.{ + //1.{ - if (m_nestingLevel>0 + if (m_nestingLevel>0 //&& // a sub page //(Doxygen::mainPage==0 || getOuterScope()!=Doxygen::mainPage) // and not a subpage of the mainpage ) @@ -195,14 +195,14 @@ void PageDefImpl::writeDocumentation(OutputList &ol) } ol.pushGeneratorState(); - //2.{ + //2.{ ol.disableAllBut(OutputGenerator::Man); startFile(ol,getOutputFileBase(),manPageName,title(),HLI_Pages,!generateTreeView); ol.enableAll(); ol.disable(OutputGenerator::Man); startFile(ol,getOutputFileBase(),pageName,title(),HLI_Pages,!generateTreeView); ol.popGeneratorState(); - //2.} + //2.} if (!generateTreeView) { @@ -229,7 +229,8 @@ void PageDefImpl::writeDocumentation(OutputList &ol) if (si->title() != manPageName) { - ol.generateDoc(docFile(),docLine(),this,0,si->title(),TRUE,FALSE,0,TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,si->title(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endSection(si->label(),si->type()); } } @@ -248,7 +249,8 @@ void PageDefImpl::writeDocumentation(OutputList &ol) ol.startPageDoc(si->title()); //ol.startSection(si->label,si->title,si->type); startTitle(ol,getOutputFileBase(),this); - ol.generateDoc(docFile(),docLine(),this,0,si->title(),TRUE,FALSE,0,TRUE,FALSE); + ol.generateDoc(docFile(),docLine(),this,0,si->title(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); //stringToSearchIndex(getOutputFileBase(), // theTranslator->trPage(TRUE,TRUE)+" "+si->title, // si->title); @@ -287,13 +289,6 @@ void PageDefImpl::writeDocumentation(OutputList &ol) void PageDefImpl::writePageDocumentation(OutputList &ol) { - - bool markdownEnabled = Doxygen::markdownSupport; - if (getLanguage()==SrcLangExt_Markdown) - { - Doxygen::markdownSupport = TRUE; - } - ol.startTextBlock(); QCString docStr = documentation()+inbodyDocumentation(); if (hasBriefDescription() && !SectionManager::instance().find(name())) @@ -310,12 +305,14 @@ void PageDefImpl::writePageDocumentation(OutputList &ol) 0, // memberdef docStr, // docStr TRUE, // index words - FALSE // not an example + FALSE, // not an example + 0, // exampleName + FALSE, // singleLine + FALSE, // linkFromIndex + TRUE // markdown support ); ol.endTextBlock(); - Doxygen::markdownSupport = markdownEnabled; - if (hasSubPages()) { // for printed documentation we write subpages as section's of the @@ -357,16 +354,16 @@ bool PageDefImpl::visibleInIndex() const { static bool externalPages = Config_getBool(EXTERNAL_PAGES); return // not part of a group - !getGroupDef() && + !getGroupDef() && // not an externally defined page - (!isReference() || externalPages) + (!isReference() || externalPages) ; } bool PageDefImpl::documentedPage() const { return // not part of a group - !getGroupDef() && + !getGroupDef() && // not an externally defined page !isReference(); } diff --git a/src/parserintf.h b/src/parserintf.h index 6dc9569..911b707 100644 --- a/src/parserintf.h +++ b/src/parserintf.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -20,22 +20,25 @@ #include <qstrlist.h> +#include <functional> #include <memory> #include <map> #include <string> #include "types.h" +#include "containers.h" class Entry; class FileDef; class CodeOutputInterface; class MemberDef; class Definition; +class ClangTUParser; /** \brief Abstract interface for outline parsers. * * By implementing the methods of this interface one can add - * a new language parser to doxygen. The parser implementation can make use of the + * a new language parser to doxygen. The parser implementation can make use of the * comment block parser to parse the contents of special comment blocks. */ class OutlineParserInterface @@ -43,36 +46,18 @@ class OutlineParserInterface public: virtual ~OutlineParserInterface() {} - /** Starts processing a translation unit (source files + headers). - * After this call parseInput() is called with sameTranslationUnit - * set to FALSE. If parseInput() returns additional include files, - * these are also processed using parseInput() with - * sameTranslationUnit set to TRUE. After that - * finishTranslationUnit() is called. - */ - virtual void startTranslationUnit(const char *fileName) = 0; - - /** Called after all files in a translation unit have been - * processed. - */ - virtual void finishTranslationUnit() = 0; - - /** Parses a single input file with the goal to build an Entry tree. + /** Parses a single input file with the goal to build an Entry tree. * @param[in] fileName The full name of the file. * @param[in] fileBuf The contents of the file (zero terminated). - * @param[in,out] root The root of the tree of Entry *nodes + * @param[in,out] root The root of the tree of Entry *nodes * representing the information extracted from the file. - * @param[in] sameTranslationUnit TRUE if this file was found in the same - * translation unit (in the filesInSameTranslationUnit list - * returned for another file). - * @param[in,out] filesInSameTranslationUnit other files expected to be - * found in the same translation unit (used for libclang) + * @param[in] clangParser The clang translation unit parser object + * or nullptr if disabled. */ virtual void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit) = 0; + ClangTUParser *clangParser) = 0; /** Returns TRUE if the language identified by \a extension needs * the C preprocessor to be run before feed the result to the input @@ -80,7 +65,7 @@ class OutlineParserInterface * @see parseInput() */ virtual bool needsPreprocessing(const QCString &extension) const = 0; - + /** Callback function called by the comment block scanner. * It provides a string \a text containing the prototype of a function * or variable. The parser should parse this and store the information @@ -110,14 +95,14 @@ class CodeParserInterface * @param[in] input Actual code in the form of a string * @param[in] isExampleBlock TRUE iff the code is part of an example. * @param[in] exampleName Name of the example. - * @param[in] fileDef File definition to which the code + * @param[in] fileDef File definition to which the code * is associated. - * @param[in] startLine Starting line in case of a code fragment. + * @param[in] startLine Starting line in case of a code fragment. * @param[in] endLine Ending line of the code fragment. - * @param[in] inlineFragment Code fragment that is to be shown inline + * @param[in] inlineFragment Code fragment that is to be shown inline * as part of the documentation. * @param[in] memberDef Member definition to which the code - * is associated (non null in case of an inline fragment + * is associated (non null in case of an inline fragment * for a member). * @param[in] showLineNumbers if set to TRUE and also fileDef is not 0, * line numbers will be added to the source fragment @@ -151,29 +136,31 @@ class CodeParserInterface //----------------------------------------------------------------------------- +using OutlineParserFactory = std::function<std::unique_ptr<OutlineParserInterface>()>; + /** \brief Manages programming language parsers. * - * This class manages the language parsers in the system. One can + * This class manages the language parsers in the system. One can * register parsers, and obtain a parser given a file extension. */ class ParserManager { public: + struct ParserPair { - ParserPair(std::unique_ptr<OutlineParserInterface> oli, - std::unique_ptr<CodeParserInterface> cpi) - : outlineParser(std::move(oli)), codeParser(std::move(cpi)) + ParserPair(OutlineParserFactory opf, std::unique_ptr<CodeParserInterface> cpi) + : outlineParserFactory(opf), codeParserInterface(std::move(cpi)) { } - std::unique_ptr<OutlineParserInterface> outlineParser; - std::unique_ptr<CodeParserInterface> codeParser; + OutlineParserFactory outlineParserFactory; + std::unique_ptr<CodeParserInterface> codeParserInterface; }; - ParserManager(std::unique_ptr<OutlineParserInterface> outlineParser, - std::unique_ptr<CodeParserInterface> codeParser) - : m_defaultParsers(std::move(outlineParser),std::move(codeParser)) + ParserManager(OutlineParserFactory outlineParserFactory, + std::unique_ptr<CodeParserInterface> codeParserInterface) + : m_defaultParsers(outlineParserFactory,std::move(codeParserInterface)) { } @@ -185,14 +172,14 @@ class ParserManager * @param[in] codeParser The code parser that is to be used for the * given name. */ - void registerParser(const char *name,std::unique_ptr<OutlineParserInterface> outlineParser, - std::unique_ptr<CodeParserInterface> codeParser) + void registerParser(const char *name,OutlineParserFactory outlineParserFactory, + std::unique_ptr<CodeParserInterface> codeParserInterface) { m_parsers.emplace(std::string(name), - ParserPair(std::move(outlineParser),std::move(codeParser))); + ParserPair(outlineParserFactory,std::move(codeParserInterface))); } - /** Registers a file \a extension with a parser with name \a parserName. + /** Registers a file \a extension with a parser with name \a parserName. * Returns TRUE if the extension was successfully registered. */ bool registerExtension(const char *extension, const char *parserName) @@ -212,21 +199,21 @@ class ParserManager } /** Gets the interface to the parser associated with given \a extension. - * If there is no parser explicitly registered for the supplied extension, + * If there is no parser explicitly registered for the supplied extension, * the interface to the default parser will be returned. */ - OutlineParserInterface &getOutlineParser(const char *extension) + std::unique_ptr<OutlineParserInterface> getOutlineParser(const char *extension) { - return *getParsers(extension).outlineParser; + return getParsers(extension).outlineParserFactory(); } /** Gets the interface to the parser associated with given \a extension. - * If there is no parser explicitly registered for the supplied extension, + * If there is no parser explicitly registered for the supplied extension, * the interface to the default parser will be returned. */ CodeParserInterface &getCodeParser(const char *extension) { - return *getParsers(extension).codeParser; + return *getParsers(extension).codeParserInterface; } private: diff --git a/src/perlmodgen.cpp b/src/perlmodgen.cpp index a08e480..a6e9f22 100644 --- a/src/perlmodgen.cpp +++ b/src/perlmodgen.cpp @@ -1446,16 +1446,6 @@ static void addTemplateArgumentList(const ArgumentList &al,PerlModOutput &output output.closeList(); } -#if 0 -static void addMemberTemplateLists(MemberDef *md,PerlModOutput &output) -{ - ClassDef *cd = md->getClassDef(); - const char *cname = cd ? cd->name().data() : 0; - if (md->templateArguments()) // function template prefix - addTemplateArgumentList(md->templateArguments(),output,cname); -} -#endif - static void addTemplateList(const ClassDef *cd,PerlModOutput &output) { addTemplateArgumentList(cd->templateArguments(),output,cd->name()); @@ -1473,7 +1463,8 @@ static void addPerlModDocBlock(PerlModOutput &output, if (stext.isEmpty()) output.addField(name).add("{}"); else { - DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,stext,FALSE,0); + DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,stext,FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); output.openHash(name); PerlModDocVisitor *visitor = new PerlModDocVisitor(output); root->accept(visitor); diff --git a/src/plantuml.cpp b/src/plantuml.cpp index 2e172ac..d020da0 100644 --- a/src/plantuml.cpp +++ b/src/plantuml.cpp @@ -208,21 +208,23 @@ static void runPlantumlContent(const QDict< QList <QCString> > &plantumlFiles, QCString pumlType = ""; QCString pumlOutDir = ""; - QStrList &pumlIncludePathList = Config_getList(PLANTUML_INCLUDE_PATH); - char *s=pumlIncludePathList.first(); - if (s) + const StringVector &pumlIncludePathList = Config_getList(PLANTUML_INCLUDE_PATH); { - pumlArgs += "-Dplantuml.include.path=\""; - pumlArgs += s; - s = pumlIncludePathList.next(); - } - while (s) - { - pumlArgs += Portable::pathListSeparator(); - pumlArgs += s; - s = pumlIncludePathList.next(); + auto it = pumlIncludePathList.begin(); + if (it!=pumlIncludePathList.end()) + { + pumlArgs += "-Dplantuml.include.path=\""; + pumlArgs += it->c_str(); + ++it; + } + while (it!=pumlIncludePathList.end()) + { + pumlArgs += Portable::pathListSeparator(); + pumlArgs += it->c_str(); + ++it; + } } - if (pumlIncludePathList.first()) pumlArgs += "\" "; + if (!pumlIncludePathList.empty()) pumlArgs += "\" "; pumlArgs += "-Djava.awt.headless=true -jar \""+plantumlJarPath+"plantuml.jar\" "; if (!plantumlConfigFile.isEmpty()) { @@ -26,10 +26,16 @@ * includes */ +#include "doxygen.h" + #include <stack> #include <deque> #include <algorithm> #include <utility> +#if MULTITHREADED_INPUT +#include <mutex> +#include <thread> +#endif #include <stdio.h> #include <assert.h> @@ -44,7 +50,6 @@ #include "pre.h" #include "constexp.h" #include "define.h" -#include "doxygen.h" #include "message.h" #include "util.h" #include "defargs.h" @@ -91,252 +96,138 @@ struct FileState QCString fileName; }; -/** A dictionary of references to Define objects. */ -typedef std::map< std::string,Define* > DefineMapRef; +struct PreIncludeInfo +{ + PreIncludeInfo(const char *fn,FileDef *srcFd, FileDef *dstFd,const char *iName,bool loc, bool imp) + : fileName(fn), fromFileDef(srcFd), toFileDef(dstFd), includeName(iName), local(loc), imported(imp) + { + } + QCString fileName; // file name in which the include statement was found + FileDef *fromFileDef; // filedef in which the include statement was found + FileDef *toFileDef; // filedef to which the include is pointing + QCString includeName; // name used in the #include statement + bool local; // is it a "local" or <global> include + bool imported; // include via "import" keyword (Objective-C) +}; /** A dictionary of managed Define objects. */ typedef std::map< std::string,std::unique_ptr<Define> > DefineMapOwning; -/** @brief Singleton that manages the defines available while +/** @brief Class that manages the defines available while * preprocessing files. */ class DefineManager { - /** Local class used to hold the defines for a single file */ - class DefinesPerFile - { - public: - /** Creates an empty container for defines */ - DefinesPerFile(DefineManager *parent) - : m_parent(parent) - { - } - /** Destroys the object */ - virtual ~DefinesPerFile() - { - } - /** Adds a define in the context of a file. Will replace - * an existing define with the same name (redefinition) - * @param def The Define object to add. Ownership will be transferred. - */ - void addDefine(std::unique_ptr<Define> &&def) - { - auto it = m_defines.find(def->name.data()); - if (it!=m_defines.end()) // redefine - { - m_defines.erase(it); - } - m_defines.insert(std::make_pair(toStdString(def->name),std::move(def))); - } - /** Adds an include file for this file - * @param fileName The name of the include file - */ - void addInclude(const char *fileName) - { - m_includedFiles.insert(fileName); - } - void collectDefines(DefineMapRef &map,StringSet &includeStack); - private: - DefineManager *m_parent; - DefineMapOwning m_defines; - StringSet m_includedFiles; - }; - - public: - friend class DefinesPerFile; - - /** Creates a new DefineManager object */ - DefineManager() + private: + /** Local class used to hold the defines for a single file */ + class DefinesPerFile { - } + public: + /** Creates an empty container for defines */ + DefinesPerFile(DefineManager *parent) + : m_parent(parent) + { + } + void addInclude(std::string fileName) + { + m_includedFiles.insert(fileName); + } + void store(const DefineMapOwning &fromMap) + { + for (auto &kv : fromMap) + { + m_defines.emplace(kv.first,std::make_unique<Define>(*kv.second.get())); + } + } + void retrieve(DefineMapOwning &toMap) + { + StringSet includeStack; + retrieveRec(toMap,includeStack); + } + void retrieveRec(DefineMapOwning &toMap,StringSet &includeStack) + { + for (auto incFile : m_includedFiles) + { + DefinesPerFile *dpf = m_parent->find(incFile); + if (dpf && includeStack.find(incFile)==includeStack.end()) + { + //printf(" processing include %s\n",incFile.data()); + includeStack.insert(incFile); + dpf->retrieveRec(toMap,includeStack); + } + } + for (auto &kv : m_defines) + { + toMap.emplace(kv.first,std::make_unique<Define>(*kv.second.get())); + } + } + private: + DefineManager *m_parent; + DefineMapOwning m_defines; + StringSet m_includedFiles; + }; - /** Destroys the object */ - virtual ~DefineManager() - { - } + friend class DefinesPerFile; + public: - /** Starts a context in which defines are collected. - * Called at the start of a new file that is preprocessed. - * @param fileName the name of the file to process. - */ - void startContext(const char *fileName) + void addInclude(std::string fromFileName,std::string toFileName) { - //printf("DefineManager::startContext()\n"); - m_contextDefines.clear(); - if (fileName==0) return; - //DefinesPerFile *dpf = m_fileMap.find(fileName); - auto it = m_fileMap.find(fileName); - if (it==m_fileMap.end()) - { - //printf("New file!\n"); - m_fileMap.emplace(toStdString(fileName),std::make_unique<DefinesPerFile>(this)); - } - } - /** Ends the context started with startContext() freeing any - * defines collected within in this context. - */ - void endContext() - { - //printf("DefineManager::endContext()\n"); - m_contextDefines.clear(); - } - /** Add an included file to the current context. - * If the file has been pre-processed already, all defines are added - * to the context. - * @param fileName The name of the include file to add to the context. - */ - void addFileToContext(const char *fileName) - { - if (fileName==0) return; - //printf("DefineManager::addFileToContext(%s)\n",fileName); - auto it = m_fileMap.find(fileName); - if (it==m_fileMap.end()) - { - //printf("New file!\n"); - m_fileMap.emplace(toStdString(fileName),std::make_unique<DefinesPerFile>(this)); - } - else + auto it = m_fileMap.find(fromFileName); + if (it!=m_fileMap.end()) { - //printf("existing file!\n"); - StringSet includeStack; - it->second->collectDefines(m_contextDefines,includeStack); + auto &dpf = it->second; + dpf->addInclude(toFileName); } } - /** Add a define to the manager object. - * @param fileName The file in which the define was found - * @param def The Define object to add. Ownership will be transferred. - */ - void addDefine(const char *fileName,std::unique_ptr<Define> &&def) + void store(std::string fileName,const DefineMapOwning &fromMap) { - if (fileName==0) return; - //printf("DefineManager::addDefine(%s,%s)\n",fileName,def->name.data()); - - m_contextDefines[def->name.data()] = def.get(); - auto it = m_fileMap.find(fileName); if (it==m_fileMap.end()) { - auto ptr = std::make_unique<DefinesPerFile>(this); - ptr->addDefine(std::move(def)); - m_fileMap.emplace(toStdString(fileName),std::move(ptr)); - } - else - { - it->second->addDefine(std::move(def)); + it = m_fileMap.emplace(fileName,std::make_unique<DefinesPerFile>(this)).first; } + it->second->store(fromMap); } - /** Add an include relation to the manager object. - * @param fromFileName file name in which the include was found. - * @param toFileName file name that is included. - */ - void addInclude(const char *fromFileName,const char *toFileName) + void retrieve(std::string fileName,DefineMapOwning &toMap) { - //printf("DefineManager::addInclude(%s,%s)\n",fromFileName,toFileName); - if (fromFileName==0 || toFileName==0) return; - auto it = m_fileMap.find(fromFileName); - if (it==m_fileMap.end()) - { - auto ptr = std::make_unique<DefinesPerFile>(this); - ptr->addInclude(toFileName); - m_fileMap.emplace(toStdString(fromFileName),std::move(ptr)); - } - else - { - it->second->addInclude(toFileName); - } - } - /** Returns a reference to a Define object given its name or 0 if the Define does - * not exist. - */ - Define *isDefined(const char *name) - { - Define *d=0; - auto it = m_contextDefines.find(name); - if (it!=m_contextDefines.end()) + auto it = m_fileMap.find(fileName); + if (it!=m_fileMap.end()) { - d = it->second; - if (d->undef) - { - d=0; - } + auto &dpf = it->second; + dpf->retrieve(toMap); } - //printf("isDefined(%s)=%p\n",name,d); - return d; } - /** Returns a reference to the defines found in the current context. */ - const DefineMapRef &defineContext() const + bool alreadyProcessed(std::string fileName) const { - return m_contextDefines; + return m_fileMap.find(fileName)!=m_fileMap.end(); } private: - /** Helper function to collect all define for a given file */ - void collectDefinesForFile(const char *fileName,DefineMapRef &map) - { - if (fileName==0) return; - auto it = m_fileMap.find(fileName); - if (it!=m_fileMap.end()) - { - StringSet includeStack; - it->second->collectDefines(map,includeStack); - } - } - /** Helper function to return the DefinesPerFile object for a given file name. */ - DefinesPerFile *find(const char *fileName) const + DefinesPerFile *find(std::string fileName) const { - if (fileName==0) return nullptr; auto it = m_fileMap.find(fileName); return it!=m_fileMap.end() ? it->second.get() : nullptr; } - std::map< std::string,std::unique_ptr<DefinesPerFile> > m_fileMap; - DefineMapRef m_contextDefines; + std::unordered_map< std::string, std::unique_ptr<DefinesPerFile> > m_fileMap; }; -/** Collects all defines for a file and all files that the file includes. - * This function will recursively call itself for each file. - * @param dict The dictionary to fill with the defines. A redefine will - * replace a previous definition. - * @param includeStack The stack of includes, used to stop recursion in - * case there is a cyclic include dependency. - */ -void DefineManager::DefinesPerFile::collectDefines( - DefineMapRef &map,StringSet &includeStack) -{ - //printf("DefinesPerFile::collectDefines #defines=%d\n",m_defines.count()); - { - for (auto incFile : m_includedFiles) - { - DefinesPerFile *dpf = m_parent->find(incFile.c_str()); - if (dpf && includeStack.find(incFile)==includeStack.end()) - { - //printf(" processing include %s\n",incFile.data()); - includeStack.insert(incFile); - dpf->collectDefines(map,includeStack); - } - } - } - { - for (auto &kv : m_defines) - { - const std::unique_ptr<Define> &def = kv.second; - map[def->name.data()] = def.get(); - //printf(" adding define %s\n",def->name.data()); - } - } -} - - /* ----------------------------------------------------------------- * * global state */ -static StringUnorderedSet g_allIncludes; +#if MULTITHREADED_INPUT +static std::mutex g_debugMutex; +static std::mutex g_globalDefineMutex; +//static std::mutex g_addIncludeRelationMutex; +//static std::mutex g_macroDefinitionsMutex; +static std::mutex g_updateGlobals; +#endif static DefineManager g_defineManager; @@ -400,6 +291,9 @@ struct preYY_state std::unordered_map<std::string,Define*> expandedDict; StringUnorderedSet expanded; ConstExpressionParser constExpParser; + DefineMapOwning contextDefines; + DefineList macroDefinitions; + LinkedMap<PreIncludeInfo> includeRelations; }; // stateless functions @@ -420,9 +314,10 @@ static bool computeExpression(yyscan_t yyscanner,const QCString &expr); static void startCondSection(yyscan_t yyscanner,const char *sectId); static void endCondSection(yyscan_t yyscanner); static void addMacroDefinition(yyscan_t yyscanner); -static std::unique_ptr<Define> newDefine(yyscan_t yyscanner); +static void addDefine(yyscan_t yyscanner); static void setFileName(yyscan_t yyscanner,const char *name); static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size); +static Define * isDefined(yyscan_t yyscanner,const char *name); /* ----------------------------------------------------------------- */ @@ -515,7 +410,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) !( (yyextra->includeStack.empty() || yyextra->curlyCount>0) && yyextra->macroExpansion && - (def=g_defineManager.isDefined(name)) && + (def=isDefined(yyscanner,name)) && /*macroIsAccessible(def) &&*/ (!yyextra->expandOnlyPredef || def->isPredefined) ) @@ -641,7 +536,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) yyextra->expectGuard = FALSE; Define *def=0; //def=yyextra->globalDefineDict->find(yytext); - //def=g_defineManager.isDefined(yytext); + //def=isDefined(yyscanner,yytext); //printf("Search for define %s found=%d yyextra->includeStack.empty()=%d " // "yyextra->curlyCount=%d yyextra->macroExpansion=%d yyextra->expandOnlyPredef=%d " // "isPreDefined=%d\n",yytext,def ? 1 : 0, @@ -650,7 +545,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) // ); if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) && yyextra->macroExpansion && - (def=g_defineManager.isDefined(yytext)) && + (def=isDefined(yyscanner,yytext)) && /*(def->isPredefined || macroIsAccessible(def)) && */ (!yyextra->expandOnlyPredef || def->isPredefined) ) @@ -678,7 +573,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) Define *def=0; if ((yyextra->includeStack.empty() || yyextra->curlyCount>0) && yyextra->macroExpansion && - (def=g_defineManager.isDefined(yytext)) && + (def=isDefined(yyscanner,yytext)) && def->nargs==-1 && /*(def->isPredefined || macroIsAccessible(def)) &&*/ (!yyextra->expandOnlyPredef || def->isPredefined) @@ -895,7 +790,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) <Command>. {yyextra->yyColNr+=(int)yyleng;} <UndefName>{ID} { Define *def; - if ((def=g_defineManager.isDefined(yytext)) + if ((def=isDefined(yyscanner,yytext)) /*&& !def->isPredefined*/ && !def->nonRecursive ) @@ -937,7 +832,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) } <DefinedExpr1,DefinedExpr2>\\\n { yyextra->yyLineNr++; outputChar(yyscanner,'\n'); } <DefinedExpr1>{ID} { - if (g_defineManager.isDefined(yytext) || yyextra->guardName==yytext) + if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext) yyextra->guardExpr+=" 1L "; else yyextra->guardExpr+=" 0L "; @@ -945,7 +840,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) BEGIN(Guard); } <DefinedExpr2>{ID} { - if (g_defineManager.isDefined(yytext) || yyextra->guardName==yytext) + if (isDefined(yyscanner,yytext) || yyextra->guardName==yytext) yyextra->guardExpr+=" 1L "; else yyextra->guardExpr+=" 0L "; @@ -1546,17 +1441,11 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) { addMacroDefinition(yyscanner); } - def=g_defineManager.isDefined(yyextra->defName); + def=isDefined(yyscanner,yyextra->defName); if (def==0) // new define { //printf("new define '%s'!\n",yyextra->defName.data()); - g_defineManager.addDefine(yyextra->yyFileName,newDefine(yyscanner)); - - // also add it to the local file list if it is a source file - //if (yyextra->isSource && yyextra->includeStack.empty()) - //{ - // yyextra->fileDefineDict->insert(yyextra->defName,nd); - //} + addDefine(yyscanner); } else if (def /*&& macroIsAccessible(def)*/) // name already exists @@ -1628,6 +1517,7 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) } else { + QCString toFileName = yyextra->yyFileName; const std::unique_ptr<FileState> &fs=yyextra->includeStack.back(); //fileDefineCache->merge(yyextra->yyFileName,fs->fileName); YY_BUFFER_STATE oldBuf = YY_CURRENT_BUFFER; @@ -1648,6 +1538,31 @@ CHARLIT (("'"\\[0-7]{1,3}"'")|("'"\\."'")|("'"[^'\\\n]{1,4}"'")) outputArray(yyscanner,lineStr.data(),lineStr.length()); yyextra->includeStack.pop_back(); + +#if MULTITHREADED_INPUT + { + std::lock_guard<std::mutex> lock(g_globalDefineMutex); +#endif + // to avoid deadlocks we allow multiple threads to process the same header file. + // The first one to finish will store the results globally. After that the + // next time the same file is encountered, the stored data is used and the file + // is not processed again. + if (!g_defineManager.alreadyProcessed(toFileName.str())) + { + // now that the file is completely processed, prevent it from processing it again + g_defineManager.addInclude(yyextra->yyFileName.str(),toFileName.str()); + g_defineManager.store(toFileName.str(),yyextra->contextDefines); + } + else + { + if (Debug::isFlagSet(Debug::Preprocessor)) + { + Debug::print(Debug::Preprocessor,0,"#include %s: was already processed by another thread! not storing data...\n",qPrint(toFileName)); + } + } +#if MULTITHREADED_INPUT + } +#endif } } <*>"/*"/"*/" | @@ -1763,41 +1678,44 @@ static void setCaseDone(yyscan_t yyscanner,bool value) } -static FileState *checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,bool &alreadyIncluded) +static FileState *checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,bool &alreadyProcessed) { YY_EXTRA_TYPE state = preYYget_extra(yyscanner); - alreadyIncluded = FALSE; + alreadyProcessed = FALSE; FileState *fs = 0; //printf("checkAndOpenFile(%s)\n",fileName.data()); QFileInfo fi(fileName); if (fi.exists() && fi.isFile()) { - const QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS); - if (patternMatch(fi,&exclPatterns)) return 0; + const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS); + if (patternMatch(fi,exclPatterns)) return 0; QCString absName = fi.absFilePath().utf8(); // global guard if (state->curlyCount==0) // not #include inside { ... } { - if (g_allIncludes.find(absName.data())!=g_allIncludes.end()) +#if MULTITHREADED_INPUT + std::lock_guard<std::mutex> lock(g_globalDefineMutex); +#endif + + if (g_defineManager.alreadyProcessed(absName.str())) { - alreadyIncluded = TRUE; + alreadyProcessed = TRUE; //printf(" already included 1\n"); return 0; // already done } - g_allIncludes.insert(absName.data()); } // check include stack for absName - alreadyIncluded = std::any_of( + alreadyProcessed = std::any_of( state->includeStack.begin(), state->includeStack.end(), [absName](const std::unique_ptr<FileState> &lfs) { return lfs->fileName==absName; } ); - if (alreadyIncluded) + if (alreadyProcessed) { //printf(" already included 2\n"); return 0; @@ -1820,20 +1738,20 @@ static FileState *checkAndOpenFile(yyscan_t yyscanner,const QCString &fileName,b return fs; } -static FileState *findFile(yyscan_t yyscanner, const char *fileName,bool localInclude,bool &alreadyIncluded) +static FileState *findFile(yyscan_t yyscanner, const char *fileName,bool localInclude,bool &alreadyProcessed) { YY_EXTRA_TYPE state = preYYget_extra(yyscanner); //printf("** findFile(%s,%d) state->yyFileName=%s\n",fileName,localInclude,state->yyFileName.data()); if (Portable::isAbsolutePath(fileName)) { - FileState *fs = checkAndOpenFile(yyscanner,fileName,alreadyIncluded); + FileState *fs = checkAndOpenFile(yyscanner,fileName,alreadyProcessed); if (fs) { setFileName(yyscanner,fileName); state->yyLineNr=1; return fs; } - else if (alreadyIncluded) + else if (alreadyProcessed) { return 0; } @@ -1844,14 +1762,14 @@ static FileState *findFile(yyscan_t yyscanner, const char *fileName,bool localIn if (fi.exists()) { QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+fileName; - FileState *fs = checkAndOpenFile(yyscanner,absName,alreadyIncluded); + FileState *fs = checkAndOpenFile(yyscanner,absName,alreadyProcessed); if (fs) { setFileName(yyscanner,absName); state->yyLineNr=1; return fs; } - else if (alreadyIncluded) + else if (alreadyProcessed) { return 0; } @@ -1865,7 +1783,7 @@ static FileState *findFile(yyscan_t yyscanner, const char *fileName,bool localIn { std::string absName = path+"/"+fileName; //printf(" Looking for %s in %s\n",fileName,path.c_str()); - FileState *fs = checkAndOpenFile(yyscanner,absName.c_str(),alreadyIncluded); + FileState *fs = checkAndOpenFile(yyscanner,absName.c_str(),alreadyProcessed); if (fs) { setFileName(yyscanner,absName.c_str()); @@ -1873,7 +1791,7 @@ static FileState *findFile(yyscan_t yyscanner, const char *fileName,bool localIn //printf(" -> found it\n"); return fs; } - else if (alreadyIncluded) + else if (alreadyProcessed) { return 0; } @@ -2415,7 +2333,7 @@ static bool expandExpression(yyscan_t yyscanner,QCString &expr,QCString *rest,in { if (state->expandedDict.find(macroName.data())==state->expandedDict.end()) // expand macro { - Define *def=g_defineManager.isDefined(macroName); + Define *def=isDefined(yyscanner,macroName); if (macroName=="defined") { //printf("found defined inside macro definition '%s'\n",expr.right(expr.length()-p).data()); @@ -2768,7 +2686,7 @@ static QCString expandMacro(yyscan_t yyscanner,const QCString &name) return n; } -static std::unique_ptr<Define> newDefine(yyscan_t yyscanner) +static void addDefine(yyscan_t yyscanner) { YY_EXTRA_TYPE state = preYYget_extra(yyscanner); std::unique_ptr<Define> def = std::make_unique<Define>(); @@ -2784,11 +2702,16 @@ static std::unique_ptr<Define> newDefine(yyscan_t yyscanner) // def->fileDef ? def->fileDef->name().data() : def->fileName.data()); //printf("newDefine: '%s'->'%s'\n",def->name.data(),def->definition.data()); if (!def->name.isEmpty() && - Doxygen::expandAsDefinedSet.find(def->name.data())!=Doxygen::expandAsDefinedSet.end()) + Doxygen::expandAsDefinedSet.find(def->name.str())!=Doxygen::expandAsDefinedSet.end()) { def->isPredefined=TRUE; } - return def; + auto it = state->contextDefines.find(def->name.str()); + if (it!=state->contextDefines.end()) // redefine + { + state->contextDefines.erase(it); + } + state->contextDefines.insert(std::make_pair(toStdString(def->name),std::move(def))); } static void addMacroDefinition(yyscan_t yyscanner) @@ -2830,7 +2753,9 @@ static void addMacroDefinition(yyscan_t yyscanner) { define->definition = litTextStripped; } - Doxygen::macroDefinitions.push_back(std::move(define)); + { + state->macroDefinitions.push_back(std::move(define)); + } } static inline void outputChar(yyscan_t yyscanner,char c) @@ -2845,10 +2770,47 @@ static inline void outputArray(yyscan_t yyscanner,const char *a,int len) if (state->includeStack.empty() || state->curlyCount>0) state->outputBuf->addArray(a,len); } +static QCString determineAbsoluteIncludeName(const QCString &curFile,const QCString &incFileName) +{ + bool searchIncludes = Config_getBool(SEARCH_INCLUDES); + QCString absIncFileName = incFileName; + QFileInfo fi(curFile); + if (fi.exists()) + { + QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName; + QFileInfo fi2(absName); + if (fi2.exists()) + { + absIncFileName=fi2.absFilePath().utf8(); + } + else if (searchIncludes) // search in INCLUDE_PATH as well + { + const StringVector &includePath = Config_getList(INCLUDE_PATH); + for (const auto &incPath : includePath) + { + QFileInfo fi3(incPath.c_str()); + if (fi3.exists() && fi3.isDir()) + { + absName = QCString(fi3.absFilePath().utf8())+"/"+incFileName; + //printf("trying absName=%s\n",absName.data()); + QFileInfo fi4(absName); + if (fi4.exists()) + { + absIncFileName=fi4.absFilePath().utf8(); + break; + } + //printf( "absIncFileName = %s\n", absIncFileName.data() ); + } + } + } + //printf( "absIncFileName = %s\n", absIncFileName.data() ); + } + return absIncFileName; +} + static void readIncludeFile(yyscan_t yyscanner,const QCString &inc) { YY_EXTRA_TYPE state = preYYget_extra(yyscanner); - static bool searchIncludes = Config_getBool(SEARCH_INCLUDES); uint i=0; // find the start of the include file name @@ -2880,51 +2842,13 @@ static void readIncludeFile(yyscan_t yyscanner,const QCString &inc) int oldLineNr = state->yyLineNr; //printf("Searching for '%s'\n",incFileName.data()); - // absIncFileName avoids difficulties for incFileName starting with "../" (bug 641336) - QCString absIncFileName = incFileName; - { - QFileInfo fi(state->yyFileName); - if (fi.exists()) - { - QCString absName = QCString(fi.dirPath(TRUE).data())+"/"+incFileName; - QFileInfo fi2(absName); - if (fi2.exists()) - { - absIncFileName=fi2.absFilePath().utf8(); - } - else if (searchIncludes) // search in INCLUDE_PATH as well - { - QStrList &includePath = Config_getList(INCLUDE_PATH); - char *incPath=includePath.first(); - while (incPath) - { - QFileInfo fi3(incPath); - if (fi3.exists() && fi3.isDir()) - { - absName = QCString(fi3.absFilePath().utf8())+"/"+incFileName; - //printf("trying absName=%s\n",absName.data()); - QFileInfo fi4(absName); - if (fi4.exists()) - { - absIncFileName=fi4.absFilePath().utf8(); - break; - } - //printf( "absIncFileName = %s\n", absIncFileName.data() ); - } - incPath=includePath.next(); - } - } - //printf( "absIncFileName = %s\n", absIncFileName.data() ); - } - } - g_defineManager.addInclude(state->yyFileName,absIncFileName); - g_defineManager.addFileToContext(absIncFileName); + QCString absIncFileName = determineAbsoluteIncludeName(state->yyFileName,incFileName); // findFile will overwrite state->yyFileDef if found FileState *fs; - bool alreadyIncluded = FALSE; + bool alreadyProcessed = FALSE; //printf("calling findFile(%s)\n",incFileName.data()); - if ((fs=findFile(yyscanner,incFileName,localInclude,alreadyIncluded))) // see if the include file can be found + if ((fs=findFile(yyscanner,incFileName,localInclude,alreadyProcessed))) // see if the include file can be found { //printf("Found include file!\n"); if (Debug::isFlagSet(Debug::Preprocessor)) @@ -2935,24 +2859,25 @@ static void readIncludeFile(yyscan_t yyscanner,const QCString &inc) } //msg("#include %s: parsing...\n",incFileName.data()); } - if (oldFileDef) + + if (state->includeStack.empty() && oldFileDef) { - // add include dependency to the file in which the #include was found - bool ambig; - // change to absolute name for bug 641336 - FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig); - oldFileDef->addIncludeDependency(ambig ? 0 : incFd,incFileName,localInclude,state->isImported,FALSE); - // add included by dependency - if (state->yyFileDef) + PreIncludeInfo *ii = state->includeRelations.find(absIncFileName); + if (ii==0) { - //printf("Adding include dependency %s->%s\n",oldFileDef->name().data(),incFileName.data()); - state->yyFileDef->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,state->isImported); + bool ambig; + FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig); + state->includeRelations.add( + absIncFileName, + oldFileDef, + ambig?nullptr:incFd, + incFileName, + localInclude, + state->isImported + ); } } - else if (state->inputFileDef) - { - state->inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,state->isImported,TRUE); - } + struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; fs->bufState = YY_CURRENT_BUFFER; fs->lineNr = oldLineNr; @@ -2977,32 +2902,37 @@ static void readIncludeFile(yyscan_t yyscanner,const QCString &inc) } else { - //printf(" calling findFile(%s) alreadyInc=%d\n",incFileName.data(),alreadyIncluded); - if (oldFileDef) + if (alreadyProcessed) // if this header was already process we can just copy the stored macros + // in the local context { - bool ambig; - - // change to absolute name for bug 641336 - FileDef *fd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig); - //printf("%s::findFileDef(%s)=%p\n",oldFileDef->name().data(),incFileName.data(),fd); - // add include dependency to the file in which the #include was found - oldFileDef->addIncludeDependency(ambig ? 0 : fd,incFileName,localInclude,state->isImported,FALSE); - // add included by dependency - if (fd) - { - //printf("Adding include dependency (2) %s->%s ambig=%d\n",oldFileDef->name().data(),fd->name().data(),ambig); - fd->addIncludedByDependency(oldFileDef,oldFileDef->docName(),localInclude,state->isImported); - } +#if MULTITHREADED_INPUT + std::lock_guard<std::mutex> lock(g_globalDefineMutex); +#endif + g_defineManager.retrieve(absIncFileName.str(),state->contextDefines); } - else if (state->inputFileDef) + + if (state->includeStack.empty() && oldFileDef) { - state->inputFileDef->addIncludeDependency(0,absIncFileName,localInclude,state->isImported,TRUE); + PreIncludeInfo *ii = state->includeRelations.find(absIncFileName); + if (ii==0) + { + bool ambig; + FileDef *incFd = findFileDef(Doxygen::inputNameLinkedMap,absIncFileName,ambig); + ii = state->includeRelations.add(absIncFileName, + oldFileDef, + ambig?0:incFd, + incFileName, + localInclude, + state->isImported + ); + } } + if (Debug::isFlagSet(Debug::Preprocessor)) { - if (alreadyIncluded) + if (alreadyProcessed) { - Debug::print(Debug::Preprocessor,0,"#include %s: already included! skipping...\n",qPrint(incFileName)); + Debug::print(Debug::Preprocessor,0,"#include %s: already processed! skipping...\n",qPrint(incFileName)); } else { @@ -3010,10 +2940,11 @@ static void readIncludeFile(yyscan_t yyscanner,const QCString &inc) } //printf("error: include file %s not found\n",yytext); } - if (state->curlyCount>0 && !alreadyIncluded) // failed to find #include inside { ... } + if (state->curlyCount>0 && !alreadyProcessed) // failed to find #include inside { ... } { warn(state->yyFileName,state->yyLineNr,"include file %s not found, perhaps you forgot to add its directory to INCLUDE_PATH?",incFileName.data()); } + } } } @@ -3162,17 +3093,34 @@ static void unputChar(yyscan_t yyscanner,const QCString &expr,QCString *rest,uin //printf("result: unputChar(%s,%s,%d,%c)\n",expr.data(),rest ? rest->data() : 0,pos,c); } +/** Returns a reference to a Define object given its name or 0 if the Define does + * not exist. + */ +static Define *isDefined(yyscan_t yyscanner,const char *name) +{ + YY_EXTRA_TYPE state = preYYget_extra(yyscanner); + Define *d=0; + auto it = state->contextDefines.find(name); + if (it!=state->contextDefines.end()) + { + d = it->second.get(); + if (d->undef) + { + d=0; + } + } + return d; +} + static void initPredefined(yyscan_t yyscanner,const char *fileName) { YY_EXTRA_TYPE state = preYYget_extra(yyscanner); // add predefined macros - char *defStr; - QStrList &predefList = Config_getList(PREDEFINED); - QStrListIterator sli(predefList); - for (sli.toFirst();(defStr=sli.current());++sli) + const StringVector &predefList = Config_getList(PREDEFINED); + for (const auto &defStr : predefList) { - QCString ds = defStr; + QCString ds = defStr.c_str(); int i_equals=ds.find('='); int i_obrace=ds.find('('); int i_cbrace=ds.find(')'); @@ -3243,7 +3191,7 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName) def->nonRecursive = nonRecursive; def->fileDef = state->yyFileDef; def->fileName = fileName; - g_defineManager.addDefine(state->yyFileName,std::move(def)); + state->contextDefines.insert(std::make_pair(toStdString(def->name),std::move(def))); //printf("#define '%s' '%s' #nargs=%d\n", // def->name.data(),def->definition.data(),def->nargs); @@ -3275,7 +3223,7 @@ static void initPredefined(yyscan_t yyscanner,const char *fileName) def->nonRecursive = nonRecursive; def->fileDef = state->yyFileDef; def->fileName = fileName; - g_defineManager.addDefine(state->yyFileName,std::move(def)); + state->contextDefines.insert(std::make_pair(toStdString(def->name),std::move(def))); } } } @@ -3309,6 +3257,7 @@ Preprocessor::~Preprocessor() void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output) { +// printf("Preprocessor::processFile(%s)\n",fileName); yyscan_t yyscanner = p->yyscanner; YY_EXTRA_TYPE state = preYYget_extra(p->yyscanner); struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; @@ -3332,12 +3281,13 @@ void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output state->outputBuf=&output; state->includeStack.clear(); state->expandedDict.clear(); + state->contextDefines.clear(); while (!state->condStack.empty()) state->condStack.pop(); - //state->fileDefineDict->clear(); setFileName(yyscanner,fileName); + state->inputFileDef = state->yyFileDef; - g_defineManager.startContext(state->yyFileName); + //yyextra->defineManager.startContext(state->yyFileName); initPredefined(yyscanner,fileName); @@ -3368,6 +3318,9 @@ void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output if (Debug::isFlagSet(Debug::Preprocessor)) { +#if MULTITHREADED_INPUT + std::lock_guard<std::mutex> lock(g_debugMutex); +#endif char *orgPos=output.data()+orgOffset; char *newPos=output.data()+output.curPos(); Debug::print(Debug::Preprocessor,0,"Preprocessor output of %s (size: %d bytes):\n",fileName,newPos-orgPos); @@ -3380,14 +3333,13 @@ void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output orgPos++; } Debug::print(Debug::Preprocessor,0,"\n---------\n"); - if (g_defineManager.defineContext().size()>0) + if (yyextra->contextDefines.size()>0) { Debug::print(Debug::Preprocessor,0,"Macros accessible in this file (%s):\n", fileName); Debug::print(Debug::Preprocessor,0,"---------\n"); - for (auto &kv : g_defineManager.defineContext()) + for (auto &kv : yyextra->contextDefines) { - Define *def = kv.second; - Debug::print(Debug::Preprocessor,0,"%s ",qPrint(def->name)); + Debug::print(Debug::Preprocessor,0,"%s ",qPrint(kv.second->name)); } Debug::print(Debug::Preprocessor,0,"\n---------\n"); } @@ -3396,8 +3348,29 @@ void Preprocessor::processFile(const char *fileName,BufStr &input,BufStr &output Debug::print(Debug::Preprocessor,0,"No macros accessible in this file (%s).\n", fileName); } } - g_defineManager.endContext(); + + { +#if MULTITHREADED_INPUT + std::lock_guard<std::mutex> lock(g_updateGlobals); +#endif + for (const auto &inc : state->includeRelations) + { + if (inc->fromFileDef) + { + inc->fromFileDef->addIncludeDependency(inc->toFileDef,inc->includeName,inc->local,inc->imported); + } + if (inc->toFileDef && inc->fromFileDef) + { + inc->toFileDef->addIncludedByDependency(inc->fromFileDef,inc->fromFileDef->docName(),inc->local,inc->imported); + } + } + // add the macro definition for this file to the global map + Doxygen::macroDefinitions.emplace(std::make_pair(state->yyFileName.str(),std::move(state->macroDefinitions))); + } + + //yyextra->defineManager.endContext(); printlex(yy_flex_debug, FALSE, __FILE__, fileName); +// printf("Preprocessor::processFile(%s) finished\n",fileName); } #if USE_STATE2STRING diff --git a/src/pyscanner.h b/src/pyscanner.h index d6e8672..4f0ae38 100644 --- a/src/pyscanner.h +++ b/src/pyscanner.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -36,13 +36,10 @@ class PythonOutlineParser : public OutlineParserInterface public: PythonOutlineParser(); virtual ~PythonOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} - void parseInput(const char * fileName, - const char *fileBuf, + void parseInput(const char * fileName, + const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &extension) const; void parsePrototype(const char *text); private: diff --git a/src/pyscanner.l b/src/pyscanner.l index ed76c75..773391b 100644 --- a/src/pyscanner.l +++ b/src/pyscanner.l @@ -97,6 +97,7 @@ struct pyscannerYY_state QGString * copyString = 0; int indent = 0; int curIndent = 0; + int commentIndent = 0; bool importTuple = FALSE; QDict<QCString> packageNameCache; char atomStart = 0; @@ -140,6 +141,7 @@ static void initSpecialBlock(yyscan_t yyscanner); static void searchFoundDef(yyscan_t yyscanner); static void searchFoundClass(yyscan_t yyscanner); static QCString findPackageScope(yyscan_t yyscanner,const char *fileName); +static void stripIndentation(QCString &doc,const int indentationLevel); static yy_size_t yyread(yyscan_t yyscanner,char *buf,yy_size_t max_size); @@ -1251,7 +1253,8 @@ STARTDOCSYMS "##" QCString actualDoc=yyextra->docBlock; if (!yyextra->docBlockSpecial) // legacy unformatted docstring { - actualDoc.prepend("\\verbatim "); + stripIndentation(actualDoc,yyextra->commentIndent); + actualDoc.prepend("\\verbatim\n"); actualDoc.append("\\endverbatim "); } //printf("-------> yyextra->current=%p yyextra->bodyEntry=%p\n",yyextra->current,yyextra->bodyEntry); @@ -1262,7 +1265,8 @@ STARTDOCSYMS "##" QCString actualDoc=yyextra->docBlock; if (!yyextra->docBlockSpecial) // legacy unformatted docstring { - actualDoc.prepend("\\verbatim "); + stripIndentation(actualDoc,yyextra->commentIndent); + actualDoc.prepend("\\verbatim\n"); actualDoc.append("\\endverbatim "); } actualDoc.prepend("\\namespace "+yyextra->moduleScope+" "); @@ -1290,18 +1294,7 @@ STARTDOCSYMS "##" ^{BB} { // leading whitespace - int indent = computeIndent(yytext); - if (indent>=yyextra->curIndent) - { // strip yyextra->curIndent amount of whitespace - int i; - for (i=0;i<indent-yyextra->curIndent;i++) yyextra->docBlock+=' '; - DBG_CTX((stderr,"stripping indent %d\n",yyextra->curIndent)); - } - else - { - DBG_CTX((stderr,"not stripping: %d<%d\n",indent,yyextra->curIndent)); - yyextra->docBlock += yytext; - } + yyextra->docBlock += yytext; } [^"'\n \t\\]+ { yyextra->docBlock += yytext; @@ -1517,7 +1510,7 @@ static void newFunction(yyscan_t yyscanner) static inline int computeIndent(const char *s) { int col=0; - static int tabSize=Config_getInt(TAB_SIZE); + int tabSize=Config_getInt(TAB_SIZE); const char *p=s; char c; while ((c=*p++)) @@ -1529,6 +1522,55 @@ static inline int computeIndent(const char *s) return col; } +// strip up to \a indentationLevel spaces from each line in \a doc (excluding the first line) +static void stripIndentation(QCString &doc,const int indentationLevel) +{ + if (indentationLevel <= 0) return; // nothing to strip + + // by stripping content the string will only become shorter so we write the results + // back into the input string and then resize it at the end. + char c; + const char *src = doc.data(); + char *dst = doc.rawData(); + bool insideIndent = false; // skip the initial line from stripping + int cnt = 0; + while ((c=*src++)!=0) + { + // invariant: dst<=src + switch(c) + { + case '\n': + *dst++ = c; + insideIndent = true; + cnt = indentationLevel; + break; + case ' ': + if (insideIndent) + { + if (cnt>0) // count down the spacing until the end of the indent + { + cnt--; + } + else // reached the end of the indent, start of the part of the line to keep + { + insideIndent = false; + *dst++ = c; + } + } + else // part after indent, copy to the output + { + *dst++ = c; + } + break; + default: + insideIndent = false; + *dst++ = c; + break; + } + } + doc.resize(dst-doc.data()+1); +} + static QCString findPackageScopeFromPath(yyscan_t yyscanner,const QCString &path) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; @@ -1630,7 +1672,8 @@ static void handleCommentBlock(yyscan_t yyscanner,const QCString &doc,bool brief int position = 0; bool needsEntry; int lineNr = brief ? yyextra->current->briefLine : yyextra->current->docLine; - QCString processedDoc = processMarkdownForCommentBlock(doc,yyextra->yyFileName,lineNr); + Markdown markdown(yyextra->yyFileName,lineNr); + QCString processedDoc = Config_getBool(MARKDOWN_SUPPORT) ? markdown.process(doc,lineNr) : doc; while (yyextra->commentScanner.parseCommentBlock( yyextra->thisParser, (yyextra->docBlockInBody && yyextra->previous) ? yyextra->previous.get() : yyextra->current.get(), @@ -1642,7 +1685,8 @@ static void handleCommentBlock(yyscan_t yyscanner,const QCString &doc,bool brief yyextra->docBlockInBody, yyextra->protection, position, - needsEntry) + needsEntry, + Config_getBool(MARKDOWN_SUPPORT)) ) // need to start a new entry { if (needsEntry) @@ -1684,6 +1728,7 @@ static void initTriDoubleQuoteBlock(yyscan_t yyscanner) yyextra->docBlockJavaStyle = TRUE; yyextra->docBlockSpecial = yytext[strlen(yytext) - 1]=='!'; yyextra->docBlock.resize(0); + yyextra->commentIndent = yyextra->curIndent; yyextra->doubleQuote = TRUE; startCommentBlock(yyscanner,FALSE); } @@ -1696,6 +1741,7 @@ static void initTriSingleQuoteBlock(yyscan_t yyscanner) yyextra->docBlockJavaStyle = TRUE; yyextra->docBlockSpecial = yytext[strlen(yytext) - 1]=='!'; yyextra->docBlock.resize(0); + yyextra->commentIndent = yyextra->curIndent; yyextra->doubleQuote = FALSE; startCommentBlock(yyscanner,FALSE); } @@ -1708,6 +1754,7 @@ static void initSpecialBlock(yyscan_t yyscanner) yyextra->docBlockJavaStyle = TRUE; yyextra->docBrief = TRUE; yyextra->docBlock.resize(0); + yyextra->commentIndent = yyextra->curIndent; startCommentBlock(yyscanner,TRUE); } @@ -1934,8 +1981,7 @@ PythonOutlineParser::~PythonOutlineParser() void PythonOutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool /*sameTranslationUnit*/, - QStrList & /*filesInSameTranslationUnit*/) + ClangTUParser * /*clangParser*/) { struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; yyextra->thisParser = this; diff --git a/src/res2cc_cmd.py b/src/res2cc_cmd.py index 86d999d..268ae86 100755 --- a/src/res2cc_cmd.py +++ b/src/res2cc_cmd.py @@ -58,6 +58,7 @@ class File(object): if ext=='.lum': return LumFile(directory,subdir,fname) if ext=='.luma': return LumaFile(directory,subdir,fname) if ext=='.css': return CSSFile(directory,subdir,fname) + if ext=='.svg': return SVGFile(directory,subdir,fname) return VerbatimFile(directory,subdir,fname) class VerbatimFile(File): @@ -76,6 +77,14 @@ class CSSFile(File): def writeDirEntry(self,outputFile): print(" { \"%s\", \"%s\", %s_data, %s_len, Resource::CSS }," % (self.subdir,self.fileName,self.bareName,self.bareName), file=outputFile) +class SVGFile(File): + def __init__(self,directory,subdir,fileName): + File.__init__(self,directory,subdir,fileName,"r") + def writeContents(self,outputFile): + self.writeBytes(self.inputFile.read(),outputFile) + def writeDirEntry(self,outputFile): + print(" { \"%s\", \"%s\", %s_data, %s_len, Resource::SVG }," % (self.subdir,self.fileName,self.bareName,self.bareName), file=outputFile) + class LumFile(File): def __init__(self,directory,subdir,fileName): File.__init__(self,directory,subdir,fileName,"r") diff --git a/src/resourcemgr.cpp b/src/resourcemgr.cpp index 4ba3388..6d2946c 100644 --- a/src/resourcemgr.cpp +++ b/src/resourcemgr.cpp @@ -150,6 +150,18 @@ bool ResourceMgr::copyResourceAs(const char *name,const char *targetDir,const ch } } break; + case Resource::SVG: + { + QFile f(pathName); + if (f.open(IO_WriteOnly)) + { + QCString buf(res->size+1); + memcpy(buf.rawData(),res->data,res->size); + FTextStream t(&f); + t << replaceColorMarkers(buf); + return TRUE; + } + } } } else diff --git a/src/resourcemgr.h b/src/resourcemgr.h index 6e1587d..1959ec4 100644 --- a/src/resourcemgr.h +++ b/src/resourcemgr.h @@ -20,7 +20,7 @@ /** @brief Compiled resource */ struct Resource { - enum Type { Verbatim, Luminance, LumAlpha, CSS }; + enum Type { Verbatim, Luminance, LumAlpha, CSS, SVG }; const char *category; const char *name; const unsigned char *data; diff --git a/src/rtfgen.cpp b/src/rtfgen.cpp index ecf2d32..9d0a957 100644 --- a/src/rtfgen.cpp +++ b/src/rtfgen.cpp @@ -186,14 +186,14 @@ void RTFGenerator::init() } // overwrite some (or all) definitions from file - QCString &rtfStyleSheetFile = Config_getString(RTF_STYLESHEET_FILE); + QCString rtfStyleSheetFile = Config_getString(RTF_STYLESHEET_FILE); if (!rtfStyleSheetFile.isEmpty()) { loadStylesheet(rtfStyleSheetFile, rtf_Style); } // If user has defined an extension file, load its contents. - QCString &rtfExtensionsFile = Config_getString(RTF_EXTENSIONS_FILE); + QCString rtfExtensionsFile = Config_getString(RTF_EXTENSIONS_FILE); if (!rtfExtensionsFile.isEmpty()) { loadExtensions(rtfExtensionsFile); diff --git a/src/scanner.h b/src/scanner.h index 70df660..cefc934 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -1,12 +1,12 @@ /****************************************************************************** * - * + * * * Copyright (C) 1997-2015 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its - * documentation under the terms of the GNU General Public License is hereby - * granted. No representations are made about the suitability of this software + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * @@ -23,7 +23,7 @@ /** \brief C-like language parser using state-based lexical scanning. * * This is the language parser for doxygen. It is somewhat fuzzy and - * supports C++ and various languages that are closely related to C++, + * supports C++ and various languages that are closely related to C++, * such as C, C#, Objective-C, Java, PHP, and IDL. */ class COutlineParser : public OutlineParserInterface @@ -31,13 +31,10 @@ class COutlineParser : public OutlineParserInterface public: COutlineParser(); virtual ~COutlineParser(); - void startTranslationUnit(const char *fileName); - void finishTranslationUnit(); void parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &extension) const; void parsePrototype(const char *text); private: diff --git a/src/scanner.l b/src/scanner.l index 384b088..e63b8a0 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -193,6 +193,8 @@ struct scannerYY_state uint fencedSize = 0; bool nestedComment = false; std::vector< std::pair<Entry*,std::shared_ptr<Entry> > > outerScopeEntries; + + ClangTUParser * clangParser = 0; }; #if USE_STATE2STRING @@ -766,9 +768,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) yyextra->current->type = "id"; } yyextra->current->name = yytext; - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } } <ObjCMethod>":"{B}* { // start of parameter list @@ -2045,9 +2047,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) BEGIN(FindMembers); } <FindMembers,FindMemberName>{SCOPENAME} { - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } yyextra->yyBegColNr=yyextra->yyColNr; yyextra->yyBegLineNr=yyextra->yyLineNr; @@ -2348,9 +2350,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) */ <Define>{ID} { //printf("Define '%s' without args\n",yytext); - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } yyextra->current->bodyLine = yyextra->yyLineNr; yyextra->current->bodyColumn = yyextra->yyColNr; @@ -2359,7 +2361,6 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } <DefineEnd>\n { //printf("End define: doc=%s docFile=%s docLine=%d\n",yyextra->current->doc.data(),yyextra->current->docFile.data(),yyextra->current->docLine); - lineCount(yyscanner); yyextra->current->fileName = yyextra->yyFileName; yyextra->current->startLine = yyextra->yyLineNr; yyextra->current->startColumn = yyextra->yyColNr; @@ -2368,6 +2369,7 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) yyextra->current->name = yyextra->current->name.stripWhiteSpace(); yyextra->current->section = Entry::DEFINE_SEC; yyextra->current_root->moveToSubEntryAndRefresh(yyextra->current); + lineCount(yyscanner); initEntry(yyscanner); BEGIN(yyextra->lastDefineContext); } @@ -3463,9 +3465,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } <Sharp>. { yyextra->current->type += *yytext ; } <FindFields>{ID} { - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } yyextra->current->bodyLine = yyextra->yyLineNr; yyextra->current->bodyColumn = yyextra->yyColNr; @@ -5334,9 +5336,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } <CompoundName>{SCOPENAME} { yyextra->current->name = yytext ; - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } lineCount(yyscanner); if (yyextra->current->spec & Entry::Protocol) @@ -5399,9 +5401,9 @@ OPERATOR "operator"{B}*({ARITHOP}|{ASSIGNOP}|{LOGICOP}|{BITOP}) } } <ClassVar>{ID} { - if (yyextra->insideCpp || yyextra->insideObjC) + if (yyextra->clangParser && (yyextra->insideCpp || yyextra->insideObjC)) { - yyextra->current->id = ClangParser::instance()->lookup(yyextra->yyLineNr,yytext); + yyextra->current->id = yyextra->clangParser->lookup(yyextra->yyLineNr,yytext); } if (yyextra->insideIDL && qstrcmp(yytext,"switch")==0) { @@ -7016,7 +7018,9 @@ static void handleCommentBlock(yyscan_t yyscanner,const QCString &doc,bool brief int position=0; bool needsEntry=FALSE; - QCString processedDoc = processMarkdownForCommentBlock(stripIndentation(doc),yyextra->yyFileName,lineNr); + Markdown markdown(yyextra->yyFileName,lineNr); + QCString strippedDoc = stripIndentation(doc); + QCString processedDoc = Config_getBool(MARKDOWN_SUPPORT) ? markdown.process(strippedDoc,lineNr) : strippedDoc; while (yyextra->commentScanner.parseCommentBlock( yyextra->thisParser, yyextra->docBlockInBody && yyextra->previous ? yyextra->previous.get() : yyextra->current.get(), @@ -7028,7 +7032,8 @@ static void handleCommentBlock(yyscan_t yyscanner,const QCString &doc,bool brief yyextra->docBlockInBody, // isInBody yyextra->protection, position, - needsEntry + needsEntry, + Config_getBool(MARKDOWN_SUPPORT) ) ) { @@ -7087,9 +7092,10 @@ static void handleParametersCommentBlocks(yyscan_t yyscanner,ArgumentList &al) FALSE, yyextra->protection, position, - needsEntry + needsEntry, + Config_getBool(MARKDOWN_SUPPORT) ) - ) + ) { //printf("handleParametersCommentBlock position=%d [%s]\n",position,doc.data()+position); if (needsEntry) newEntry(yyscanner); @@ -7228,8 +7234,7 @@ static void parseMain(yyscan_t yyscanner, const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &rt, - bool sameTranslationUnit, - QStrList & filesInSameTranslationUnit) + ClangTUParser *clangParser) { struct yyguts_t *yyg = (struct yyguts_t*)yyscanner; initParser(yyscanner); @@ -7250,19 +7255,8 @@ static void parseMain(yyscan_t yyscanner, yyextra->yyBegLineNr = 1; yyextra->yyBegColNr = 0; yyextra->yyFileName = fileName; + yyextra->clangParser = clangParser; setContext(yyscanner); - bool processWithClang = yyextra->insideCpp || yyextra->insideObjC; - if (processWithClang) - { - if (!sameTranslationUnit) // new file - { - ClangParser::instance()->start(fileName,filesInSameTranslationUnit); - } - else - { - ClangParser::instance()->switchToFile(fileName); - } - } rt->lang = yyextra->language; msg("Parsing file %s...\n",yyextra->yyFileName.data()); @@ -7399,33 +7393,17 @@ COutlineParser::~COutlineParser() scannerYYlex_destroy(p->yyscanner); } -void COutlineParser::startTranslationUnit(const char *) -{ -} - -void COutlineParser::finishTranslationUnit() -{ - struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; - bool processWithClang = yyextra->insideCpp || yyextra->insideObjC; - if (processWithClang) - { - ClangParser::instance()->finish(); - } -} - void COutlineParser::parseInput(const char *fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList & filesInSameTranslationUnit) + ClangTUParser *clangParser) { struct yyguts_t *yyg = (struct yyguts_t*)p->yyscanner; yyextra->thisParser = this; printlex(yy_flex_debug, TRUE, __FILE__, fileName); - ::parseMain(p->yyscanner, fileName,fileBuf,root, - sameTranslationUnit,filesInSameTranslationUnit); + ::parseMain(p->yyscanner,fileName,fileBuf,root,clangParser); printlex(yy_flex_debug, FALSE, __FILE__, fileName); } diff --git a/src/sqlite3gen.cpp b/src/sqlite3gen.cpp index f767eab..2f72221 100644 --- a/src/sqlite3gen.cpp +++ b/src/sqlite3gen.cpp @@ -1424,7 +1424,11 @@ QCString getSQLDocBlock(const Definition *scope, dynamic_cast<const MemberDef*>(def), doc, FALSE, - FALSE + FALSE, + 0, + FALSE, + FALSE, + Config_getBool(MARKDOWN_SUPPORT) ); XMLCodeGenerator codeGen(t); // create a parse tree visitor for XML @@ -1991,7 +1995,6 @@ static void generateSqlite3ForClass(const ClassDef *cd) DBG_CTX(("-----> ClassDef includeInfo for %s\n", nm.data())); DBG_CTX((" local : %d\n", ii->local)); DBG_CTX((" imported : %d\n", ii->imported)); - DBG_CTX((" indirect : %d\n", ii->indirect)); DBG_CTX(("header: %s\n", ii->fileDef->absFilePath().data())); DBG_CTX((" file_id : %d\n", file_id)); DBG_CTX((" header_id: %d\n", header_id)); @@ -2207,7 +2210,6 @@ static void generateSqlite3ForFile(const FileDef *fd) DBG_CTX(("-----> FileDef includeInfo for %s\n", ii->includeName.data())); DBG_CTX((" local: %d\n", ii->local)); DBG_CTX((" imported: %d\n", ii->imported)); - DBG_CTX((" indirect: %d\n", ii->indirect)); if(ii->fileDef) { DBG_CTX(("include: %s\n", ii->fileDef->absFilePath().data())); @@ -2501,11 +2503,10 @@ static void generateSqlite3ForPage(const PageDef *pd,bool isExample) static sqlite3* openDbConnection() { - QCString outputDirectory = Config_getString(OUTPUT_DIRECTORY); + QCString outputDirectory = Config_getString(SQLITE3_OUTPUT); QDir sqlite3Dir(outputDirectory); sqlite3 *db; int rc; - struct stat buf; rc = sqlite3_initialize(); if (rc != SQLITE_OK) @@ -2514,15 +2515,24 @@ static sqlite3* openDbConnection() return NULL; } + QCString dbFileName = "doxygen_sqlite3.db"; + QFileInfo fi(outputDirectory+"/"+dbFileName); - if (stat (outputDirectory+"/doxygen_sqlite3.db", &buf) == 0) + if (fi.exists()) { - err("doxygen_sqlite3.db already exists! Rename, remove, or archive it to regenerate\n"); - return NULL; + if (Config_getBool(SQLITE3_RECREATE_DB)) + { + QDir().remove(fi.absFilePath()); + } + else + { + err("doxygen_sqlite3.db already exists! Rename, remove, or archive it to regenerate\n"); + return NULL; + } } rc = sqlite3_open_v2( - outputDirectory+"/doxygen_sqlite3.db", + fi.absFilePath().utf8(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0 diff --git a/src/tagreader.cpp b/src/tagreader.cpp index 12010e8..3c493b4 100644 --- a/src/tagreader.cpp +++ b/src/tagreader.cpp @@ -1526,7 +1526,7 @@ void TagFileParser::addIncludes() // ifd->getOutputFileBase().data(),ii->id.data()); if (ifd->getOutputFileBase()==QCString(ii->id)) { - fd->addIncludeDependency(ifd.get(),ii->text,ii->isLocal,ii->isImported,FALSE); + fd->addIncludeDependency(ifd.get(),ii->text,ii->isLocal,ii->isImported); } } } diff --git a/src/template.cpp b/src/template.cpp index 1763eec..c836c6b 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -2843,7 +2843,11 @@ template<class T> class TemplateNodeCreator : public TemplateNode if (d.exists()) { bool ok = d.mkdir(fileName.mid(j,i-j)); - if (!ok) break; + if (!ok) + { + err("Failed to create directory '%s'\n",(fileName.mid(j,i-j)).data()); + break; + } QCString dirName = outputDir+'/'+fileName.left(i); d = QDir(dirName); j = i+1; diff --git a/src/threadpool.h b/src/threadpool.h new file mode 100644 index 0000000..5b3f823 --- /dev/null +++ b/src/threadpool.h @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2020 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#ifndef THREADPOOL_H +#define THREADPOOL_H + +#include <condition_variable> +#include <deque> +#include <functional> +#include <future> +#include <mutex> +#include <thread> +#include <type_traits> +#include <utility> +#include <vector> + +/// Class managing a pool of worker threads. +/// Work can be queued by passing a function to queue(). When the +/// work is done the result of the function will be passed back via a future. +class ThreadPool +{ + public: + /// start N threads in the thread pool. + ThreadPool(std::size_t N=1) + { + for (std::size_t i = 0; i < N; ++i) + { + // each thread is a std::async running thread_task(): + m_finished.push_back( + std::async( + std::launch::async, + [this]{ threadTask(); } + ) + ); + } + } + /// deletes the thread pool by finishing all threads + ~ThreadPool() + { + finish(); + } + + /// Queue the lambda 'task' for the threads to execute. + /// A future of the return type of the lambda is returned to capture the result. + template<class F, class R=std::result_of_t<F&()> > + std::future<R> queue(F&& f) + { + // wrap the function object into a packaged task, splitting + // execution from the return value: + std::packaged_task<R()> p(std::forward<F>(f)); + + auto r=p.get_future(); // get the return value before we hand off the task + { + std::unique_lock<std::mutex> l(m_mutex); + m_work.emplace_back(std::move(p)); // store the task<R()> as a task<void()> + m_cond.notify_one(); // wake a thread to work on the task + } + + return r; // return the future result of the task + } + + /// finish enques a "stop the thread" message for every thread, + /// then waits for them to finish + void finish() + { + { + std::unique_lock<std::mutex> l(m_mutex); + for(auto&& u : m_finished) + { + unused_variable(u); + m_work.push_back({}); + } + } + m_cond.notify_all(); + m_finished.clear(); + } + private: + + // helper to silence the compiler warning about unused variables + template <typename ...Args> + void unused_variable(Args&& ...args) { (void)(sizeof...(args)); } + + // the work that a worker thread does: + void threadTask() + { + while(true) + { + // pop a task off the queue: + std::packaged_task<void()> f; + { + // usual thread-safe queue code: + std::unique_lock<std::mutex> l(m_mutex); + if (m_work.empty()) + { + m_cond.wait(l,[&]{return !m_work.empty();}); + } + f = std::move(m_work.front()); + m_work.pop_front(); + } + // if the task is invalid, it means we are asked to abort + if (!f.valid()) return; + // otherwise, run the task + f(); + } + } + + // the mutex, condition variable and deque form a single + // thread-safe triggered queue of tasks: + std::mutex m_mutex; + std::condition_variable m_cond; + + // note that a packaged_task<void> can store a packaged_task<R>: + std::deque< std::packaged_task<void()> > m_work; + + // this holds futures representing the worker threads being done: + std::vector< std::future<void> > m_finished; +}; + +#endif + diff --git a/src/translator.h b/src/translator.h index 188b775..e3bfb51 100644 --- a/src/translator.h +++ b/src/translator.h @@ -50,6 +50,11 @@ class Translator * can be returned. */ virtual QCString latexFontenc() { return "T1"; } + virtual QCString latexFont() { + return "\\usepackage[scaled=.90]{helvet}\n" + "\\usepackage{courier}\n" + "\\renewcommand{\\familydefault}{\\sfdefault}\n"; + } /*! * Sets the commands to be inserted directly after the `\\begin{document}` * in the LaTeX document. @@ -588,7 +593,6 @@ class Translator virtual QCString trClassMethods() = 0; virtual QCString trInstanceMethods() = 0; virtual QCString trMethodDocumentation() = 0; - virtual QCString trDesignOverview() = 0; ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 diff --git a/src/translator_adapter.h b/src/translator_adapter.h index b0c8a24..fdc68f9 100644 --- a/src/translator_adapter.h +++ b/src/translator_adapter.h @@ -216,9 +216,6 @@ class TranslatorAdapter_1_8_2 : public TranslatorAdapter_1_8_4 virtual QCString trMethodDocumentation() { return english.trMethodDocumentation(); } - - virtual QCString trDesignOverview() - { return english.trDesignOverview(); } }; diff --git a/src/translator_br.h b/src/translator_br.h index 01c5b9f..7c98480 100644 --- a/src/translator_br.h +++ b/src/translator_br.h @@ -2011,15 +2011,6 @@ class TranslatorBrazilian : public Translator return "Documentação do método"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - // I'm not sure how to accurately translate it - return "Visão geral do design"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_cn.h b/src/translator_cn.h index 0e559c1..1036b6b 100644 --- a/src/translator_cn.h +++ b/src/translator_cn.h @@ -1862,14 +1862,6 @@ class TranslatorChinese : public TranslatorAdapter_1_8_15 return "函数文档"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "设计概要"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_cz.h b/src/translator_cz.h index 9d6c489..89f6371 100644 --- a/src/translator_cz.h +++ b/src/translator_cz.h @@ -1977,14 +1977,6 @@ class TranslatorCzech : public TranslatorAdapter_1_8_15 return "Dokumentace metody"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Návrhové schéma"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_de.h b/src/translator_de.h index bf5ce5e..9672fbe 100644 --- a/src/translator_de.h +++ b/src/translator_de.h @@ -2072,14 +2072,6 @@ class TranslatorGerman : public TranslatorAdapter_1_8_15 return "Methodendokumentation"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Übersicht"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_en.h b/src/translator_en.h index 400e59c..a5be968 100644 --- a/src/translator_en.h +++ b/src/translator_en.h @@ -1940,14 +1940,6 @@ class TranslatorEnglish : public Translator return "Method Documentation"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Design Overview"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_eo.h b/src/translator_eo.h index 28876d7..7150f2d 100644 --- a/src/translator_eo.h +++ b/src/translator_eo.h @@ -1933,14 +1933,6 @@ class TranslatorEsperanto : public TranslatorAdapter_1_8_4 return "Dokumentaro de la Metodo"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Fasona Superrigardo"; - } - ////////////////////////////////////////////////////////////////////////// }; diff --git a/src/translator_es.h b/src/translator_es.h index b28ed75..e69afc2 100644 --- a/src/translator_es.h +++ b/src/translator_es.h @@ -1992,14 +1992,6 @@ class TranslatorSpanish : public TranslatorAdapter_1_8_15 return "Método de documentación"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Diseño información general"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_fr.h b/src/translator_fr.h index 0035e23..fc624df 100644 --- a/src/translator_fr.h +++ b/src/translator_fr.h @@ -2001,14 +2001,6 @@ class TranslatorFrench : public TranslatorAdapter_1_8_15 return "Documentation des méthodes"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Vue d'ensemble"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_gr.h b/src/translator_gr.h index 6ed43db..0e1824a 100644 --- a/src/translator_gr.h +++ b/src/translator_gr.h @@ -59,8 +59,18 @@ class TranslatorGreek : public TranslatorAdapter_1_8_15 virtual QCString latexLanguageSupportCommand() { - return "\\usepackage[greek,english]{babel}\n" - "\\usepackage{alphabeta}\n"; + return "\\usepackage{fontspec}\n" + "\\usepackage[greek]{babel}\n"; + } + + virtual QCString latexFontenc() + { + return ""; + } + virtual QCString latexFont() + { + return "\\setmainfont{Libertinus Sans}\n" + "\\setmonofont{Courier New}\n"; } // --- Language translation methods ------------------- @@ -1159,6 +1169,16 @@ class TranslatorGreek : public TranslatorAdapter_1_8_15 return "1253"; } + virtual QCString latexCommandName() + { + QCString latex_command = Config_getString(LATEX_CMD_NAME); + if (latex_command.isEmpty()) latex_command = "latex"; + if (Config_getBool(USE_PDFLATEX)) + { + if (latex_command == "latex") latex_command = "xelatex"; + } + return latex_command; + } /*! Used as ansicpg for RTF fcharset */ @@ -1916,14 +1936,6 @@ class TranslatorGreek : public TranslatorAdapter_1_8_15 return "Τεκμηρίωση Μεθόδου"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Επισκόπηση σχεδίασης"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_hu.h b/src/translator_hu.h index 44363c9..bf326f7 100644 --- a/src/translator_hu.h +++ b/src/translator_hu.h @@ -1955,14 +1955,6 @@ class TranslatorHungarian : public TranslatorAdapter_1_8_15 return "Metódus dokumentáció"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Dizájn áttekintés"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_it.h b/src/translator_it.h index 9638a01..10c4a5a 100644 --- a/src/translator_it.h +++ b/src/translator_it.h @@ -1912,14 +1912,6 @@ class TranslatorItalian : public TranslatorAdapter_1_8_15 return "Documentazione dei metodi"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Panoramica del progetto"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_jp.h b/src/translator_jp.h index fc0d65d..074864e 100644 --- a/src/translator_jp.h +++ b/src/translator_jp.h @@ -1925,14 +1925,6 @@ class TranslatorJapanese : public TranslatorAdapter_1_8_15 return "メソッド詳解"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "デザイン概観"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_kr.h b/src/translator_kr.h index fb1c356..d475411 100644 --- a/src/translator_kr.h +++ b/src/translator_kr.h @@ -1948,14 +1948,6 @@ class TranslatorKorean : public TranslatorAdapter_1_8_15 return "메소드 문서화"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "디자인 개요"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_lv.h b/src/translator_lv.h index bd579da..479ed68 100644 --- a/src/translator_lv.h +++ b/src/translator_lv.h @@ -1936,14 +1936,6 @@ class TranslatorLatvian : public TranslatorAdapter_1_8_4 return "Metožu dokumentācija"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Dizaina pārskats"; - } - ////////////////////////////////////////////////////////////////////////// }; diff --git a/src/translator_nl.h b/src/translator_nl.h index 7cecc7d..f2887c6 100644 --- a/src/translator_nl.h +++ b/src/translator_nl.h @@ -1530,14 +1530,6 @@ class TranslatorDutch : public Translator return "Methode Documentatie"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Ontwerp Overzicht"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_pt.h b/src/translator_pt.h index 970cf45..dfe4027 100644 --- a/src/translator_pt.h +++ b/src/translator_pt.h @@ -1945,15 +1945,6 @@ class TranslatorPortuguese : public Translator return "Documentação do método"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - // I'm not sure how to accurately translate it - return "Visão geral do design"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_ro.h b/src/translator_ro.h index 6f0c197..69fd554 100644 --- a/src/translator_ro.h +++ b/src/translator_ro.h @@ -1943,14 +1943,6 @@ class TranslatorRomanian : public TranslatorAdapter_1_8_15 return "Documentația Metodelor"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Vedere de Ansamblu a Designului"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_ru.h b/src/translator_ru.h index 9d92888..5c87e86 100644 --- a/src/translator_ru.h +++ b/src/translator_ru.h @@ -1904,14 +1904,6 @@ class TranslatorRussian : public TranslatorAdapter_1_8_15 return "Документация метода"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Обзор дизайна"; - } - /////////////////////////////////////////////////////////////////////// // new since 1.8.4 /////////////////////////////////////////////////////////////////////// diff --git a/src/translator_sk.h b/src/translator_sk.h index 9ee8252..760120a 100644 --- a/src/translator_sk.h +++ b/src/translator_sk.h @@ -1907,14 +1907,6 @@ class TranslatorSlovak : public TranslatorAdapter_1_8_15 return "Dokumentácia metódy"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Návrhová schéma"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_sv.h b/src/translator_sv.h index 6277445..a4ff4f6 100644 --- a/src/translator_sv.h +++ b/src/translator_sv.h @@ -2020,14 +2020,6 @@ class TranslatorSwedish : public Translator return "Metoddokumentation"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Designöversikt"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_tw.h b/src/translator_tw.h index 9e9092d..247b128 100644 --- a/src/translator_tw.h +++ b/src/translator_tw.h @@ -1913,14 +1913,6 @@ class TranslatorChinesetraditional : public TranslatorAdapter_1_8_15 return "方法文件"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "設計概述"; - } - ////////////////////////////////////////////////////////////////////////// // new since 1.8.4 ////////////////////////////////////////////////////////////////////////// diff --git a/src/translator_ua.h b/src/translator_ua.h index 034cb1b..7f7656f 100644 --- a/src/translator_ua.h +++ b/src/translator_ua.h @@ -1901,14 +1901,6 @@ class TranslatorUkrainian : public TranslatorAdapter_1_8_4 return "Документація метода"; } - /*! Used as the title of the design overview picture created for the - * VHDL output. - */ - virtual QCString trDesignOverview() - { - return "Огляд дизайну проекту"; - } - ////////////////////////////////////////////////////////////////////////// }; diff --git a/src/util.cpp b/src/util.cpp index d198a5d..aa1acb4 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -22,6 +22,8 @@ #include <cinttypes> #include <string.h> +#include <mutex> +#include <unordered_set> #include "md5.h" @@ -276,22 +278,20 @@ QCString generateMarker(int id) return result; } -static QCString stripFromPath(const QCString &path,QStrList &l) +static QCString stripFromPath(const QCString &path,const StringVector &l) { // look at all the strings in the list and strip the longest match - const char *s=l.first(); QCString potential; unsigned int length = 0; - while (s) + for (const auto &s : l) { - QCString prefix = s; + QCString prefix = s.c_str(); if (prefix.length() > length && qstricmp(path.left(prefix.length()),prefix)==0) // case insensitive compare { length = prefix.length(); potential = path.right(path.length()-prefix.length()); } - s = l.next(); } if (length) return potential; return path; @@ -1664,15 +1664,16 @@ static CharAroundSpace g_charAroundSpace; // Note: this function is not reentrant due to the use of static buffer! QCString removeRedundantWhiteSpace(const QCString &s) { - static bool cliSupport = Config_getBool(CPP_CLI_SUPPORT); - static bool vhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL); + bool cliSupport = Config_getBool(CPP_CLI_SUPPORT); + bool vhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL); if (s.isEmpty() || vhdl) return s; // We use a static character array to // improve the performance of this function - static char *growBuf = 0; - static int growBufLen = 0; + // and thread_local is needed to make it multi-thread safe + static THREAD_LOCAL char *growBuf = 0; + static THREAD_LOCAL int growBufLen = 0; if ((int)s.length()*3>growBufLen) // For input character we produce at most 3 output characters, { growBufLen = s.length()*3; @@ -2375,15 +2376,13 @@ int filterCRLF(char *buf,int len) return dest; // length of the valid part of the buf } -static QCString getFilterFromList(const char *name,const QStrList &filterList,bool &found) +static QCString getFilterFromList(const char *name,const StringVector &filterList,bool &found) { found=FALSE; // compare the file name to the filter pattern list - QStrListIterator sli(filterList); - char* filterStr; - for (sli.toFirst(); (filterStr = sli.current()); ++sli) + for (const auto &filterStr : filterList) { - QCString fs = filterStr; + QCString fs = filterStr.c_str(); int i_equals=fs.find('='); if (i_equals!=-1) { @@ -2417,12 +2416,12 @@ QCString getFileFilter(const char* name,bool isSourceCode) // sanity check if (name==0) return ""; - QStrList& filterSrcList = Config_getList(FILTER_SOURCE_PATTERNS); - QStrList& filterList = Config_getList(FILTER_PATTERNS); + const StringVector& filterSrcList = Config_getList(FILTER_SOURCE_PATTERNS); + const StringVector& filterList = Config_getList(FILTER_PATTERNS); QCString filterName; bool found=FALSE; - if (isSourceCode && !filterSrcList.isEmpty()) + if (isSourceCode && !filterSrcList.empty()) { // first look for source filter pattern list filterName = getFilterFromList(name,filterSrcList,found); } @@ -4480,11 +4479,19 @@ struct FindFileCacheElem static QCache<FindFileCacheElem> g_findFileDefCache(5000); +#if MULTITHREADED_INPUT +static std::mutex g_findFileDefMutex; +#endif + FileDef *findFileDef(const FileNameLinkedMap *fnMap,const char *n,bool &ambig) { ambig=FALSE; if (n==0) return 0; +#if MULTITHREADED_INPUT + std::unique_lock<std::mutex> lock(g_findFileDefMutex); +#endif + const int maxAddrSize = 20; char addr[maxAddrSize]; qsnprintf(addr,maxAddrSize,"%p:",(void*)fnMap); @@ -4623,11 +4630,10 @@ QCString substituteKeywords(const QCString &s,const char *title, int getPrefixIndex(const QCString &name) { if (name.isEmpty()) return 0; - static QStrList &sl = Config_getList(IGNORE_PREFIX); - char *s = sl.first(); - while (s) + const StringVector &sl = Config_getList(IGNORE_PREFIX); + for (const auto &s : sl) { - const char *ps=s; + const char *ps=s.c_str(); const char *pd=name.data(); int i=0; while (*ps!=0 && *pd!=0 && *ps==*pd) ps++,pd++,i++; @@ -4635,7 +4641,6 @@ int getPrefixIndex(const QCString &name) { return i; } - s = sl.next(); } return 0; } @@ -5018,10 +5023,20 @@ void createSubDirs(QDir &d) int l1,l2; for (l1=0;l1<16;l1++) { - d.mkdir(QCString().sprintf("d%x",l1)); + QCString subdir; + subdir.sprintf("d%x",l1); + if (!d.exists(subdir) && !d.mkdir(subdir)) + { + term("Failed to create output directory '%s'\n",subdir.data()); + } for (l2=0;l2<256;l2++) { - d.mkdir(QCString().sprintf("d%x/d%02x",l1,l2)); + QCString subsubdir; + subsubdir.sprintf("d%x/d%02x",l1,l2); + if (!d.exists(subsubdir) && !d.mkdir(subsubdir)) + { + term("Failed to create output directory '%s'\n",subsubdir.data()); + } } } } @@ -5268,6 +5283,16 @@ QCString convertToId(const char *s) return growBuf.get(); } +/*! Some strings have been corrected but the requirement regarding the fact + * that an id cannot have a digit at the first position. To overcome problems + * with double labels we always place an "a" in front + */ +QCString correctId(QCString s) +{ + if (s.isEmpty()) return s; + return "a" + s; +} + /*! Converts a string to an XML-encoded string */ QCString convertToXML(const char *s, bool keepEntities) { @@ -6587,10 +6612,11 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine) // search for leading empty lines int i=0,li=-1,l=s.length(); char c; - while ((c=*p++)) + while ((c=*p)) { - if (c==' ' || c=='\t' || c=='\r') i++; - else if (c=='\n') i++,li=i,docLine++; + if (c==' ' || c=='\t' || c=='\r') i++,p++; + else if (c=='\\' && qstrncmp(p,"\\ilinebr",8)==0) i+=8,li=i,docLine++,p+=8; + else if (c=='\n') i++,li=i,docLine++,p++; else break; } @@ -6599,9 +6625,10 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine) p=s.data()+b; while (b>=0) { - c=*p; p--; - if (c==' ' || c=='\t' || c=='\r') b--; - else if (c=='\n') bi=b,b--; + c=*p; + if (c==' ' || c=='\t' || c=='\r') b--,p--; + else if (c=='r' && b>=7 && qstrncmp(p-7,"\\ilinebr",8)==0) bi=b-7,b-=8,p-=8; + else if (c=='\n') bi=b,b--,p--; else break; } @@ -6612,6 +6639,7 @@ QCString stripLeadingAndTrailingEmptyLines(const QCString &s,int &docLine) if (bi==-1) bi=l; if (li==-1) li=0; if (bi<=li) return 0; // only empty lines + //printf("docLine='%s' len=%d li=%d bi=%d\n",s.data(),s.length(),li,bi); return s.mid(li,bi-li); } @@ -6963,7 +6991,8 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md, if (doc.isEmpty()) return s.data(); FTextStream t(&s); DocNode *root = validatingParseDoc(fileName,lineNr, - (Definition*)scope,(MemberDef*)md,doc,FALSE,FALSE); + (Definition*)scope,(MemberDef*)md,doc,FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); TextDocVisitor *visitor = new TextDocVisitor(t); root->accept(visitor); delete visitor; @@ -6998,9 +7027,8 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md, //-------------------------------------------------------------------------------------- -static QDict<void> aliasesProcessed; - -static QCString expandAliasRec(const QCString s,bool allowRecursion=FALSE); +static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed, + const QCString s,bool allowRecursion=FALSE); struct Marker { @@ -7042,7 +7070,8 @@ static int findEndOfCommand(const char *s) * with the corresponding values found in the comma separated argument * list \a argList and the returns the result after recursive alias expansion. */ -static QCString replaceAliasArguments(const QCString &aliasValue,const QCString &argList) +static QCString replaceAliasArguments(StringUnorderedSet &aliasesProcessed, + const QCString &aliasValue,const QCString &argList) { //printf("----- replaceAliasArguments(val=[%s],args=[%s])\n",aliasValue.data(),argList.data()); @@ -7122,7 +7151,7 @@ static QCString replaceAliasArguments(const QCString &aliasValue,const QCString //printf("part before marker %d: '%s'\n",i,aliasValue.mid(p,m->pos-p).data()); if (m->number>0 && m->number<=(int)args.count()) // valid number { - result+=expandAliasRec(*args.at(m->number-1),TRUE); + result+=expandAliasRec(aliasesProcessed,*args.at(m->number-1),TRUE); //printf("marker index=%d pos=%d number=%d size=%d replacement %s\n",i,m->pos,m->number,m->size, // args.at(m->number-1)->data()); } @@ -7134,7 +7163,7 @@ static QCString replaceAliasArguments(const QCString &aliasValue,const QCString // expand the result again result = substitute(result,"\\{","{"); result = substitute(result,"\\}","}"); - result = expandAliasRec(substitute(result,"\\,",",")); + result = expandAliasRec(aliasesProcessed,substitute(result,"\\,",",")); return result; } @@ -7161,7 +7190,7 @@ static QCString escapeCommas(const QCString &s) return result.data(); } -static QCString expandAliasRec(const QCString s,bool allowRecursion) +static QCString expandAliasRec(StringUnorderedSet &aliasesProcessed,const QCString s,bool allowRecursion) { QCString result; static QRegExp cmdPat("[\\\\@][a-z_A-Z][a-z_A-Z0-9]*"); @@ -7194,19 +7223,20 @@ static QCString expandAliasRec(const QCString s,bool allowRecursion) } //printf("Found command s='%s' cmd='%s' numArgs=%d args='%s' aliasText=%s\n", // s.data(),cmd.data(),numArgs,args.data(),aliasText?aliasText->data():"<none>"); - if ((allowRecursion || aliasesProcessed.find(cmd)==0) && aliasText) // expand the alias + if ((allowRecursion || aliasesProcessed.find(cmd.str())==aliasesProcessed.end()) && + aliasText) // expand the alias { //printf("is an alias!\n"); - if (!allowRecursion) aliasesProcessed.insert(cmd,(void *)0x8); + if (!allowRecursion) aliasesProcessed.insert(cmd.str()); QCString val = *aliasText; if (hasArgs) { - val = replaceAliasArguments(val,args); + val = replaceAliasArguments(aliasesProcessed,val,args); //printf("replace '%s'->'%s' args='%s'\n", // aliasText->data(),val.data(),args.data()); } - result+=expandAliasRec(val); - if (!allowRecursion) aliasesProcessed.remove(cmd); + result+=expandAliasRec(aliasesProcessed,val); + if (!allowRecursion) aliasesProcessed.erase(cmd.str()); p=i+l; if (hasArgs) p+=argsLen+2; } @@ -7276,9 +7306,9 @@ QCString extractAliasArgs(const QCString &args,int pos) QCString resolveAliasCmd(const QCString aliasCmd) { QCString result; - aliasesProcessed.clear(); + StringUnorderedSet aliasesProcessed; //printf("Expanding: '%s'\n",aliasCmd.data()); - result = expandAliasRec(aliasCmd); + result = expandAliasRec(aliasesProcessed,aliasCmd); //printf("Expanding result: '%s'->'%s'\n",aliasCmd.data(),result.data()); return result; } @@ -7286,12 +7316,12 @@ QCString resolveAliasCmd(const QCString aliasCmd) QCString expandAlias(const QCString &aliasName,const QCString &aliasValue) { QCString result; - aliasesProcessed.clear(); + StringUnorderedSet aliasesProcessed; // avoid expanding this command recursively - aliasesProcessed.insert(aliasName,(void *)0x8); + aliasesProcessed.insert(aliasName.str()); // expand embedded commands //printf("Expanding: '%s'->'%s'\n",aliasName.data(),aliasValue.data()); - result = expandAliasRec(aliasValue); + result = expandAliasRec(aliasesProcessed,aliasValue); //printf("Expanding result: '%s'->'%s'\n",aliasName.data(),result.data()); return result; } @@ -7309,7 +7339,8 @@ void writeTypeConstraints(OutputList &ol,const Definition *d,const ArgumentList linkifyText(TextGeneratorOLImpl(ol),d,0,0,a.type); ol.endConstraintType(); ol.startConstraintDocs(); - ol.generateDoc(d->docFile(),d->docLine(),d,0,a.docs,TRUE,FALSE); + ol.generateDoc(d->docFile(),d->docLine(),d,0,a.docs,TRUE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endConstraintDocs(); } ol.endConstraintList(); @@ -7496,9 +7527,9 @@ QCString filterTitle(const QCString &title) // returns TRUE if the name of the file represented by 'fi' matches // one of the file patterns in the 'patList' list. -bool patternMatch(const QFileInfo &fi,const QStrList *patList) +bool patternMatch(const QFileInfo &fi,const StringVector &patList) { - static bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES); + bool caseSenseNames = Config_getBool(CASE_SENSE_NAMES); bool found = FALSE; // For platforms where the file system is non case sensitive overrule the setting @@ -7507,17 +7538,15 @@ bool patternMatch(const QFileInfo &fi,const QStrList *patList) caseSenseNames = FALSE; } - if (patList) + if (!patList.empty()) { - QStrListIterator it(*patList); - QCString pattern; - QCString fn = fi.fileName().data(); QCString fp = fi.filePath().data(); QCString afp= fi.absFilePath().data(); - for (it.toFirst();(pattern=it.current());++it) + for (const auto &pat: patList) { + QCString pattern = pat.c_str(); if (!pattern.isEmpty()) { int i=pattern.find('='); @@ -8108,20 +8137,22 @@ bool classVisibleInIndex(const ClassDef *cd) QCString extractDirection(QCString &docs) { - QRegExp re("\\[[^\\]]+\\]"); // [...] + QRegExp re("\\[[ inout,]+\\]"); // [...] int l=0; - if (re.match(docs,0,&l)==0) + if (re.match(docs,0,&l)==0 && l>2) { - int inPos = docs.find("in", 1,FALSE); - int outPos = docs.find("out",1,FALSE); - bool input = inPos!=-1 && inPos<l; - bool output = outPos!=-1 && outPos<l; - if (input || output) // in,out attributes + // make dir the part inside [...] without separators + QCString dir=substitute(substitute(docs.mid(1,l-2)," ",""),",",""); + int inIndex, outIndex; + unsigned char ioMask=0; + if (( inIndex=dir.find( "in"))!=-1) dir.remove (inIndex,2),ioMask|=(1<<0); + if ((outIndex=dir.find("out"))!=-1) dir.remove(outIndex,3),ioMask|=(1<<1); + if (dir.isEmpty() && ioMask!=0) // only in and/or out attributes found { docs = docs.mid(l); // strip attributes - if (input && output) return "[in,out]"; - else if (input) return "[in]"; - else if (output) return "[out]"; + if (ioMask==((1<<0)|(1<<1))) return "[in,out]"; + else if (ioMask==(1<<0)) return "[in]"; + else if (ioMask==(1<<1)) return "[out]"; } } return QCString(); @@ -8358,18 +8389,16 @@ bool openOutputFile(const char *outFile,QFile &f) void writeExtraLatexPackages(FTextStream &t) { // User-specified packages - QStrList &extraPackages = Config_getList(EXTRA_PACKAGES); - if (!extraPackages.isEmpty()) + const StringVector &extraPackages = Config_getList(EXTRA_PACKAGES); + if (!extraPackages.empty()) { t << "% Packages requested by user\n"; - const char *pkgName=extraPackages.first(); - while (pkgName) + for (const auto &pkgName : extraPackages) { if ((pkgName[0] == '[') || (pkgName[0] == '{')) - t << "\\usepackage" << pkgName << "\n"; + t << "\\usepackage" << pkgName.c_str() << "\n"; else - t << "\\usepackage{" << pkgName << "}\n"; - pkgName=extraPackages.next(); + t << "\\usepackage{" << pkgName.c_str() << "}\n"; } t << "\n"; } @@ -31,6 +31,7 @@ #include "docparser.h" #include "classdef.h" #include "arguments.h" +#include "containers.h" //-------------------------------------------------------------------- @@ -277,6 +278,7 @@ QCString insertTemplateSpecifierInScope(const QCString &scope,const QCString &te QCString stripScope(const char *name); QCString convertToId(const char *s); +QCString correctId(QCString s); QCString convertToHtml(const char *s,bool keepEntities=TRUE); @@ -436,7 +438,7 @@ bool readInputFile(const char *fileName,BufStr &inBuf, bool filter=TRUE,bool isSourceCode=FALSE); QCString filterTitle(const QCString &title); -bool patternMatch(const QFileInfo &fi,const QStrList *patList); +bool patternMatch(const QFileInfo &fi,const StringVector &patList); QCString externalLinkTarget(const bool parent = false); QCString externalRef(const QCString &relPath,const QCString &ref,bool href); diff --git a/src/vhdldocgen.cpp b/src/vhdldocgen.cpp index 380c77b..8e311b7 100644 --- a/src/vhdldocgen.cpp +++ b/src/vhdldocgen.cpp @@ -2165,8 +2165,9 @@ void VhdlDocGen::writeVHDLDeclaration(const MemberDef* mdef,OutputList &ol, QCString s=mdef->briefDescription(); ol.startMemberDescription(mdef->anchor(), NULL, mm == VhdlDocGen::PORT); ol.generateDoc(mdef->briefFile(),mdef->briefLine(), - mdef->getOuterScope()?mdef->getOuterScope():d, - mdef,s.data(),TRUE,FALSE,0,TRUE,FALSE); + mdef->getOuterScope()?mdef->getOuterScope():d, + mdef,s.data(),TRUE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); if (detailsVisible) { ol.pushGeneratorState(); @@ -2270,7 +2271,8 @@ void VhdlDocGen::writeVHDLDeclarations(const MemberList* ml,OutputList &ol, if (subtitle && subtitle[0]!=0) { ol.startMemberSubtitle(); - ol.generateDoc("[generated]",-1,0,0,subtitle,FALSE,FALSE,0,TRUE,FALSE); + ol.generateDoc("[generated]",-1,0,0,subtitle,FALSE,FALSE, + 0,TRUE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberSubtitle(); } //printf("memberGroupList=%p\n",memberGroupList); @@ -2296,7 +2298,8 @@ void VhdlDocGen::writeVHDLDeclarations(const MemberList* ml,OutputList &ol, { //printf("Member group has docs!\n"); ol.startMemberGroupDocs(); - ol.generateDoc("[generated]",-1,0,0,mg->documentation()+"\n",FALSE,FALSE); + ol.generateDoc("[generated]",-1,0,0,mg->documentation()+"\n",FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); ol.endMemberGroupDocs(); } ol.startMemberGroup(); @@ -2936,13 +2939,11 @@ void VhdlDocGen::createFlowChart(const MemberDef *mdef) bool b=readCodeFragment( fd->absFilePath().data(), actualStart,actualEnd,codeFragment); if (!b) return; - VHDLOutlineParser &intf =dynamic_cast<VHDLOutlineParser&>(Doxygen::parserManager->getOutlineParser(".vhd")); + auto parser { Doxygen::parserManager->getOutlineParser(".vhd") }; VhdlDocGen::setFlowMember(mdef); std::shared_ptr<Entry> root = std::make_shared<Entry>(); - QStrList filesInSameTu; - intf.startTranslationUnit(""); - intf.parseInput("",codeFragment.data(),root,FALSE,filesInSameTu); - intf.finishTranslationUnit(); + StringVector filesInSameTu; + parser->parseInput("",codeFragment.data(),root,nullptr); } void VhdlDocGen::resetCodeVhdlParserState() @@ -3171,20 +3172,18 @@ void FlowChart::printFlowTree() void FlowChart::colTextNodes() { - QCString text; - FlowChart *flno; + FlowChart *flno = NULL; bool found=FALSE; for (uint j=0;j<flowList.count();j++) { FlowChart *flo=flowList.at(j); if (flo->type&TEXT_NO) { - text+=flo->text+'\n'; if (!found) { flno=flo; } - if (found) + else { flno->text+=flo->text; flowList.remove(flo); @@ -3524,12 +3523,11 @@ void FlowChart::printUmlTree() } qcs+="\n"; - QCString & htmlOutDir = Config_getString(HTML_OUTPUT); + QCString htmlOutDir = Config_getString(HTML_OUTPUT); QCString n=convertNameToFileName(); - QCString tmp=htmlOutDir; - n=PlantumlManager::instance()->writePlantUMLSource(tmp,n,qcs,PlantumlManager::PUML_SVG); - PlantumlManager::instance()->generatePlantUMLOutput(n.data(),tmp.data(),PlantumlManager::PUML_SVG); + n=PlantumlManager::instance()->writePlantUMLSource(htmlOutDir,n,qcs,PlantumlManager::PUML_SVG); + PlantumlManager::instance()->generatePlantUMLOutput(n,htmlOutDir,PlantumlManager::PUML_SVG); } QCString FlowChart::convertNameToFileName() @@ -3638,9 +3636,8 @@ void FlowChart::writeFlowChart() #ifdef DEBUGFLOW printFlowTree(); #endif - const MemberDef *p=VhdlDocGen::getFlowMember(); - if (p->isStatic()) + if (!Config_getString(PLANTUML_JAR_PATH).isEmpty()) { printUmlTree(); delFlowList(); diff --git a/src/vhdljjparser.cpp b/src/vhdljjparser.cpp index ea60dd6..7c83d52 100644 --- a/src/vhdljjparser.cpp +++ b/src/vhdljjparser.cpp @@ -81,6 +81,7 @@ struct VHDLOutlineParser::Private VHDLDocInfo str_doc; VhdlParser::SharedState shared; QCString forL; + int code = 0; }; @@ -125,7 +126,7 @@ VHDLOutlineParser::~VHDLOutlineParser() } void VHDLOutlineParser::parseInput(const char *fileName,const char *fileBuf, - const std::shared_ptr<Entry> &root, bool ,QStrList&) + const std::shared_ptr<Entry> &root, ClangTUParser *) { VhdlParser::SharedState *s = &p->shared; p->thisParser=this; @@ -264,34 +265,128 @@ void VHDLOutlineParser::handleFlowComment(const char* doc) } } +int VHDLOutlineParser::checkInlineCode(QCString &doc) +{ + QRegExp cs("[\\\\@]code"); + QRegExp cend("[\\s ]*[\\\\@]endcode"); + QRegExp cbrief("[\\\\@]brief"); + int index = doc.find(cs); + + if (doc.contains(cend) > 0) + return 1; + + if (index < 0) + return index; + + VhdlParser::SharedState *s = &p->shared; + p->strComment += doc; + p->code = p->inputString.find(cs, p->code + 1); + int com = p->inputString.find(p->strComment.data()); + int ref = p->inputString.find(cend, p->code + 1); + int len = p->strComment.size(); + + int ll = com + len; + int diff = ref - ll - 3; + QCString code = p->inputString.mid(ll, diff); + int iLine = 0; + code = stripLeadingAndTrailingEmptyLines(code, iLine); + int val = code.contains('\n'); + VhdlDocGen::prepareComment(p->strComment); + QCStringList ql = QCStringList::split('\n', p->strComment); + + QCString co; + QCString na; + for (QCString qcs : ql) + { + qcs = qcs.simplifyWhiteSpace(); + if (qcs.contains(cs)) + { + int i = qcs.find('{'); + int j = qcs.find('}'); + if (i > 0 && j > 0 && j > i) + { + na = qcs.mid(i + 1, (j - i - 1)); + } + continue; + } + qcs = qcs.replace(cbrief, ""); + co += qcs; + co += '\n'; + } + + VhdlDocGen::prepareComment(co); + + Entry gBlock; + if (!na.isEmpty()) + gBlock.name = na; + else + gBlock.name = "misc" + VhdlDocGen::getRecordNumber(); + gBlock.startLine = p->yyLineNr+iLine-1; + gBlock.bodyLine = p->yyLineNr+iLine-1 ; + gBlock.doc = code; + gBlock.inbodyDocs = code; + gBlock.brief = co; + gBlock.section = Entry::VARIABLE_SEC; + gBlock.spec = VhdlDocGen::MISCELLANEOUS; + gBlock.fileName = p->yyFileName; + gBlock.endBodyLine = p->yyLineNr + val +iLine; + gBlock.lang = SrcLangExt_VHDL; + std::shared_ptr<Entry> compound; + + if (s->lastEntity) + compound = s->lastEntity; + else if (s->lastCompound) + compound = s->lastCompound; + else + compound = 0; + + if (compound) + { + compound->copyToSubEntry(&gBlock); + } + else + { + gBlock.type = "misc"; // global code like library ieee... + s->current_root->copyToSubEntry(&gBlock); + } + p->strComment.resize(0); + return 1; +} -void VHDLOutlineParser::handleCommentBlock(const char* doc1,bool brief) +void VHDLOutlineParser::handleCommentBlock(const char *doc1, bool brief) { + int position = 0; + bool needsEntry = FALSE; VhdlParser::SharedState *s = &p->shared; QCString doc = doc1; - if (doc.isEmpty()) return; - if (checkMultiComment(doc,p->yyLineNr)) + if (doc.isEmpty()) + return; + + if (checkMultiComment(doc, p->yyLineNr)) { p->strComment.resize(0); return; } - VhdlDocGen::prepareComment(doc); + if (checkInlineCode(doc) > 0) + { + return; + } - Protection protection=Public; + Protection protection = Public; + VhdlDocGen::prepareComment(doc); - if (p->oldEntry==s->current.get()) + if (p->oldEntry == s->current.get()) { - //printf("\n find pending message < %s > at line: %d \n ",doc.data(),iDocLine); - p->str_doc.doc=doc; - p->str_doc.iDocLine=p->iDocLine; - p->str_doc.brief=brief; - p->str_doc.pending=TRUE; + p->str_doc.doc = doc; + p->str_doc.iDocLine = p->iDocLine; + p->str_doc.brief = brief; + p->str_doc.pending = TRUE; return; } - p->oldEntry=s->current.get(); + p->oldEntry = s->current.get(); if (brief) { @@ -302,45 +397,41 @@ void VHDLOutlineParser::handleCommentBlock(const char* doc1,bool brief) s->current->docLine = p->yyLineNr; } - int j=doc.find("[plant]"); - if (j>=0) - { - doc=doc.remove(j,7); - s->current->stat=true; - } - int position=0; - bool needsEntry=FALSE; - QCString processedDoc = processMarkdownForCommentBlock(doc,p->yyFileName,p->iDocLine); + + Markdown markdown(p->yyFileName,p->iDocLine); + int lineNr = p->iDocLine; + QCString processedDoc = Config_getBool(MARKDOWN_SUPPORT) ? markdown.process(doc,lineNr) : doc; + while (p->commentScanner.parseCommentBlock( - p->thisParser, - s->current.get(), - processedDoc, // text - p->yyFileName, // file - p->iDocLine, // line of block start - brief, - 0, - FALSE, - protection, - position, - needsEntry - ) - ) - { - if (needsEntry) newEntry(); + p->thisParser, + s->current.get(), + processedDoc, // text + p->yyFileName, // file + lineNr, // line of block start + brief, + 0, + FALSE, + protection, + position, + needsEntry, + Config_getBool(MARKDOWN_SUPPORT))) + { + if (needsEntry) + newEntry(); } if (needsEntry) { if (p->varr) { - p->varr=FALSE; - s->current->name=p->varName; - s->current->section=Entry::VARIABLEDOC_SEC; - p->varName=""; + p->varr = FALSE; + s->current->name = p->varName; + s->current->section = Entry::VARIABLEDOC_SEC; + p->varName = ""; } newEntry(); } - p->iDocLine=-1; + p->iDocLine = -1; p->strComment.resize(0); } diff --git a/src/vhdljjparser.h b/src/vhdljjparser.h index c4a55de..651221c 100755 --- a/src/vhdljjparser.h +++ b/src/vhdljjparser.h @@ -32,20 +32,17 @@ class VHDLOutlineParser : public OutlineParserInterface public: VHDLOutlineParser(); virtual ~VHDLOutlineParser(); - void startTranslationUnit(const char *) {} - void finishTranslationUnit() {} void parseInput(const char * fileName, const char *fileBuf, const std::shared_ptr<Entry> &root, - bool sameTranslationUnit, - QStrList &filesInSameTranslationUnit); + ClangTUParser *clangParser); bool needsPreprocessing(const QCString &) const { return TRUE; } void parsePrototype(const char *text); // interface for generated parser code - + void setLineParsed(int tok); int getLine(int tok); int getLine(); @@ -72,6 +69,7 @@ class VHDLOutlineParser : public OutlineParserInterface bool checkMultiComment(QCString& qcs,int line); void insertEntryAtLine(std::shared_ptr<Entry> ce,int line); QString getNameID(); + int checkInlineCode(QCString & doc); private: struct Private; std::unique_ptr<Private> p; diff --git a/src/xmlgen.cpp b/src/xmlgen.cpp index 3a649e9..b04297f 100644 --- a/src/xmlgen.cpp +++ b/src/xmlgen.cpp @@ -401,7 +401,8 @@ static void writeXMLDocBlock(FTextStream &t, QCString stext = text.stripWhiteSpace(); if (stext.isEmpty()) return; // convert the documentation string into an abstract syntax tree - DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,text,FALSE,FALSE); + DocNode *root = validatingParseDoc(fileName,lineNr,scope,md,text,FALSE,FALSE, + 0,FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT)); // create a code generator XMLCodeGenerator *xmlCodeGen = new XMLCodeGenerator(t); // create a parse tree visitor for XML @@ -1150,7 +1151,8 @@ static void writeInnerNamespaces(const NamespaceSDict *nl,FTextStream &t) if (!nd->isHidden() && !nd->isAnonymous()) { t << " <innernamespace refid=\"" << nd->getOutputFileBase() - << "\">" << convertToXML(nd->name()) << "</innernamespace>" << endl; + << "\"" << (nd->isInline() ? " inline=\"yes\"" : "") + << ">" << convertToXML(nd->name()) << "</innernamespace>" << endl; } } } @@ -1458,7 +1460,9 @@ static void generateXMLForNamespace(const NamespaceDef *nd,FTextStream &ti) writeXMLHeader(t); t << " <compounddef id=\"" << nd->getOutputFileBase() - << "\" kind=\"namespace\" language=\"" + << "\" kind=\"namespace\" " + << (nd->isInline()?"inline=\"yes\" ":"") + << "language=\"" << langToString(nd->getLanguage()) << "\">" << endl; t << " <compoundname>"; writeXMLString(t,nd->name()); |