diff options
Diffstat (limited to 'src/sqlite3gen.cpp')
-rw-r--r-- | src/sqlite3gen.cpp | 1361 |
1 files changed, 1361 insertions, 0 deletions
diff --git a/src/sqlite3gen.cpp b/src/sqlite3gen.cpp new file mode 100644 index 0000000..c50ea75 --- /dev/null +++ b/src/sqlite3gen.cpp @@ -0,0 +1,1361 @@ +/****************************************************************************** + * + * 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 <stdlib.h> +#include <stdio.h> +#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 "arguments.h" +#include "classlist.h" +#include "filedef.h" +#include "namespacedef.h" +#include "filename.h" + +#include <qdir.h> +#include <string.h> +#include <sqlite3.h> + +//#define DBG_CTX(x) printf x +#define DBG_CTX(x) do { } while(0) + +////////////////////////////////////////////////////// +const char *i_q_includes="INSERT OR REPLACE INTO includes " + "( refid, local, name ) " + "VALUES " + "(:refid,:local,:name )" ; +const char *c_q_includes="SELECT count(*) from includes where refid=:refid and local=:local and name=:name"; +static sqlite3_stmt *i_s_includes=0; +static sqlite3_stmt *c_s_includes=0; +////////////////////////////////////////////////////// +const char *i_q_innerclass="INSERT OR REPLACE INTO innerclass " + "( refid, prot, name )" + "VALUES " + "(:refid,:prot,:name )"; +static sqlite3_stmt *i_s_innerclass=0; +////////////////////////////////////////////////////// +const char *i_q_files="INSERT OR REPLACE INTO files " + "( name )" + "VALUES " + "(:name )"; +const char *id_q_files="SELECT id from files where name=:name"; +static sqlite3_stmt *id_s_files=0; +static sqlite3_stmt *i_s_files=0; +////////////////////////////////////////////////////// +const char *i_q_xrefs="INSERT OR REPLACE INTO xrefs " + "( src, dst, id_file, line, column )" + "VALUES " + "(:src,:dst,:id_file,:line,:column )"; +static sqlite3_stmt *i_s_xrefs=0; +////////////////////////////////////////////////////// +const char *i_q_memberdef="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, kind, id_bfile, bline, bcolumn, id_file, line, column)" + "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,:kind,:id_bfile,:bline,:bcolumn,:id_file,:line,:column)"; +const char *id_q_memberdef="SELECT id from memberdef where refid=:refid and id is not null"; +static sqlite3_stmt *id_s_memberdef=0; +static sqlite3_stmt *i_s_memberdef=0; +////////////////////////////////////////////////////// +const char *i_q_compounddef="INSERT OR REPLACE INTO compounddef " + "( name, kind, prot, refid, id_file, line, column ) " + "VALUES " + "(:name,:kind,:prot,:refid,:id_file,:line,:column )"; +static sqlite3_stmt *i_s_compounddef=0; +////////////////////////////////////////////////////// +const char *i_q_basecompoundref="INSERT OR REPLACE INTO basecompoundref " + "( base, derived, refid, prot, virt ) " + "VALUES " + "(:base,:derived,:refid,:prot,:virt )" ; +static sqlite3_stmt *i_s_basecompoundref=0; +////////////////////////////////////////////////////// +const char *i_q_derivedcompoundref="INSERT OR REPLACE INTO derivedcompoundref " + "( refid, prot, virt, base, derived ) " + "VALUES " + "(:refid,:prot,:virt,:base,:derived )" ; +static sqlite3_stmt *i_s_derivedcompoundref=0; +////////////////////////////////////////////////////// + +const char * schema_queries[][2] = +{ + { + "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)" + }, + { + "includes", + "CREATE TABLE IF NOT EXISTS includes (" + "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " + "refid TEXT NOT NULL," + "local INTEGER NOT NULL," + "name TEXT NOT NULL)" + }, + { + "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," + "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_bfile INTEGER," + "bline INTEGER," + "bcolumn INTEGER," + "id_file INTEGER NOT NULL," + "line INTEGER NOT NULL," + "column INTEGER NOT 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 generateSqlite3ForMember(sqlite3*db,MemberDef *md,Definition *def); + + +static void bindTextParameter(sqlite3_stmt *stmt,const char *name,const char *value) +{ + int idx = sqlite3_bind_parameter_index(stmt, name); + sqlite3_bind_text(id_s_files, idx, value, -1, SQLITE_STATIC); +} + +static void bindIntParameter(sqlite3_stmt *stmt,const char *name,int value) +{ + int idx = sqlite3_bind_parameter_index(stmt, name); + sqlite3_bind_int(stmt, idx, value); +} + +static int step(sqlite3 *db, sqlite3_stmt *stmt,bool getRowId=FALSE) +{ + int id=-1; + int rc = sqlite3_step(stmt); + if (rc!=SQLITE_DONE && rc!=SQLITE_ROW) + { + msg("failed count files: %s\n", sqlite3_errmsg(db)); + } + if (getRowId) id = sqlite3_column_int(stmt, 0); + sqlite3_reset(stmt); + return id; +} + +#if 0 +static QCString memberOutputFileBase(MemberDef *md) +{ + //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES"); + //if (inlineGroupedClasses && md->getClassDef() && md->getClassDef()->partOfGroups()!=0) + // return md->getClassDef()->getXmlOutputFileBase(); + //else + // return md->getOutputFileBase(); + return md->getOutputFileBase(); +} +#endif + +static int insertFile(sqlite3 *db, const char* name) +{ + int id=-1; + if (name==0) return -1; + // see if it's already in DB + + bindTextParameter(id_s_files,":name",name); + id=step(db,i_s_files,TRUE); + if (id==0) + { + // insert it + bindTextParameter(i_s_files,":name",name); + + step(db,i_s_files); + id=sqlite3_last_insert_rowid(db); + } + return id; +} + +static void insertMemberReference(sqlite3 *db, const char*src, const char*dst, const char *file, int line, int column) +{ +#if 0 + QCString scope = dst->getScopeString(); + QCString src_name = src->name(); + QCString dst_name = dst->name(); + if (!dst->getScopeString().isEmpty() && dst->getScopeString()!=def->name()) + { + dst_name.prepend(scope+getLanguageSpecificSeparator(dst->getLanguage())); + } + if (!src->getScopeString().isEmpty() && src->getScopeString()!=def->name()) + { + src_name.prepend(scope+getLanguageSpecificSeparator(src->getLanguage())); + } +#endif + // + bindTextParameter(i_s_xrefs,":src",src); + bindTextParameter(i_s_xrefs,":dst",dst); + + int id_file = insertFile(db,file); + + bindIntParameter(i_s_xrefs,":id_file",id_file); + bindIntParameter(i_s_xrefs,":line",line); + bindIntParameter(i_s_xrefs,":column",column); + + step(db,i_s_xrefs); +} + +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) + { + sscanf(floc,"%[^:]:%d:%d",file,&line,&column); + } + 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 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(i_s_innerclass,":refid",cd->getOutputFileBase()); + bindIntParameter(i_s_innerclass,":prot",cd->protection()); + bindTextParameter(i_s_innerclass,":name",cd->name()); + step(db,i_s_innerclass); + } + } +} + +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 + { +// t << " <innernamespace refid=\"" << nd->getOutputFileBase() +// << "\">" << convertToXML(nd->name()) << "</innernamespace>" << endl; + } + } + } +} + +static void writeTemplateArgumentList(sqlite3* /*db*/, + ArgumentList * /*al*/, + Definition * /*scope*/, + FileDef * /*fileScope*/, + int /*indent*/) +{ +#if 0 + QCString indentStr; + indentStr.fill(' ',indent); + if (al) + { + t << indentStr << "<templateparamlist>" << endl; + ArgumentListIterator ali(*al); + Argument *a; + for (ali.toFirst();(a=ali.current());++ali) + { + t << indentStr << " <param>" << endl; + if (!a->type.isEmpty()) + { + t << indentStr << " <type>"; + linkifyText(TextGeneratorXMLImpl(t),scope,fileScope,0,a->type); + t << "</type>" << endl; + } + if (!a->name.isEmpty()) + { + t << indentStr << " <declname>" << a->name << "</declname>" << endl; + t << indentStr << " <defname>" << a->name << "</defname>" << endl; + } + if (!a->defval.isEmpty()) + { + t << indentStr << " <defval>"; + linkifyText(TextGeneratorXMLImpl(t),scope,fileScope,0,a->defval); + t << "</defval>" << endl; + } + t << indentStr << " </param>" << endl; + } + t << indentStr << "</templateparamlist>" << endl; + } +#endif +} + +static void writeTemplateList(sqlite3*db,ClassDef *cd) +{ + writeTemplateArgumentList(db,cd->templateArguments(),cd,0,4); +} + +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 +#if 0 + + t << " <sectiondef kind=\"" << kind << "\">" << endl; + if (header) + { + t << " <header>" << convertToXML(header) << "</header>" << endl; + } + if (documentation) + { + t << " <description>"; + writeXMLDocBlock(t,d->docFile(),d->docLine(),d,0,documentation); + t << "</description>" << endl; + } +#endif + 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); + } + } + //t << " </sectiondef>" << endl; +} + +static int prepareStatements(sqlite3 *db) +{ + int rc; + rc = sqlite3_prepare_v2(db,id_q_memberdef,-1,&id_s_memberdef,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n", id_q_memberdef, sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,id_q_files,-1,&id_s_files,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n", id_q_files, sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,i_q_files,-1,&i_s_files,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n",i_q_files,sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,i_q_xrefs,-1,&i_s_xrefs,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n", i_q_xrefs, sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db, i_q_innerclass, -1, &i_s_innerclass, 0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n", i_q_innerclass, sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,i_q_memberdef,-1,&i_s_memberdef,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n",i_q_memberdef,sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,i_q_compounddef,-1,&i_s_compounddef,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n",i_q_compounddef,sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,i_q_basecompoundref,-1,&i_s_basecompoundref,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n",i_q_basecompoundref,sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db,i_q_derivedcompoundref,-1,&i_s_derivedcompoundref,0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n",i_q_derivedcompoundref,sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db, i_q_includes, -1, &i_s_includes, 0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n", i_q_includes, sqlite3_errmsg(db)); + return -1; + } + rc = sqlite3_prepare_v2(db, c_q_includes, -1, &c_s_includes, 0); + if (rc!=SQLITE_OK) + { + msg("prepare failed for %s\n%s\n", c_q_includes, sqlite3_errmsg(db)); + 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); +} + +static void 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 *tname = schema_queries[k][0]; + 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)); + exit(-1); + } + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) + { + msg("failed to execute query: %s\n\t%s\n", q, sqlite3_errmsg(db)); + exit(-1); + } + sqlite3_finalize(stmt); + + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +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 +#if 0 + ti << " <compound refid=\"" << nd->getOutputFileBase() + << "\" kind=\"namespace\"" << "><name>" + << convertToXML(nd->name()) << "</name>" << endl; + + QCString outputDirectory = Config_getString("XML_OUTPUT"); + QCString fileName=outputDirectory+"/"+nd->getOutputFileBase()+".xml"; + QFile f(fileName); + if (!f.open(IO_WriteOnly)) + { + err("Cannot open file %s for writing!\n",fileName.data()); + return; + } + FTextStream t(&f); + //t.setEncoding(FTextStream::UnicodeUTF8); + + writeXMLHeader(t); + t << " <compounddef id=\"" + << nd->getOutputFileBase() << "\" kind=\"namespace\">" << endl; + t << " <compoundname>"; + writeXMLString(t,nd->name()); + t << "</compoundname>" << endl; +#endif + writeInnerClasses(db,nd->getClassSDict()); + writeInnerNamespaces(db,nd->getNamespaceSDict()); + + 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()); + } + } + + QListIterator<MemberList> 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())); + } + } +#if 0 + generateXMLSection(nd,ti,t,&nd->decDefineMembers,"define"); + generateXMLSection(nd,ti,t,&nd->decProtoMembers,"prototype"); + generateXMLSection(nd,ti,t,&nd->decTypedefMembers,"typedef"); + generateXMLSection(nd,ti,t,&nd->decEnumMembers,"enum"); + generateXMLSection(nd,ti,t,&nd->decFuncMembers,"func"); + generateXMLSection(nd,ti,t,&nd->decVarMembers,"var"); + + t << " <briefdescription>" << endl; + writeXMLDocBlock(t,nd->briefFile(),nd->briefLine(),nd,0,nd->briefDescription()); + t << " </briefdescription>" << endl; + t << " <detaileddescription>" << endl; + writeXMLDocBlock(t,nd->docFile(),nd->docLine(),nd,0,nd->documentation()); + t << " </detaileddescription>" << endl; + t << " <location file=\"" + << nd->getDefFileName() << "\" line=\"" + << nd->getDefLine() << "\"" << " column=\"" + << nd->getDefColumn() << "\"/>" << endl ; + t << " </compounddef>" << endl; + t << "</doxygen>" << endl; + + ti << " </compound>" << endl; +#endif +} + + +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 +#if 0 + ti << " <compound refid=\"" << fd->getOutputFileBase() + << "\" kind=\"file\"><name>" << convertToXML(fd->name()) + << "</name>" << endl; + + QCString outputDirectory = Config_getString("XML_OUTPUT"); + QCString fileName=outputDirectory+"/"+fd->getOutputFileBase()+".xml"; + QFile f(fileName); + if (!f.open(IO_WriteOnly)) + { + err("Cannot open file %s for writing!\n",fileName.data()); + return; + } + FTextStream t(&f); + //t.setEncoding(FTextStream::UnicodeUTF8); + + writeXMLHeader(t); + t << " <compounddef id=\"" + << fd->getOutputFileBase() << "\" kind=\"file\">" << endl; + t << " <compoundname>"; + writeXMLString(t,fd->name()); + t << "</compoundname>" << endl; + + IncludeInfo *inc; + + if (fd->includeFileList()) + { + QListIterator<IncludeInfo> ili1(*fd->includeFileList()); + for (ili1.toFirst();(inc=ili1.current());++ili1) + { + t << " <includes"; + if (inc->fileDef && !inc->fileDef->isReference()) // TODO: support external references + { + t << " refid=\"" << inc->fileDef->getOutputFileBase() << "\""; + } + t << " local=\"" << (inc->local ? "yes" : "no") << "\">"; + t << inc->includeName; + t << "</includes>" << endl; + } + } + + if (fd->includedByFileList()) + { + QListIterator<IncludeInfo> ili2(*fd->includedByFileList()); + for (ili2.toFirst();(inc=ili2.current());++ili2) + { + t << " <includedby"; + if (inc->fileDef && !inc->fileDef->isReference()) // TODO: support external references + { + t << " refid=\"" << inc->fileDef->getOutputFileBase() << "\""; + } + t << " local=\"" << (inc->local ? "yes" : "no") << "\">"; + t << inc->includeName; + t << "</includedby>" << endl; + } + } + + DotInclDepGraph incDepGraph(fd,FALSE); + if (!incDepGraph.isTrivial()) + { + t << " <incdepgraph>" << endl; + incDepGraph.writeXML(t); + t << " </incdepgraph>" << endl; + } + + DotInclDepGraph invIncDepGraph(fd,TRUE); + if (!invIncDepGraph.isTrivial()) + { + t << " <invincdepgraph>" << endl; + invIncDepGraph.writeXML(t); + t << " </invincdepgraph>" << endl; + } +#endif + if (fd->getClassSDict()) + { + writeInnerClasses(db,fd->getClassSDict()); + } + if (fd->getNamespaceSDict()) + { + writeInnerNamespaces(db,fd->getNamespaceSDict()); + } + + 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()); + } + } + + QListIterator<MemberList> 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())); + } + } +#if 0 + generateXMLSection(fd,ti,t,fd->decDefineMembers,"define"); + generateXMLSection(fd,ti,t,fd->decProtoMembers,"prototype"); + generateXMLSection(fd,ti,t,fd->decTypedefMembers,"typedef"); + generateXMLSection(fd,ti,t,fd->decEnumMembers,"enum"); + generateXMLSection(fd,ti,t,fd->decFuncMembers,"func"); + generateXMLSection(fd,ti,t,fd->decVarMembers,"var"); +#endif +#if 0 + t << " <briefdescription>" << endl; + writeXMLDocBlock(t,fd->briefFile(),fd->briefLine(),fd,0,fd->briefDescription()); + t << " </briefdescription>" << endl; + t << " <detaileddescription>" << endl; + writeXMLDocBlock(t,fd->docFile(),fd->docLine(),fd,0,fd->documentation()); + t << " </detaileddescription>" << endl; + if (Config_getBool("XML_PROGRAMLISTING")) + { + t << " <programlisting>" << endl; + writeXMLCodeBlock(t,fd); + t << " </programlisting>" << endl; + } + t << " <location file=\"" << fd->getDefFileName() << "\"/>" << endl; + t << " </compounddef>" << endl; + t << "</doxygen>" << endl; + + ti << " </compound>" << endl; +#endif +} + + + + +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; +#if 0 + // member + idx = sqlite3_bind_parameter_index(stmt, ":refid"); + sqlite3_bind_text(stmt, idx, memberOutputFileBase(md).data(),-1,SQLITE_TRANSIENT); + + idx = sqlite3_bind_parameter_index(stmt,":kind"); + sqlite3_bind_int(stmt, idx, md->memberType()); + + idx = sqlite3_bind_parameter_index(stmt, ":name"); + sqlite3_bind_text(stmt, idx, md->name().data(),-1,SQLITE_TRANSIENT); +#endif + // memberdef + bindTextParameter(i_s_memberdef,":refid",md->anchor()); + bindIntParameter(i_s_memberdef,":kind",md->memberType()); + bindIntParameter(i_s_memberdef,":prot",md->protection()); + bindIntParameter(i_s_memberdef,":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) + { + LockingPtr<ArgumentList> al = md->argumentList(); + if (al!=0 && al->constSpecifier) + { + bindIntParameter(i_s_memberdef,":const",al->constSpecifier); + } + + bindIntParameter(i_s_memberdef,":explicit",md->isExplicit()); + bindIntParameter(i_s_memberdef,":inline",md->isInline()); + bindIntParameter(i_s_memberdef,":final",md->isFinal()); + bindIntParameter(i_s_memberdef,":sealed",md->isSealed()); + bindIntParameter(i_s_memberdef,":new",md->isNew()); + bindIntParameter(i_s_memberdef,":optional",md->isOptional()); + bindIntParameter(i_s_memberdef,":required",md->isRequired()); + bindIntParameter(i_s_memberdef,":virt",md->virtualness()); + } + // place in the arguments and linkify the arguments + + if (md->memberType() == MemberType_Variable) + { + bindIntParameter(i_s_memberdef,":mutable",md->isMutable()); + bindIntParameter(i_s_memberdef,":initonly",md->isInitonly()); + } + else if (md->memberType() == MemberType_Property) + { + bindIntParameter(i_s_memberdef,":readable",md->isReadable()); + bindIntParameter(i_s_memberdef,":writable",md->isWritable()); + bindIntParameter(i_s_memberdef,":gettable",md->isGettable()); + bindIntParameter(i_s_memberdef,":settable",md->isSettable()); + + if (md->isAssign() || md->isCopy() || md->isRetain()) + { + int accessor = md->isAssign() ? md->isAssign() : + (md->isCopy() ? md->isCopy() : md->isRetain()) ; + + bindIntParameter(i_s_memberdef,":accessor",accessor); + } + } + else if (md->memberType() == MemberType_Event) + { + bindIntParameter(i_s_memberdef,":addable",md->isAddable()); + bindIntParameter(i_s_memberdef,":removable",md->isRemovable()); + bindIntParameter(i_s_memberdef,":raisable",md->isRaisable()); + } + + if (md->memberType()!=MemberType_Define && + md->memberType()!=MemberType_Enumeration + ) + { + QCString typeStr = md->typeString(); + stripQualifiers(typeStr); + StringList l; + linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,typeStr); + if (typeStr.data()) + { + bindTextParameter(i_s_memberdef,":type",typeStr); + } + + if (md->definition()) + { + bindTextParameter(i_s_memberdef,":definition",md->definition()); + } + + if (md->argsString()) + { + bindTextParameter(i_s_memberdef,":argsstring",md->argsString()); + } + } + + bindTextParameter(i_s_memberdef,":name",md->name()); + + if (md->memberType() == MemberType_Property) + { + if (md->isReadable()) + { + DBG_CTX(("<read>\n")); + } + if (md->isWritable()) + { + DBG_CTX(("<write>\n")); + } + } +#if 0 + if (md->memberType()==MemberType_Variable && md->bitfieldString()) + { + QCString bitfield = md->bitfieldString(); + if (bitfield.at(0)==':') bitfield=bitfield.mid(1); + t << " <bitfield>" << bitfield << "</bitfield>" << endl; + } + + MemberDef *rmd = md->reimplements(); + if (rmd) + { + t << " <reimplements refid=\"" + << memberOutputFileBase(rmd) << "_1" << rmd->anchor() << "\">" + << convertToXML(rmd->name()) << "</reimplements>" << endl; + } + LockingPtr<MemberList> rbml = md->reimplementedBy(); + if (rbml!=0) + { + MemberListIterator mli(*rbml); + for (mli.toFirst();(rmd=mli.current());++mli) + { + t << " <reimplementedby refid=\"" + << memberOutputFileBase(rmd) << "_1" << rmd->anchor() << "\">" + << convertToXML(rmd->name()) << "</reimplementedby>" << endl; + } + } +#endif + if (isFunc) //function + { + LockingPtr<ArgumentList> declAl = md->declArgumentList(); + LockingPtr<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(); + DBG_CTX(("<param>\n")); + if (!a->attrib.isEmpty()) + { + DBG_CTX(("<attributes>:%s\n",a->attrib.data())); + } + if (!a->type.isEmpty()) + { + StringList l; + linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,a->type); + + QCString *s=l.first(); + while (s) + { + insertMemberReference(db,md->anchor().data(),s->data(),def->getDefFileName().data(),md->getDefLine(),1); + s=l.next(); + } + } + if (!a->name.isEmpty()) + { + DBG_CTX(("<declname>%s\n",a->name.data())); + } + if (defArg && !defArg->name.isEmpty() && defArg->name!=a->name) + { + DBG_CTX(("<defname>%s\n",defArg->name.data())); + } + if (!a->array.isEmpty()) + { + DBG_CTX(("<array>%s",a->array.data())); + } + if (!a->defval.isEmpty()) + { + StringList l; + linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,a->defval); + } + if (defArg) ++defAli; + } + } + } + else if (md->memberType()==MemberType_Define && + md->argsString()) // define + { + 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) + { + DBG_CTX(("<param><defname>%s\n",a->type.data())); + } + } + } + + + // Extract references from initializer + // avoid that extremely large tables are written to the output. + // todo: it's better to adhere to MAX_INITIALIZER_LINES. + // drm_mod_register_buffer, + if (!md->initializer().isEmpty() && md->initializer().length()<2000) + { + StringList l; + linkifyText(TextGeneratorSqlite3Impl(l),def,md->getBodyDef(),md,md->initializer()); + QCString *s=l.first(); + while (s) + { + 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); + s=l.next(); + } + } + +#if 0 + if (md->excpString()) + { + linkifyText(TextGeneratorXMLImpl(t),def,md->getBodyDef(),md,md->excpString()); + } +#endif + if ( md->getScopeString() ) + { + bindTextParameter(i_s_memberdef,":scope",md->getScopeString()); + } + + // File location + if (md->getDefLine() != -1) + { + int id_file = insertFile(db,md->getDefFileName()); + if (id_file!=-1) + { + bindIntParameter(i_s_memberdef,":id_file",id_file); + bindIntParameter(i_s_memberdef,":line",md->getDefLine()); + bindIntParameter(i_s_memberdef,":column",md->getDefColumn()); + + if (md->getStartBodyLine()!=-1) + { + int id_bfile = insertFile(db,md->getBodyDef()->absFilePath()); + if (id_bfile == -1) exit(-1); + bindIntParameter(i_s_memberdef,":id_ibfile",id_bfile); + bindIntParameter(i_s_memberdef,":bline",md->getStartBodyLine()); + + // XXX implement getStartBodyColumn + bindIntParameter(i_s_memberdef,":bcolumn",1); + } + } + } + + + step(db,i_s_memberdef); + /*int id_src =*/ sqlite3_last_insert_rowid(db); + + // + cross-references + // The cross-references in initializers only work when both the src and dst + // are defined. + LockingPtr<MemberSDict> mdict = md->getReferencesMembers(); + // references + if (mdict!=0) + { + MemberSDict::IteratorDict mdi(*mdict); + MemberDef *rmd; + for (mdi.toFirst();(rmd=mdi.current());++mdi) + { + insertMemberReference(db,md,rmd,mdi.currentKey()); + } + } + + mdict = md->getReferencedByMembers(); + // referencedby + if (mdict!=0) + { + MemberSDict::IteratorDict mdi(*mdict); + MemberDef *rmd; + for (mdi.toFirst();(rmd=mdi.current());++mdi) + { + insertMemberReference(db,rmd,md,mdi.currentKey()); + } + } +} + +static void generateSqlite3ForClass(sqlite3 *db, ClassDef *cd) +{ + // + brief description + // + detailed description + // + template argument list(s) + // - include file + // + member groups + // + inheritance diagram + // + list of direct super classes + // + list of direct sub classes + // + list of inner classes + // + collaboration diagram + // + list of all members + // + 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()); + + //int idx,rc; + //sqlite3_stmt *stmt ; + + // + compounddef + //stmt = i_s_compounddef; + + bindTextParameter(i_s_compounddef,":name",cd->name()); + bindTextParameter(i_s_compounddef,":kind",cd->compoundTypeString()); + bindIntParameter(i_s_compounddef,":prot",cd->protection()); + bindTextParameter(i_s_compounddef,":refid",cd->getOutputFileBase()); + + int id_file = insertFile(db,cd->getDefFileName().data()); + bindIntParameter(i_s_compounddef,":id_file",id_file); + bindIntParameter(i_s_compounddef,":line",cd->getDefLine()); + bindIntParameter(i_s_compounddef,":column",cd->getDefColumn()); + + step(db,i_s_compounddef); + sqlite3_int64 id_compound=0 ; + id_compound = sqlite3_last_insert_rowid(db); + + // + basecompoundref + if (cd->baseClasses()) + { + BaseClassListIterator bcli(*cd->baseClasses()); + BaseClassDef *bcd; + for (bcli.toFirst();(bcd=bcli.current());++bcli) + { + bindTextParameter(i_s_basecompoundref,":refid",bcd->classDef->getOutputFileBase()); + bindIntParameter(i_s_basecompoundref,":prot",bcd->prot); + bindIntParameter(i_s_basecompoundref,":virt",bcd->virt); + + if (!bcd->templSpecifiers.isEmpty()) + { + bindTextParameter(i_s_basecompoundref,":base",insertTemplateSpecifierInScope(bcd->classDef->name(),bcd->templSpecifiers)); + } + else + { + bindTextParameter(i_s_basecompoundref,":base",bcd->classDef->displayName()); + } + bindTextParameter(i_s_basecompoundref,":derived",cd->displayName()); + step(db,i_s_basecompoundref); + } + } + + // + derivedcompoundref + if (cd->subClasses()) + { + BaseClassListIterator bcli(*cd->subClasses()); + BaseClassDef *bcd; + for (bcli.toFirst();(bcd=bcli.current());++bcli) + { + bindTextParameter(i_s_derivedcompoundref,":base",cd->displayName()); + bindTextParameter(i_s_derivedcompoundref,":dervied",bcd->classDef->displayName()); + bindTextParameter(i_s_derivedcompoundref,":refid",bcd->classDef->getOutputFileBase()); + bindIntParameter(i_s_derivedcompoundref,":prot",bcd->prot); + bindIntParameter(i_s_derivedcompoundref,":virt",bcd->virt); + step(db,i_s_derivedcompoundref); + } + } + + /////////////////////////////////////////////////////////////////// + // INCLUDEINFO + IncludeInfo *ii=cd->includeInfo(); + if (ii) + { + QCString nm = ii->includeName; + if (nm.isEmpty() && ii->fileDef) nm = ii->fileDef->docName(); + if (!nm.isEmpty()) + { + bindTextParameter(c_s_includes,":refid",ii->fileDef->getOutputFileBase()); + bindIntParameter(c_s_includes,":local",ii->local); + bindTextParameter(c_s_includes,":name",nm); + int count=step(db,c_s_includes,TRUE); + if ( count==0 ) + { + bindTextParameter(i_s_includes,":refid",ii->fileDef->getOutputFileBase()); + bindIntParameter(i_s_includes,":local",ii->local); + bindTextParameter(i_s_includes,":name",nm); + step(db,i_s_includes); + } + } + } + /////////////////////////////////////////////////////////////////// + writeInnerClasses(db,cd->getClassSDict()); + writeTemplateList(db,cd); + + 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()); + } + } + + QListIterator<MemberList> 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())); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +void generateSqlite3() +{ + // + classes + // + namespaces + // + files + // - groups + // - related pages + // - examples + //QCString outputDirectory = Config_getString("SQLITE3_OUTPUT"); + 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"); + exit(-1); + } + beginTransaction(db); + pragmaTuning(db); + + initializeSchema(db); + 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); + } + } + endTransaction(db); +} + +#else // USE_SQLITE3 +void generateSqlite3() +{ + err("Error: sqlite3 support has not been compiled in!"); +} +#endif + |