/****************************************************************************** * * Copyright (C) 1997-2012 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. * */ #include #include #include "settings.h" #include "message.h" #if USE_SQLITE3 #include "qtbc.h" #include "sqlite3gen.h" #include "doxygen.h" #include "config.h" #include "util.h" #include "docparser.h" #include "language.h" #include "dot.h" #include "arguments.h" #include "classlist.h" #include "filedef.h" #include "namespacedef.h" #include "filename.h" #include "groupdef.h" #include "pagedef.h" #include "dirdef.h" #include #include #include //#define DBG_CTX(x) printf x #define DBG_CTX(x) do { } while(0) const char * schema_queries[][2] = { { "includes", "CREATE TABLE IF NOT EXISTS includes (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "local INTEGER NOT NULL," "id_src INTEGER NOT NULL REFERENCES files(id) ON UPDATE CASCADE," "id_dst INTEGER NOT NULL REFERENCES files(id) ON UPDATE CASCADE)" }, { "innerclass", "CREATE TABLE IF NOT EXISTS innerclass (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "refid TEXT NOT NULL," "prot INTEGER NOT NULL," "name TEXT NOT NULL)" }, { "files", "CREATE TABLE IF NOT EXISTS files (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "name TEXT NOT NULL)" }, { "xrefs", "CREATE TABLE IF NOT EXISTS xrefs (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "src TEXT NOT NULL, " "dst TEXT NOT NULL, " "id_file INTEGER NOT NULL, " "line INTEGER, " "column INTEGER)" }, { "memberdef", "CREATE TABLE IF NOT EXISTS memberdef (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "name TEXT NOT NULL," "definition TEXT," "type TEXT," "argsstring TEXT," "scope TEXT," "initializer TEXT," "prot INTEGER NOT NULL," "static INTEGER NOT NULL," "const INTEGER," "explicit INTEGER," "inline INTEGER," "final INTEGER," "sealed INTEGER," "new INTEGER," "optional INTEGER," "required INTEGER," "virt INTEGER," "mutable INTEGER," "initonly INTEGER," "readable INTEGER," "writable INTEGER," "gettable INTEGER," "settable INTEGER," "accessor INTEGER," "addable INTEGER," "removable INTEGER," "raisable INTEGER," "kind INTEGER," "refid TEXT NOT NULL," "id_bodyfile INTEGER," "bodystart INTEGER," "bodyend INTEGER," "id_file INTEGER NOT NULL REFERENCES files(id) ON UPDATE CASCADE," "line INTEGER NOT NULL," "column INTEGER NOT NULL," "detaileddescription TEXT," "briefdescription TEXT," "inbodydescription TEXT" ")" }, { "compounddef", "CREATE TABLE IF NOT EXISTS compounddef (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "name TEXT NOT NULL," "kind TEXT NOT NULL," "prot INTEGER NOT NULL," "refid TEXT NOT NULL," "id_file INTEGER NOT NULL," "line INTEGER NOT NULL," "column INTEGER NOT NULL)" }, { "basecompoundref", "CREATE TABLE IF NOT EXISTS basecompoundref (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "base TEXT NOT NULL," "derived TEXT NOT NULL," "refid TEXT NOT NULL," "prot INTEGER NOT NULL," "virt INTEGER NOT NULL)" }, { "derivedcompoundref", "CREATE TABLE IF NOT EXISTS derivedcompoundref (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " "base TEXT NOT NULL," "derived TEXT NOT NULL," "refid TEXT NOT NULL," "prot INTEGER NOT NULL," "virt INTEGER NOT NULL)" }, { "params", "CREATE TABLE IF NOT EXISTS params (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "attributes TEXT," "type TEXT," "declname TEXT," "defnname TEXT," "array TEXT," "defval TEXT," "briefdescription TEXT)" }, { "memberdef_params", "CREATE TABLE IF NOT EXISTS memberdef_params (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "id_memberdef INTEGER NOT NULL," "id_param INTEGER NOT NULL)" }, { "innernamespaces", "CREATE TABLE IF NOT EXISTS innernamespaces (" "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," "refid TEXT NOT NULL," "name TEXT NOT NULL)" } }; ////////////////////////////////////////////////////// struct sql_stmt { const char *query; sqlite3_stmt *stmt; }; ////////////////////////////////////////////////////// sql_stmt incl_insert={ "INSERT OR REPLACE INTO includes " "( local, id_src, id_dst ) " "VALUES " "(:local,:id_src,:id_dst )" ,NULL }; sql_stmt incl_count={ "SELECT count(*) FROM includes WHERE local=:local and id_src=:id_src and id_dst=:id_dst" ,NULL }; ////////////////////////////////////////////////////// sql_stmt innerclass_insert={"INSERT OR REPLACE INTO innerclass " "( refid, prot, name )" "VALUES " "(:refid,:prot,:name )" ,NULL }; ////////////////////////////////////////////////////// sql_stmt files_insert={"INSERT OR REPLACE INTO files " "( name )" "VALUES " "(:name )" ,NULL }; sql_stmt files_select={"SELECT id FROM files WHERE name=:name" ,NULL }; ////////////////////////////////////////////////////// sql_stmt xrefs_insert={"INSERT OR REPLACE INTO xrefs " "( src, dst, id_file, line, column )" "VALUES " "(:src,:dst,:id_file,:line,:column )" ,NULL }; ////////////////////////////////////////////////////// sql_stmt memberdef_insert={"INSERT OR REPLACE INTO memberdef " "( refid, prot, static, const, explicit, inline, final, sealed, new, optional, required, virt, mutable, initonly, readable, writable, gettable, settable, accessor, addable, removable, raisable, name, type, definition, argsstring, scope, initializer, kind, id_bodyfile, bodystart, bodyend, id_file, line, column, detaileddescription, briefdescription, inbodydescription)" "VALUES " "(:refid,:prot,:static,:const,:explicit,:inline,:final,:sealed,:new,:optional,:required,:virt,:mutable,:initonly,:readable,:writable,:gettable,:settable,:accessor,:addable,:removable,:raisable,:name,:type,:definition,:argsstring,:scope,:initializer,:kind,:id_bodyfile,:bodystart,:bodyend,:id_file,:line,:column,:detaileddescription,:briefdescription,:inbodydescription)" ,NULL }; sql_stmt memberdef_select={"SELECT id FROM memberdef WHERE refid=:refid and id is not null" ,NULL }; ////////////////////////////////////////////////////// sql_stmt compounddef_insert={"INSERT OR REPLACE INTO compounddef " "( name, kind, prot, refid, id_file, line, column ) " "VALUES " "(:name,:kind,:prot,:refid,:id_file,:line,:column )" ,NULL }; ////////////////////////////////////////////////////// sql_stmt basecompoundref_insert={"INSERT OR REPLACE INTO basecompoundref " "( base, derived, refid, prot, virt ) " "VALUES " "(:base,:derived,:refid,:prot,:virt )" ,NULL }; ////////////////////////////////////////////////////// sql_stmt derivedcompoundref_insert={"INSERT OR REPLACE INTO derivedcompoundref " "( refid, prot, virt, base, derived ) " "VALUES " "(:refid,:prot,:virt,:base,:derived )" ,NULL }; ////////////////////////////////////////////////////// sql_stmt params_insert={ "INSERT OR REPLACE INTO params " "( attributes, type, declname, defnname, array, defval, briefdescription ) " "VALUES " "(:attributes,:type,:declname,:defnname,:array,:defval,:briefdescription)" ,NULL }; ////////////////////////////////////////////////////// sql_stmt memberdef_params_insert={ "INSERT OR REPLACE INTO memberdef_params " "( id_memberdef, id_param)" "VALUES " "(:id_memberdef,:id_param)" ,NULL }; ////////////////////////////////////////////////////// sql_stmt innernamespace_insert={"INSERT OR REPLACE INTO innernamespaces " "( refid, name)" "VALUES " "(:refid,:name)", NULL }; class TextGeneratorSqlite3Impl : public TextGeneratorIntf { public: TextGeneratorSqlite3Impl(StringList &l) : l(l) { l.setAutoDelete(TRUE); } void writeString(const char * /*s*/,bool /*keepSpaces*/) const { } void writeBreak(int) const { DBG_CTX(("writeBreak\n")); } void writeLink(const char * /*extRef*/,const char *file, const char *anchor,const char * /*text*/ ) const { QCString *rs=new QCString(file); if (anchor) { rs->append("_1").append(anchor); } l.append(rs); } private: StringList &l; // the list is filled by linkifyText and consumed by the caller }; static void bindTextParameter(sql_stmt &s,const char *name,const char *value, bool _static=TRUE) { int idx = sqlite3_bind_parameter_index(s.stmt, name); sqlite3_bind_text(s.stmt, idx, value, -1, _static==TRUE?SQLITE_STATIC:SQLITE_TRANSIENT); } static void bindIntParameter(sql_stmt &s,const char *name,int value) { int idx = sqlite3_bind_parameter_index(s.stmt, name); sqlite3_bind_int(s.stmt, idx, value); } static int step(sqlite3 *db, sql_stmt &s,bool getRowId=FALSE, bool select=FALSE) { int id=-1; int rc = sqlite3_step(s.stmt); if (rc!=SQLITE_DONE && rc!=SQLITE_ROW) { msg("sqlite3_step failed: %s\n", sqlite3_errmsg(db)); sqlite3_clear_bindings(s.stmt); return -1; } if (getRowId && select) id = sqlite3_column_int(s.stmt, 0); // works on selects, doesnt on inserts if (getRowId && !select) id = sqlite3_last_insert_rowid(db); //works on inserts, doesnt on selects sqlite3_reset(s.stmt); return id; } static int insertFile(sqlite3 *db, const char* name) { int id=-1; if (name==0) return id; // see if it's already in DB bindTextParameter(files_select,":name",name); id=step(db,files_select,TRUE,TRUE); if (id==0) { bindTextParameter(files_insert,":name",name); id=step(db,files_insert,TRUE); } return id; } static int insertMemberReference(sqlite3 *db, const char*src, const char*dst, const char *file, int line, int column) { int id_file = insertFile(db,file); if (id_file==-1) return -1; bindTextParameter(xrefs_insert,":src",src); bindTextParameter(xrefs_insert,":dst",dst); bindIntParameter(xrefs_insert,":id_file",id_file); bindIntParameter(xrefs_insert,":line",line); bindIntParameter(xrefs_insert,":column",column); return step(db,xrefs_insert); } static void insertMemberReference(sqlite3 *db, MemberDef *src, MemberDef *dst, const char*floc) { if (dst->getStartBodyLine()!=-1 && dst->getBodyDef()) { char file[4096] = { 0 }; int line=0,column=0; if (floc) { int rv = sscanf(floc,"%[^:]:%d:%d",file,&line,&column); if (rv!=3) { msg("unable to read file loc\n"); return; } } insertMemberReference(db,src->anchor().data(),dst->anchor().data(),file,line,column); } } static void stripQualifiers(QCString &typeStr) { bool done=FALSE; while (!done) { if (typeStr.stripPrefix("static ")); else if (typeStr.stripPrefix("virtual ")); else if (typeStr.stripPrefix("volatile ")); else if (typeStr=="virtual") typeStr=""; else done=TRUE; } } static int prepareStatement(sqlite3 *db, sql_stmt &s) { int rc; rc = sqlite3_prepare_v2(db,s.query,-1,&s.stmt,0); if (rc!=SQLITE_OK) { msg("prepare failed for %s\n%s\n", s.query, sqlite3_errmsg(db)); return -1; } return rc; } static int prepareStatements(sqlite3 *db) { if ( -1==prepareStatement(db, memberdef_select) || -1==prepareStatement(db, memberdef_insert) || -1==prepareStatement(db, files_insert) || -1==prepareStatement(db, files_select) || -1==prepareStatement(db, xrefs_insert) || -1==prepareStatement(db, innerclass_insert) || -1==prepareStatement(db, compounddef_insert) || -1==prepareStatement(db, basecompoundref_insert) || -1==prepareStatement(db, derivedcompoundref_insert) || -1==prepareStatement(db, incl_insert)|| -1==prepareStatement(db, incl_count)|| -1==prepareStatement(db, params_insert) || -1==prepareStatement(db, memberdef_params_insert)|| -1==prepareStatement(db, innernamespace_insert) ) { return -1; } return 0; } static void beginTransaction(sqlite3 *db) { char * sErrMsg = 0; sqlite3_exec(db, "BEGIN TRANSACTION", NULL, NULL, &sErrMsg); } static void endTransaction(sqlite3 *db) { char * sErrMsg = 0; sqlite3_exec(db, "END TRANSACTION", NULL, NULL, &sErrMsg); } static void pragmaTuning(sqlite3 *db) { char * sErrMsg = 0; sqlite3_exec(db, "PRAGMA synchronous = OFF", NULL, NULL, &sErrMsg); sqlite3_exec(db, "PRAGMA journal_mode = MEMORY", NULL, NULL, &sErrMsg); sqlite3_exec(db, "PRAGMA foreign_keys = ON", NULL, NULL, &sErrMsg); } static int initializeSchema(sqlite3* db) { int rc; sqlite3_stmt *stmt = 0; msg("Initializing DB schema...\n"); for (unsigned int k = 0; k < sizeof(schema_queries) / sizeof(schema_queries[0]); k++) { const char *q = schema_queries[k][1]; // create table rc = sqlite3_prepare_v2(db, q, -1, &stmt, 0); if (rc != SQLITE_OK) { msg("failed to prepare query: %s\n\t%s\n", q, sqlite3_errmsg(db)); return -1; } rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) { msg("failed to execute query: %s\n\t%s\n", q, sqlite3_errmsg(db)); return -1; } sqlite3_finalize(stmt); } return 0; } //////////////////////////////////////////// static void writeInnerClasses(sqlite3*db,const ClassSDict *cl) { if (!cl) return; ClassSDict::Iterator cli(*cl); ClassDef *cd; for (cli.toFirst();(cd=cli.current());++cli) { if (!cd->isHidden() && cd->name().find('@')==-1) // skip anonymous scopes { bindTextParameter(innerclass_insert,":refid",cd->getOutputFileBase(),FALSE); bindIntParameter(innerclass_insert,":prot",cd->protection()); bindTextParameter(innerclass_insert,":name",cd->name()); step(db,innerclass_insert); } } } static void writeInnerNamespaces(sqlite3 *db,const NamespaceSDict *nl) { if (nl) { NamespaceSDict::Iterator nli(*nl); NamespaceDef *nd; for (nli.toFirst();(nd=nli.current());++nli) { if (!nd->isHidden() && nd->name().find('@')==-1) // skip anonymouse scopes { bindTextParameter(innernamespace_insert,":refid",nd->getOutputFileBase(),FALSE); bindTextParameter(innernamespace_insert,":name",nd->name(),FALSE); step(db,innernamespace_insert); } } } } static void writeTemplateArgumentList(sqlite3* db, ArgumentList * al, Definition * scope, FileDef * fileScope) { if (al) { ArgumentListIterator ali(*al); Argument *a; for (ali.toFirst();(a=ali.current());++ali) { if (!a->type.isEmpty()) { #warning linkifyText(TextGeneratorXMLImpl(t),scope,fileScope,0,a->type); bindTextParameter(params_insert,":type",a->type); } if (!a->name.isEmpty()) { bindTextParameter(params_insert,":declname",a->name); bindTextParameter(params_insert,":defnname",a->name); } if (!a->defval.isEmpty()) { #warning linkifyText(TextGeneratorXMLImpl(t),scope,fileScope,0,a->defval); bindTextParameter(params_insert,":defval",a->defval); } step(db,params_insert); } } } static void writeMemberTemplateLists(sqlite3* db,MemberDef *md) { ArgumentList *templMd = md->templateArguments(); if (templMd) // function template prefix { writeTemplateArgumentList(db,templMd,md->getClassDef(),md->getFileDef()); } } static void writeTemplateList(sqlite3*db,ClassDef *cd) { writeTemplateArgumentList(db,cd->templateArguments(),cd,0); } //////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// static void generateSqlite3ForMember(sqlite3*db,MemberDef *md,Definition *def) { // + declaration/definition arg lists // + reimplements // + reimplementedBy // + exceptions // + const/volatile specifiers // - examples // + source definition // + source references // + source referenced by // - body code // + template arguments // (templateArguments(), definitionTemplateParameterLists()) // - call graph // enum values are written as part of the enum if (md->memberType()==MemberType_EnumValue) return; if (md->isHidden()) return; //if (md->name().at(0)=='@') return; // anonymous member // group members are only visible in their group //if (def->definitionType()!=Definition::TypeGroup && md->getGroupDef()) return; QCString memType; // memberdef bindTextParameter(memberdef_insert,":refid",md->anchor().data(),FALSE); bindIntParameter(memberdef_insert,":kind",md->memberType()); bindIntParameter(memberdef_insert,":prot",md->protection()); bindIntParameter(memberdef_insert,":static",md->isStatic()); bool isFunc=FALSE; switch (md->memberType()) { case MemberType_Function: // fall through case MemberType_Signal: // fall through case MemberType_Friend: // fall through case MemberType_DCOP: // fall through case MemberType_Slot: isFunc=TRUE; break; default: break; } if (isFunc) { ArgumentList *al = md->argumentList(); if (al!=0 && al->constSpecifier) { bindIntParameter(memberdef_insert,":const",al->constSpecifier); } bindIntParameter(memberdef_insert,":explicit",md->isExplicit()); bindIntParameter(memberdef_insert,":inline",md->isInline()); bindIntParameter(memberdef_insert,":final",md->isFinal()); bindIntParameter(memberdef_insert,":sealed",md->isSealed()); bindIntParameter(memberdef_insert,":new",md->isNew()); bindIntParameter(memberdef_insert,":optional",md->isOptional()); bindIntParameter(memberdef_insert,":required",md->isRequired()); bindIntParameter(memberdef_insert,":virt",md->virtualness()); } // place in the arguments and linkify the arguments if (md->memberType() == MemberType_Variable) { bindIntParameter(memberdef_insert,":mutable",md->isMutable()); bindIntParameter(memberdef_insert,":initonly",md->isInitonly()); } else if (md->memberType() == MemberType_Property) { bindIntParameter(memberdef_insert,":readable",md->isReadable()); bindIntParameter(memberdef_insert,":writable",md->isWritable()); bindIntParameter(memberdef_insert,":gettable",md->isGettable()); bindIntParameter(memberdef_insert,":settable",md->isSettable()); if (md->isAssign() || md->isCopy() || md->isRetain()) { int accessor = md->isAssign() ? md->isAssign() : (md->isCopy() ? md->isCopy() : md->isRetain()) ; bindIntParameter(memberdef_insert,":accessor",accessor); } } else if (md->memberType() == MemberType_Event) { bindIntParameter(memberdef_insert,":addable",md->isAddable()); bindIntParameter(memberdef_insert,":removable",md->isRemovable()); bindIntParameter(memberdef_insert,":raisable",md->isRaisable()); } // + declaration/definition arg lists if (md->memberType()!=MemberType_Define && md->memberType()!=MemberType_Enumeration ) { if (md->memberType()!=MemberType_Typedef) { writeMemberTemplateLists(db,md); } QCString typeStr = md->typeString(); stripQualifiers(typeStr); StringList l; linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,typeStr); if (typeStr.data()) { bindTextParameter(memberdef_insert,":type",typeStr.data(),FALSE); } if (md->definition()) { bindTextParameter(memberdef_insert,":definition",md->definition()); } if (md->argsString()) { bindTextParameter(memberdef_insert,":argsstring",md->argsString()); } } bindTextParameter(memberdef_insert,":name",md->name()); if (md->memberType() == MemberType_Property) { if (md->isReadable()) { bindIntParameter(memberdef_insert,":readable",1); } if (md->isWritable()) { bindIntParameter(memberdef_insert,":writable",1); } } // Extract references from initializer // avoid that extremely large tables are written to the output. // drm_mod_register_buffer, if (md->hasMultiLineInitializer() || md->hasOneLineInitializer()) { bindTextParameter(memberdef_insert,":initializer",md->initializer().data()); StringList l; linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,md->initializer()); StringListIterator li(l); QCString *s; while ((s=li.current())) { if (md->getBodyDef()) { DBG_CTX(("initializer:%s %s %s %d\n", md->anchor().data(), s->data(), md->getBodyDef()->getDefFileName().data(), md->getStartBodyLine())); insertMemberReference(db,md->anchor().data(),s->data(),md->getBodyDef()->getDefFileName().data(),md->getStartBodyLine(),1); } ++li; } } if ( md->getScopeString() ) { bindTextParameter(memberdef_insert,":scope",md->getScopeString().data(),FALSE); } // +Brief, detailed and inbody description bindTextParameter(memberdef_insert,":briefdescription",md->briefDescription(),FALSE); bindTextParameter(memberdef_insert,":detaileddescription",md->documentation(),FALSE); bindTextParameter(memberdef_insert,":inbodydescription",md->inbodyDocumentation(),FALSE); // File location if (md->getDefLine() != -1) { int id_file = insertFile(db,md->getDefFileName()); if (id_file!=-1) { bindIntParameter(memberdef_insert,":id_file",id_file); bindIntParameter(memberdef_insert,":line",md->getDefLine()); bindIntParameter(memberdef_insert,":column",md->getDefColumn()); if (md->getStartBodyLine()!=-1) { int id_bodyfile = insertFile(db,md->getBodyDef()->absFilePath()); if (id_bodyfile == -1) { sqlite3_clear_bindings(memberdef_insert.stmt); } else { bindIntParameter(memberdef_insert,":id_bodyfile",id_bodyfile); bindIntParameter(memberdef_insert,":bodystart",md->getStartBodyLine()); bindIntParameter(memberdef_insert,":bodyend",md->getEndBodyLine()); } } } } int id_memberdef=step(db,memberdef_insert,TRUE); // + parameters // ++ function if (isFunc) { ArgumentList *declAl = md->declArgumentList(); ArgumentList *defAl = md->argumentList(); if (declAl!=0 && declAl->count()>0) { ArgumentListIterator declAli(*declAl); ArgumentListIterator defAli(*defAl); Argument *a; for (declAli.toFirst();(a=declAli.current());++declAli) { Argument *defArg = defAli.current(); if (!a->attrib.isEmpty()) { bindTextParameter(params_insert,":attributes",a->attrib.data()); } if (!a->type.isEmpty()) { StringList l; linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,a->type); StringListIterator li(l); QCString *s; while ((s=li.current())) { insertMemberReference(db,md->anchor().data(),s->data(),def->getDefFileName().data(),md->getDefLine(),1); ++li; } bindTextParameter(params_insert,":type",a->type.data()); } if (!a->name.isEmpty()) { bindTextParameter(params_insert,":declname",a->name.data()); } if (defArg && !defArg->name.isEmpty() && defArg->name!=a->name) { bindTextParameter(params_insert,":defnname",defArg->name.data()); } if (!a->array.isEmpty()) { bindTextParameter(params_insert,":array",a->array.data()); } if (!a->defval.isEmpty()) { StringList l; linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,a->defval); bindTextParameter(params_insert,":defval",a->defval.data()); } if (defArg) ++defAli; int id_param=step(db,params_insert,TRUE); sqlite3_clear_bindings(params_insert.stmt); bindIntParameter(memberdef_params_insert,":id_memberdef",id_memberdef); bindIntParameter(memberdef_params_insert,":id_param",id_param); step(db,memberdef_params_insert); } } } // ++ define else if (md->memberType()==MemberType_Define && md->argsString()) { if (md->argumentList()->count()==0) // special case for "foo()" to // disguish it from "foo". { DBG_CTX(("no params\n")); } else { ArgumentListIterator ali(*md->argumentList()); Argument *a; for (ali.toFirst();(a=ali.current());++ali) { bindTextParameter(params_insert,":defnname",a->type.data()); int id_param=step(db,params_insert,TRUE); sqlite3_clear_bindings(params_insert.stmt); bindIntParameter(memberdef_params_insert,":id_memberdef",id_memberdef); bindIntParameter(memberdef_params_insert,":id_param",id_param); step(db,memberdef_params_insert); } } } // + source references // The cross-references in initializers only work when both the src and dst // are defined. MemberSDict *mdict = md->getReferencesMembers(); if (mdict!=0) { MemberSDict::IteratorDict mdi(*mdict); MemberDef *rmd; for (mdi.toFirst();(rmd=mdi.current());++mdi) { insertMemberReference(db,md,rmd,mdi.currentKey()); } } // + source referenced by mdict = md->getReferencedByMembers(); if (mdict!=0) { MemberSDict::IteratorDict mdi(*mdict); MemberDef *rmd; for (mdi.toFirst();(rmd=mdi.current());++mdi) { insertMemberReference(db,rmd,md,mdi.currentKey()); } } } static void generateSqlite3Section(sqlite3*db, Definition *d, MemberList *ml,const char * /*kind*/,const char * /*header*/=0, const char * /*documentation*/=0) { if (ml==0) return; MemberListIterator mli(*ml); MemberDef *md; int count=0; for (mli.toFirst();(md=mli.current());++mli) { // namespace members are also inserted in the file scope, but // to prevent this duplication in the XML output, we filter those here. if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0) { count++; } } if (count==0) return; // empty list for (mli.toFirst();(md=mli.current());++mli) { // namespace members are also inserted in the file scope, but // to prevent this duplication in the XML output, we filter those here. //if (d->definitionType()!=Definition::TypeFile || md->getNamespaceDef()==0) { generateSqlite3ForMember(db,md,d); } } } static void generateSqlite3ForClass(sqlite3 *db, ClassDef *cd) { // + list of direct super classes // + list of direct sub classes // + include file // + list of inner classes // - template argument list(s) // + member groups // + list of all members // - brief description // - detailed description // - inheritance DOT diagram // - collaboration DOT diagram // - user defined member sections // - standard member sections // - detailed member documentation // - examples using the class if (cd->isReference()) return; // skip external references. if (cd->isHidden()) return; // skip hidden classes. if (cd->name().find('@')!=-1) return; // skip anonymous compounds. if (cd->templateMaster()!=0) return; // skip generated template instances. msg("Generating Sqlite3 output for class %s\n",cd->name().data()); bindTextParameter(compounddef_insert,":name",cd->name()); bindTextParameter(compounddef_insert,":kind",cd->compoundTypeString(),FALSE); bindIntParameter(compounddef_insert,":prot",cd->protection()); bindTextParameter(compounddef_insert,":refid",cd->getOutputFileBase(),FALSE); int id_file = insertFile(db,cd->getDefFileName().data()); bindIntParameter(compounddef_insert,":id_file",id_file); bindIntParameter(compounddef_insert,":line",cd->getDefLine()); bindIntParameter(compounddef_insert,":column",cd->getDefColumn()); step(db,compounddef_insert); // + list of direct super classes if (cd->baseClasses()) { BaseClassListIterator bcli(*cd->baseClasses()); BaseClassDef *bcd; for (bcli.toFirst();(bcd=bcli.current());++bcli) { bindTextParameter(basecompoundref_insert,":refid",bcd->classDef->getOutputFileBase(),FALSE); bindIntParameter(basecompoundref_insert,":prot",bcd->prot); bindIntParameter(basecompoundref_insert,":virt",bcd->virt); if (!bcd->templSpecifiers.isEmpty()) { bindTextParameter(basecompoundref_insert,":base",insertTemplateSpecifierInScope(bcd->classDef->name(),bcd->templSpecifiers),FALSE); } else { bindTextParameter(basecompoundref_insert,":base",bcd->classDef->displayName(),FALSE); } bindTextParameter(basecompoundref_insert,":derived",cd->displayName(),FALSE); step(db,basecompoundref_insert); } } // + list of direct sub classes if (cd->subClasses()) { BaseClassListIterator bcli(*cd->subClasses()); BaseClassDef *bcd; for (bcli.toFirst();(bcd=bcli.current());++bcli) { bindTextParameter(derivedcompoundref_insert,":base",cd->displayName()); bindTextParameter(derivedcompoundref_insert,":dervied",bcd->classDef->displayName()); bindTextParameter(derivedcompoundref_insert,":refid",bcd->classDef->getOutputFileBase()); bindIntParameter(derivedcompoundref_insert,":prot",bcd->prot); bindIntParameter(derivedcompoundref_insert,":virt",bcd->virt); step(db,derivedcompoundref_insert); } } // + include file IncludeInfo *ii=cd->includeInfo(); if (ii) { QCString nm = ii->includeName; if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); if (!nm.isEmpty()) { int id_dst=insertFile(db,nm); bindIntParameter(incl_count,":local",ii->local); bindIntParameter(incl_count,":id_src",id_file); bindIntParameter(incl_count,":id_dst",id_dst); int count=step(db,incl_count,TRUE,TRUE); if (count==0) { bindIntParameter(incl_insert,":local",ii->local); bindIntParameter(incl_insert,":id_src",id_file); bindIntParameter(incl_insert,":id_dst",id_dst); step(db,incl_insert); } } } // + list of inner classes writeInnerClasses(db,cd->getClassSDict()); // - template argument list(s) writeTemplateList(db,cd); // + member groups if (cd->getMemberGroupSDict()) { MemberGroupSDict::Iterator mgli(*cd->getMemberGroupSDict()); MemberGroup *mg; for (;(mg=mgli.current());++mgli) { generateSqlite3Section(db,cd,mg->members(),"user-defined",mg->header(), mg->documentation()); } } // + list of all members QListIterator mli(cd->getMemberLists()); MemberList *ml; for (mli.toFirst();(ml=mli.current());++mli) { if ((ml->listType()&MemberListType_detailedLists)==0) { generateSqlite3Section(db,cd,ml,"user-defined");//g_xmlSectionMapper.find(ml->listType())); } } } static void generateSqlite3ForNamespace(sqlite3 *db, NamespaceDef *nd) { // + contained class definitions // + contained namespace definitions // + member groups // + normal members // - brief desc // - detailed desc // - location // - files containing (parts of) the namespace definition if (nd->isReference() || nd->isHidden()) return; // skip external references // + contained class definitions writeInnerClasses(db,nd->getClassSDict()); // + contained namespace definitions writeInnerNamespaces(db,nd->getNamespaceSDict()); // + member groups if (nd->getMemberGroupSDict()) { MemberGroupSDict::Iterator mgli(*nd->getMemberGroupSDict()); MemberGroup *mg; for (;(mg=mgli.current());++mgli) { generateSqlite3Section(db,nd,mg->members(),"user-defined",mg->header(), mg->documentation()); } } // + normal members QListIterator mli(nd->getMemberLists()); MemberList *ml; for (mli.toFirst();(ml=mli.current());++mli) { if ((ml->listType()&MemberListType_declarationLists)!=0) { generateSqlite3Section(db,nd,ml,"user-defined");//g_xmlSectionMapper.find(ml->listType())); } } } static void generateSqlite3ForFile(sqlite3 *db, FileDef *fd) { // + includes files // + includedby files // - include graph // - included by graph // + contained class definitions // + contained namespace definitions // + member groups // + normal members // - brief desc // - detailed desc // - source code // - location // - number of lines if (fd->isReference()) return; // skip external references // + includes files IncludeInfo *ii; if (fd->includeFileList()) { QListIterator ili(*fd->includeFileList()); for (ili.toFirst();(ii=ili.current());++ili) { int id_src=insertFile(db,fd->absFilePath().data()); int id_dst=insertFile(db,ii->includeName.data()); bindIntParameter(incl_insert,":local",ii->local); bindIntParameter(incl_insert,":id_src",id_src); bindIntParameter(incl_insert,":id_dst",id_dst); step(db,incl_insert); } } // + includedby files if (fd->includedByFileList()) { QListIterator ili(*fd->includedByFileList()); for (ili.toFirst();(ii=ili.current());++ili) { int id_src=insertFile(db,ii->includeName); int id_dst=insertFile(db,fd->absFilePath()); bindIntParameter(incl_insert,":local",ii->local); bindIntParameter(incl_insert,":id_src",id_src); bindIntParameter(incl_insert,":id_dst",id_dst); step(db,incl_insert); } } // + contained class definitions if (fd->getClassSDict()) { writeInnerClasses(db,fd->getClassSDict()); } // + contained namespace definitions if (fd->getNamespaceSDict()) { writeInnerNamespaces(db,fd->getNamespaceSDict()); } // + member groups if (fd->getMemberGroupSDict()) { MemberGroupSDict::Iterator mgli(*fd->getMemberGroupSDict()); MemberGroup *mg; for (;(mg=mgli.current());++mgli) { generateSqlite3Section(db,fd,mg->members(),"user-defined",mg->header(), mg->documentation()); } } // + normal members QListIterator mli(fd->getMemberLists()); MemberList *ml; for (mli.toFirst();(ml=mli.current());++mli) { if ((ml->listType()&MemberListType_declarationLists)!=0) { generateSqlite3Section(db,fd,ml,"user-defined");//g_xmlSectionMapper.find(ml->listType())); } } } static void generateSqlite3ForGroup(sqlite3*db,GroupDef *gd) { #warning WorkInProgress } static void generateSqlite3ForDir(sqlite3 *db,DirDef *dd) { #warning WorkInProgress } static void generateSqlite3ForPage(sqlite3 *db,PageDef *pd,bool isExample) { #warning WorkInProgress } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// void generateSqlite3() { // + classes // + namespaces // + files // + groups // + related pages // + examples // + main page QCString outputDirectory = Config_getString("OUTPUT_DIRECTORY"); QDir sqlite3Dir(outputDirectory); sqlite3 *db; sqlite3_initialize(); int rc = sqlite3_open_v2(outputDirectory+"/doxygen_sqlite3.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, 0); if (rc != SQLITE_OK) { sqlite3_close(db); msg("database open failed: %s\n", "doxygen_sqlite3.db"); return; } beginTransaction(db); pragmaTuning(db); if (-1==initializeSchema(db)) return; if ( -1 == prepareStatements(db) ) { err("sqlite generator: prepareStatements failed!"); return; } // + classes ClassSDict::Iterator cli(*Doxygen::classSDict); ClassDef *cd; for (cli.toFirst();(cd=cli.current());++cli) { msg("Generating Sqlite3 output for class %s\n",cd->name().data()); generateSqlite3ForClass(db,cd); } // + namespaces NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); NamespaceDef *nd; for (nli.toFirst();(nd=nli.current());++nli) { msg("Generating Sqlite3 output for namespace %s\n",nd->name().data()); generateSqlite3ForNamespace(db,nd); } // + files FileNameListIterator fnli(*Doxygen::inputNameList); FileName *fn; for (;(fn=fnli.current());++fnli) { FileNameIterator fni(*fn); FileDef *fd; for (;(fd=fni.current());++fni) { msg("Generating Sqlite3 output for file %s\n",fd->name().data()); generateSqlite3ForFile(db,fd); } } // + groups GroupSDict::Iterator gli(*Doxygen::groupSDict); GroupDef *gd; for (;(gd=gli.current());++gli) { msg("Generating Sqlite3 output for group %s\n",gd->name().data()); generateSqlite3ForGroup(db,gd); } // + page { PageSDict::Iterator pdi(*Doxygen::pageSDict); PageDef *pd=0; for (pdi.toFirst();(pd=pdi.current());++pdi) { msg("Generating Sqlite3 output for page %s\n",pd->name().data()); generateSqlite3ForPage(db,pd,FALSE); } } // + dirs { DirDef *dir; DirSDict::Iterator sdi(*Doxygen::directories); for (sdi.toFirst();(dir=sdi.current());++sdi) { msg("Generating Sqlite3 output for dir %s\n",dir->name().data()); generateSqlite3ForDir(db,dir); } } // + examples { PageSDict::Iterator pdi(*Doxygen::exampleSDict); PageDef *pd=0; for (pdi.toFirst();(pd=pdi.current());++pdi) { msg("Generating Sqlite3 output for example %s\n",pd->name().data()); generateSqlite3ForPage(db,pd,TRUE); } } // + main page if (Doxygen::mainPage) { msg("Generating Sqlite3 output for the main page\n"); generateSqlite3ForPage(db,Doxygen::mainPage,FALSE); } endTransaction(db); } #else // USE_SQLITE3 void generateSqlite3() { err("sqlite3 support has not been compiled in!"); } #endif