/****************************************************************************** * * 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 * 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. * */ /** @file * @brief Example of how to use doxygen as part of another GPL applications * * This example shows how to configure and run doxygen programmatically from * within an application without generating the usual output. * The example should work on any Unix like OS (including Linux and Mac OS X). * * This example shows how to use to code parser to get cross-references information * and it also shows how to look up symbols in a program parsed by doxygen and * show some information about them. */ #include #include #include #include "doxygen.h" #include "outputgen.h" #include "parserintf.h" #include "classdef.h" #include "namespacedef.h" #include "filedef.h" #include "util.h" #include "classlist.h" #include "config.h" #include "filename.h" #include class XRefDummyCodeGenerator : public CodeOutputInterface { public: XRefDummyCodeGenerator(FileDef *fd) : m_fd(fd) {} ~XRefDummyCodeGenerator() {} // these are just null functions, they can be used to produce a syntax highlighted // and cross-linked version of the source code, but who needs that anyway ;-) void codify(const char *) {} void writeCodeLink(const char *, const char *, const char *, const char *, const char *) {} void writeLineNumber(const char *, const char *, const char *, int) {} virtual void writeTooltip(const char *, const DocLinkInfo &, const char *, const char *, const SourceLinkInfo &, const SourceLinkInfo &) {} void startCodeLine(bool) {} void endCodeLine() {} void startCodeAnchor(const char *) {} void endCodeAnchor() {} void startFontClass(const char *) {} void endFontClass() {} void writeCodeAnchor(const char *) {} void setCurrentDoc(Definition *, const char *, bool) {} void addWord(const char *, bool) {} // here we are presented with the symbols found by the code parser void linkableSymbol(int l, const char *sym, Definition *symDef, Definition *context) { QCString ctx; if (context) // the context of the symbol is known { if (context->definitionType() == Definition::TypeMember) // it is inside a member { Definition *parentContext = context->getOuterScope(); if (parentContext && parentContext->definitionType() == Definition::TypeClass) // it is inside a member of a class { ctx.sprintf("inside %s %s of %s %s", ((MemberDef *)context)->memberTypeName().data(), context->name().data(), ((ClassDef *)parentContext)->compoundTypeString().data(), parentContext->name().data()); } else if (parentContext == Doxygen::globalScope) // it is inside a global member { ctx.sprintf("inside %s %s", ((MemberDef *)context)->memberTypeName().data(), context->name().data()); } } if (ctx.isEmpty()) // it is something else (class, or namespace member, ...) { ctx.sprintf("in %s", context->name().data()); } } printf("Found symbol %s at line %d of %s %s\n", sym, l, m_fd->getDefFileName().data(), ctx.data()); if (symDef && context) // in this case the definition of the symbol is // known to doxygen. { printf("-> defined at line %d of %s\n", symDef->getDefLine(), symDef->getDefFileName().data()); } } private: FileDef *m_fd; }; static void findXRefSymbols(FileDef *fd) { // get the interface to a parser that matches the file extension ParserInterface *pIntf = Doxygen::parserManager->getParser(fd->getDefFileExtension()); // get the programming language from the file name SrcLangExt lang = getLanguageFromFileName(fd->name()); // reset the parsers state pIntf->resetCodeParserState(); // create a new backend object XRefDummyCodeGenerator *xrefGen = new XRefDummyCodeGenerator(fd); // parse the source code pIntf->parseCode(*xrefGen, 0, fileToString(fd->absFilePath()), lang, FALSE, 0, fd); // dismiss the object. delete xrefGen; } static void listSymbol(Definition *d) { if (d != Doxygen::globalScope && // skip the global namespace symbol d->name().at(0) != '@' // skip anonymous stuff ) { printf("%s\n", d->name().data()); } } static void listSymbols() { QDictIterator sli(*Doxygen::symbolMap); DefinitionIntf *di; for (sli.toFirst(); (di = sli.current()); ++sli) { if (di->definitionType() == DefinitionIntf::TypeSymbolList) // list of symbols // with same name { DefinitionListIterator dli(*(DefinitionList *)di); Definition *d; // for each symbol for (dli.toFirst(); (d = dli.current()); ++dli) { listSymbol(d); } } else // single symbol { listSymbol((Definition *)di); } } } static void lookupSymbol(Definition *d) { if (d != Doxygen::globalScope && // skip the global namespace symbol d->name().at(0) != '@' // skip anonymous stuff ) { printf("Symbol info\n"); printf("-----------\n"); printf("Name: %s\n", d->name().data()); //printf("File: %s\n", d->getDefFileName().data()); printf("Line: %d\n", d->getDefLine()); // depending on the definition type we can case to the appropriate // derived to get additional information switch (d->definitionType()) { case Definition::TypeClass: { ClassDef *cd = (ClassDef *)d; printf("Kind: %s\n", cd->compoundTypeString().data()); } break; case Definition::TypeFile: { FileDef *fd = (FileDef *)d; printf("Kind: File: #includes %d other files\n", fd->includeFileList() ? fd->includeFileList()->count() : 0); } break; case Definition::TypeNamespace: { NamespaceDef *nd = (NamespaceDef *)d; printf("Kind: Namespace: contains %d classes and %d namespaces\n", nd->getClassSDict() ? nd->getClassSDict()->count() : 0, nd->getNamespaceSDict() ? nd->getNamespaceSDict()->count() : 0); } break; case Definition::TypeMember: { MemberDef *md = (MemberDef *)d; MemberSDict *referenced_members = md->getReferencesMembers(); printf("Kind: %s\n", md->memberTypeName().data()); if(referenced_members == NULL) { printf("getReferencesMembers returns NULL\n"); } else { MemberSDict::Iterator msdi(*referenced_members); MemberDef *rmd; for (msdi.toFirst(); (rmd=msdi.current()); ++msdi) { printf("Defined in class: %s\n", md->getClassDef()->name().data()); } } } break; default: // ignore groups/pages/packages/dirs for now break; } } } static void lookupSymbols(const QCString &sym) { if (!sym.isEmpty()) { DefinitionIntf *di = Doxygen::symbolMap->find(sym); if (di) { if (di->definitionType() == DefinitionIntf::TypeSymbolList) { DefinitionListIterator dli(*(DefinitionList *)di); Definition *d; // for each symbol with the given name for (dli.toFirst(); (d = dli.current()); ++dli) { lookupSymbol(d); } } else { lookupSymbol((Definition *)di); } } else { printf("Unknown symbol\n"); } } } int main(int argc, char **argv) { char cmd[256]; if (argc < 2) { printf("Usage: %s [source_file | source_dir]\n", argv[0]); exit(1); } // initialize data structures initDoxygen(); // check and finialize the configuration checkConfiguration(); adjustConfiguration(); // setup the non-default configuration options // we need a place to put intermediate files Config_getString(OUTPUT_DIRECTORY) = "/tmp/doxygen"; // enable HTML (fake) output to omit warning about missing output format Config_getBool(GENERATE_HTML) = TRUE; // disable latex output Config_getBool(GENERATE_LATEX) = FALSE; // be quiet Config_getBool(QUIET) = TRUE; // turn off warnings Config_getBool(WARNINGS) = FALSE; Config_getBool(WARN_IF_UNDOCUMENTED) = FALSE; Config_getBool(WARN_IF_DOC_ERROR) = FALSE; // Extract as much as possible Config_getBool(EXTRACT_ALL) = TRUE; Config_getBool(EXTRACT_STATIC) = TRUE; Config_getBool(EXTRACT_PRIVATE) = TRUE; Config_getBool(EXTRACT_LOCAL_METHODS) = TRUE; // Extract source browse information, needed // to make doxygen gather the cross reference info Config_getBool(SOURCE_BROWSER) = TRUE; // find functions call between modules Config_getBool(CALL_GRAPH) = TRUE; // loop recursive over input files Config_getBool(RECURSIVE) = TRUE; // set the input Config_getList(INPUT).append(argv[1]); // parse the files parseInput(); // iterate over the input files FileNameListIterator fnli(*Doxygen::inputNameList); FileName *fn; // foreach file with a certain name for (fnli.toFirst(); (fn = fnli.current()); ++fnli) { FileNameIterator fni(*fn); FileDef *fd; // for each file definition for (; (fd = fni.current()); ++fni) { // get the references (linked and unlinked) found in this file findXRefSymbols(fd); } } // remove temporary files if (!Doxygen::objDBFileName.isEmpty()) QFile::remove(Doxygen::objDBFileName); if (!Doxygen::entryDBFileName.isEmpty()) QFile::remove(Doxygen::entryDBFileName); // clean up after us QDir().rmdir("/tmp/doxygen"); while (1) { printf("> Type a symbol name or\n> .list for a list of symbols or\n> .quit to exit\n> "); fgets(cmd, 256, stdin); QCString s(cmd); if (s.at(s.length() - 1) == '\n') s = s.left(s.length() - 1); // strip trailing \n if (s == ".list") listSymbols(); else if (s == ".quit") exit(0); else lookupSymbols(s); } }