diff options
Diffstat (limited to 'src/searchindex.cpp')
-rw-r--r-- | src/searchindex.cpp | 975 |
1 files changed, 430 insertions, 545 deletions
diff --git a/src/searchindex.cpp b/src/searchindex.cpp index eee1aa1..89f1681 100644 --- a/src/searchindex.cpp +++ b/src/searchindex.cpp @@ -1,8 +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 @@ -15,6 +13,7 @@ * */ + #include <ctype.h> #include <assert.h> @@ -31,12 +30,17 @@ #include "message.h" #include "version.h" #include "groupdef.h" -#include "classlist.h" #include "filedef.h" #include "memberdef.h" #include "filename.h" #include "membername.h" #include "resourcemgr.h" +#include "namespacedef.h" +#include "classdef.h" + +//--------------------------------------------------------------------------------------------- +// the following part is for the server based search engine +//--------------------------------------------------------------------------------------------- // file format: (all multi-byte values are stored in big endian format) // 4 byte header @@ -49,41 +53,33 @@ // (4 bytes index to url string + 4 bytes frequency counter) // for each url: a \0 terminated string -const int numIndexEntries = 256*256; +const size_t numIndexEntries = 256*256; //-------------------------------------------------------------------- -IndexWord::IndexWord(const char *word) : m_word(word), m_urls(17) +IndexWord::IndexWord(QCString word) : m_word(word) { - m_urls.setAutoDelete(TRUE); //printf("IndexWord::IndexWord(%s)\n",word); } void IndexWord::addUrlIndex(int idx,bool hiPriority) { //printf("IndexWord::addUrlIndex(%d,%d)\n",idx,hiPriority); - URLInfo *ui = m_urls.find(idx); - if (ui==0) + auto it = m_urls.find(idx); + if (it==m_urls.end()) { //printf("URLInfo::URLInfo(%d)\n",idx); - ui=new URLInfo(idx,0); - m_urls.insert(idx,ui); + it = m_urls.insert(std::make_pair(idx,URLInfo(idx,0))).first; } - ui->freq+=2; - if (hiPriority) ui->freq|=1; // mark as high priority document + it->second.freq+=2; + if (hiPriority) it->second.freq|=1; // mark as high priority document } //-------------------------------------------------------------------- -SearchIndex::SearchIndex() : SearchIndexIntf(Internal), - m_words(328829), m_index(numIndexEntries), m_url2IdMap(10007), m_urls(10007), m_urlIndex(-1) +SearchIndex::SearchIndex() : SearchIndexIntf(Internal) { - int i; - m_words.setAutoDelete(TRUE); - m_url2IdMap.setAutoDelete(TRUE); - m_urls.setAutoDelete(TRUE); - m_index.setAutoDelete(TRUE); - for (i=0;i<numIndexEntries;i++) m_index.insert(i,new QList<IndexWord>); + m_index.resize(numIndexEntries); } void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool isSourceFile) @@ -91,7 +87,7 @@ void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool is if (ctx==0) return; assert(!isSourceFile || ctx->definitionType()==Definition::TypeFile); //printf("SearchIndex::setCurrentDoc(%s,%s,%s)\n",name,baseName,anchor); - QCString url=isSourceFile ? (dynamic_cast<const FileDef*>(ctx))->getSourceFileBase() : ctx->getOutputFileBase(); + QCString url=isSourceFile ? (toFileDef(ctx))->getSourceFileBase() : ctx->getOutputFileBase(); url+=Config_getString(HTML_FILE_EXTENSION); QCString baseUrl = url; if (anchor) url+=QCString("#")+anchor; @@ -99,7 +95,7 @@ void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool is QCString name=ctx->qualifiedName(); if (ctx->definitionType()==Definition::TypeMember) { - const MemberDef *md = dynamic_cast<const MemberDef *>(ctx); + const MemberDef *md = toMemberDef(ctx); name.prepend((md->getLanguage()==SrcLangExt_Fortran ? theTranslator->trSubprogram(TRUE,TRUE) : theTranslator->trMember(TRUE,TRUE))+" "); @@ -116,7 +112,7 @@ void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool is { case Definition::TypePage: { - const PageDef *pd = dynamic_cast<const PageDef *>(ctx); + const PageDef *pd = toPageDef(ctx); if (pd->hasTitle()) { name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title(); @@ -129,7 +125,7 @@ void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool is break; case Definition::TypeClass: { - const ClassDef *cd = dynamic_cast<const ClassDef *>(ctx); + const ClassDef *cd = toClassDef(ctx); name.prepend(cd->compoundTypeString()+" "); } break; @@ -151,7 +147,7 @@ void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool is break; case Definition::TypeGroup: { - const GroupDef *gd = dynamic_cast<const GroupDef *>(ctx); + const GroupDef *gd = toGroupDef(ctx); if (gd->groupTitle()) { name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle(); @@ -167,16 +163,16 @@ void SearchIndex::setCurrentDoc(const Definition *ctx,const char *anchor,bool is } } - int *pIndex = m_url2IdMap.find(baseUrl); - if (pIndex==0) + auto it = m_url2IdMap.find(baseUrl.str()); + if (it == m_url2IdMap.end()) { ++m_urlIndex; - m_url2IdMap.insert(baseUrl,new int(m_urlIndex)); - m_urls.insert(m_urlIndex,new URL(name,url)); + m_url2IdMap.insert(std::make_pair(baseUrl.str(),m_urlIndex)); + m_urls.insert(std::make_pair(m_urlIndex,URL(name,url))); } else { - m_urls.insert(*pIndex,new URL(name,url)); + m_urls.insert(std::make_pair(it->second,URL(name,url))); } } @@ -208,17 +204,16 @@ void SearchIndex::addWord(const char *word,bool hiPriority,bool recurse) if (word==0 || word[0]=='\0') return; QCString wStr = QCString(word).lower(); //printf("SearchIndex::addWord(%s,%d) wStr=%s\n",word,hiPriority,wStr.data()); - IndexWord *w = m_words[wStr]; - if (w==0) + int idx=charsToIndex(wStr); + if (idx<0 || idx>=static_cast<int>(m_index.size())) return; + auto it = m_words.find(wStr.str()); + if (it==m_words.end()) { - int idx=charsToIndex(wStr); //fprintf(stderr,"addWord(%s) at index %d\n",word,idx); - if (idx<0) return; - w = new IndexWord(wStr); - m_index[idx]->append(w); - m_words.insert(wStr,w); + m_index[idx].push_back(IndexWord(wStr)); + it = m_words.insert({ wStr.str(), static_cast<int>(m_index[idx].size())-1 }).first; } - w->addUrlIndex(m_urlIndex,hiPriority); + m_index[idx][it->second].addUrlIndex(m_urlIndex,hiPriority); int i; bool found=FALSE; if (!recurse) // the first time we check if we can strip the prefix @@ -244,12 +239,12 @@ void SearchIndex::addWord(const char *word,bool hiPriority) addWord(word,hiPriority,FALSE); } -static void writeInt(QFile &f,int index) +static void writeInt(QFile &f,size_t index) { - f.putch(((uint)index)>>24); - f.putch((((uint)index)>>16)&0xff); - f.putch((((uint)index)>>8)&0xff); - f.putch(((uint)index)&0xff); + f.putch(static_cast<int>(index>>24)); + f.putch(static_cast<int>((index>>16)&0xff)); + f.putch(static_cast<int>((index>>8)&0xff)); + f.putch(static_cast<int>(index&0xff)); } static void writeString(QFile &f,const char *s) @@ -261,21 +256,19 @@ static void writeString(QFile &f,const char *s) void SearchIndex::write(const char *fileName) { - int i; - int size=4; // for the header + size_t i; + size_t size=4; // for the header size+=4*numIndexEntries; // for the index - int wordsOffset = size; + size_t wordsOffset = size; // first pass: compute the size of the wordlist for (i=0;i<numIndexEntries;i++) { - QList<IndexWord> *wlist = m_index[i]; - if (!wlist->isEmpty()) + const auto &wlist = m_index[i]; + if (!wlist.empty()) { - QListIterator<IndexWord> iwi(*wlist); - IndexWord *iw; - for (iwi.toFirst();(iw=iwi.current());++iwi) + for (const auto &iw : wlist) { - int ws = iw->word().length()+1; + int ws = iw.word().length()+1; size+=ws+4; // word + url info list offset } size+=1; // zero list terminator @@ -283,19 +276,17 @@ void SearchIndex::write(const char *fileName) } // second pass: compute the offsets in the index - int indexOffsets[numIndexEntries]; - int offset=wordsOffset; + size_t indexOffsets[numIndexEntries]; + size_t offset=wordsOffset; for (i=0;i<numIndexEntries;i++) { - QList<IndexWord> *wlist = m_index[i]; - if (!wlist->isEmpty()) + const auto &wlist = m_index[i]; + if (!wlist.empty()) { indexOffsets[i]=offset; - QListIterator<IndexWord> iwi(*wlist); - IndexWord *iw; - for (iwi.toFirst();(iw=iwi.current());++iwi) + for (const auto &iw : wlist) { - offset+= iw->word().length()+1; + offset+= iw.word().length()+1; offset+=4; // word + offset to url info array } offset+=1; // zero list terminator @@ -305,42 +296,36 @@ void SearchIndex::write(const char *fileName) indexOffsets[i]=0; } } - int padding = size; + size_t padding = size; size = (size+3)&~3; // round up to 4 byte boundary padding = size - padding; - //int statsOffset = size; - //IndexWord *iw; - int *wordStatOffsets = new int[m_words.count()]; + std::vector<size_t> wordStatOffsets(m_words.size()); int count=0; // third pass: compute offset to stats info for each word for (i=0;i<numIndexEntries;i++) { - QList<IndexWord> *wlist = m_index[i]; - if (!wlist->isEmpty()) + const auto &wlist = m_index[i]; + if (!wlist.empty()) { - QListIterator<IndexWord> iwi(*wlist); - IndexWord *iw; - for (iwi.toFirst();(iw=iwi.current());++iwi) + for (const auto &iw : wlist) { //printf("wordStatOffsets[%d]=%d\n",count,size); wordStatOffsets[count++] = size; - size+=4+iw->urls().count()*8; // count + (url_index,freq) per url + size+=4 + iw.urls().size() * 8; // count + (url_index,freq) per url } } } - int *urlOffsets = new int[m_urls.count()]; - //int urlsOffset = size; - QIntDictIterator<URL> udi(m_urls); - URL *url; - for (udi.toFirst();(url=udi.current());++udi) + std::vector<size_t> urlOffsets(m_urls.size()); + for (const auto &udi : m_urls) { - urlOffsets[udi.currentKey()]=size; - size+=url->name.length()+1+ - url->url.length()+1; + urlOffsets[udi.first]=size; + size+=udi.second.name.length()+1+ + udi.second.url.length()+1; } + //printf("Total size %x bytes (word=%x stats=%x urls=%x)\n",size,wordsOffset,statsOffset,urlsOffset); QFile f(fileName); if (f.open(IO_WriteOnly)) @@ -356,14 +341,12 @@ void SearchIndex::write(const char *fileName) count=0; for (i=0;i<numIndexEntries;i++) { - QList<IndexWord> *wlist = m_index[i]; - if (!wlist->isEmpty()) + const auto &wlist = m_index[i]; + if (!wlist.empty()) { - QListIterator<IndexWord> iwi(*wlist); - IndexWord *iw; - for (iwi.toFirst();(iw=iwi.current());++iwi) + for (const auto &iw : wlist) { - writeString(f,iw->word()); + writeString(f,iw.word()); writeInt(f,wordStatOffsets[count++]); } f.putch(0); @@ -374,37 +357,29 @@ void SearchIndex::write(const char *fileName) // write word statistics for (i=0;i<numIndexEntries;i++) { - QList<IndexWord> *wlist = m_index[i]; - if (!wlist->isEmpty()) + const auto &wlist = m_index[i]; + if (!wlist.empty()) { - QListIterator<IndexWord> iwi(*wlist); - IndexWord *iw; - for (iwi.toFirst();(iw=iwi.current());++iwi) + for (const auto &iw : wlist) { - int numUrls = iw->urls().count(); + size_t numUrls = iw.urls().size(); writeInt(f,numUrls); - QIntDictIterator<URLInfo> uli(iw->urls()); - URLInfo *ui; - for (uli.toFirst();(ui=uli.current());++uli) + for (const auto &ui : iw.urls()) { - writeInt(f,urlOffsets[ui->urlIdx]); - writeInt(f,ui->freq); + writeInt(f,urlOffsets[ui.second.urlIdx]); + writeInt(f,ui.second.freq); } } } } // write urls - QIntDictIterator<URL> udi(m_urls); - URL *url; - for (udi.toFirst();(url=udi.current());++udi) + for (const auto &udi : m_urls) { - writeString(f,url->name); - writeString(f,url->url); + writeString(f,udi.second.name); + writeString(f,udi.second.url); } } - delete[] urlOffsets; - delete[] wordStatOffsets; } @@ -424,29 +399,19 @@ struct SearchDocEntry struct SearchIndexExternal::Private { - Private() : docEntries(12251) {} - SDict<SearchDocEntry> docEntries; + std::map<std::string,SearchDocEntry> docEntries; SearchDocEntry *current = 0; }; -SearchIndexExternal::SearchIndexExternal() : SearchIndexIntf(External) +SearchIndexExternal::SearchIndexExternal() : SearchIndexIntf(External), p(std::make_unique<Private>()) { - p = new SearchIndexExternal::Private; - p->docEntries.setAutoDelete(TRUE); - p->current=0; -} - -SearchIndexExternal::~SearchIndexExternal() -{ - //printf("p->docEntries.count()=%d\n",p->docEntries.count()); - delete p; } static QCString definitionToName(const Definition *ctx) { if (ctx && ctx->definitionType()==Definition::TypeMember) { - const MemberDef *md = dynamic_cast<const MemberDef*>(ctx); + const MemberDef *md = toMemberDef(ctx); if (md->isFunction()) return "function"; else if (md->isSlot()) @@ -477,7 +442,7 @@ static QCString definitionToName(const Definition *ctx) switch(ctx->definitionType()) { case Definition::TypeClass: - return (dynamic_cast<const ClassDef*>(ctx))->compoundTypeString(); + return (toClassDef(ctx))->compoundTypeString(); case Definition::TypeFile: return "file"; case Definition::TypeNamespace: @@ -499,29 +464,28 @@ static QCString definitionToName(const Definition *ctx) void SearchIndexExternal::setCurrentDoc(const Definition *ctx,const char *anchor,bool isSourceFile) { - QCString extId = stripPath(Config_getString(EXTERNAL_SEARCH_ID)); - QCString baseName = isSourceFile ? (dynamic_cast<const FileDef*>(ctx))->getSourceFileBase() : ctx->getOutputFileBase(); + static QCString extId = stripPath(Config_getString(EXTERNAL_SEARCH_ID)); + QCString baseName = isSourceFile ? (toFileDef(ctx))->getSourceFileBase() : ctx->getOutputFileBase(); QCString url = baseName + Doxygen::htmlFileExtension; if (anchor) url+=QCString("#")+anchor; QCString key = extId+";"+url; - p->current = p->docEntries.find(key); - //printf("setCurrentDoc(url=%s,isSourceFile=%d) current=%p\n",url.data(),isSourceFile,p->current); - if (!p->current) + auto it = p->docEntries.find(key.str()); + if (it == p->docEntries.end()) { - SearchDocEntry *e = new SearchDocEntry; - e->type = isSourceFile ? QCString("source") : definitionToName(ctx); - e->name = ctx->qualifiedName(); + SearchDocEntry e; + e.type = isSourceFile ? QCString("source") : definitionToName(ctx); + e.name = ctx->qualifiedName(); if (ctx->definitionType()==Definition::TypeMember) { - e->args = (dynamic_cast<const MemberDef*>(ctx))->argsString(); + e.args = (toMemberDef(ctx))->argsString(); } - e->extId = extId; - e->url = url; - p->current = e; - p->docEntries.append(key,e); + e.extId = extId; + e.url = url; + it = p->docEntries.insert({key.str(),e}).first; //printf("searchIndexExt %s : %s\n",e->name.data(),e->url.data()); } + p->current = &it->second; } void SearchIndexExternal::addWord(const char *word,bool hiPriority) @@ -541,26 +505,25 @@ void SearchIndexExternal::write(const char *fileName) FTextStream t(&f); t << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl; t << "<add>" << endl; - SDict<SearchDocEntry>::Iterator it(p->docEntries); - SearchDocEntry *doc; - for (it.toFirst();(doc=it.current());++it) + for (auto &kv : p->docEntries) { - doc->normalText.addChar(0); // make sure buffer ends with a 0 terminator - doc->importantText.addChar(0); // make sure buffer ends with a 0 terminator + SearchDocEntry &doc = kv.second; + doc.normalText.addChar(0); // make sure buffer ends with a 0 terminator + doc.importantText.addChar(0); // make sure buffer ends with a 0 terminator t << " <doc>" << endl; - t << " <field name=\"type\">" << doc->type << "</field>" << endl; - t << " <field name=\"name\">" << convertToXML(doc->name) << "</field>" << endl; - if (!doc->args.isEmpty()) + t << " <field name=\"type\">" << doc.type << "</field>" << endl; + t << " <field name=\"name\">" << convertToXML(doc.name) << "</field>" << endl; + if (!doc.args.isEmpty()) { - t << " <field name=\"args\">" << convertToXML(doc->args) << "</field>" << endl; + t << " <field name=\"args\">" << convertToXML(doc.args) << "</field>" << endl; } - if (!doc->extId.isEmpty()) + if (!doc.extId.isEmpty()) { - t << " <field name=\"tag\">" << convertToXML(doc->extId) << "</field>" << endl; + t << " <field name=\"tag\">" << convertToXML(doc.extId) << "</field>" << endl; } - t << " <field name=\"url\">" << convertToXML(doc->url) << "</field>" << endl; - t << " <field name=\"keywords\">" << convertToXML(doc->importantText.get()) << "</field>" << endl; - t << " <field name=\"text\">" << convertToXML(doc->normalText.get()) << "</field>" << endl; + t << " <field name=\"url\">" << convertToXML(doc.url) << "</field>" << endl; + t << " <field name=\"keywords\">" << convertToXML(doc.importantText.get()) << "</field>" << endl; + t << " <field name=\"text\">" << convertToXML(doc.normalText.get()) << "</field>" << endl; t << " </doc>" << endl; } t << "</add>" << endl; @@ -571,19 +534,96 @@ void SearchIndexExternal::write(const char *fileName) } } -//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------------------------- // the following part is for the javascript based search engine +//--------------------------------------------------------------------------------------------- -#include "memberdef.h" -#include "namespacedef.h" -#include "pagedef.h" -#include "classdef.h" -#include "filedef.h" -#include "language.h" -#include "doxygen.h" -#include "message.h" +QCString searchName(const Definition *d) +{ + return d->definitionType()==Definition::TypeGroup ? QCString(toGroupDef(d)->groupTitle()) : + d->definitionType()==Definition::TypePage ? toPageDef(d)->title() : + d->localName(); +} -static SearchIndexInfo g_searchIndexInfo[NUM_SEARCH_INDICES]; +QCString searchId(const Definition *d) +{ + QCString s = searchName(d); + int c; + uint i; + QCString result; + for (i=0;i<s.length();i++) + { + c=s.at(i); + if (c>0x7f || c<0) // part of multibyte character + { + result+=(char)c; + } + else if (isalnum(c)) // simply alpha numerical character + { + result+=(char)tolower(c); + } + else // other 'unprintable' characters + { + char val[4]; + sprintf(val,"_%02x",(uchar)c); + result+=val; + } + } + return result; +} + + +#define SEARCH_INDEX_ALL 0 +#define SEARCH_INDEX_CLASSES 1 +#define SEARCH_INDEX_INTERFACES 2 +#define SEARCH_INDEX_STRUCTS 3 +#define SEARCH_INDEX_EXCEPTIONS 4 +#define SEARCH_INDEX_NAMESPACES 5 +#define SEARCH_INDEX_FILES 6 +#define SEARCH_INDEX_FUNCTIONS 7 +#define SEARCH_INDEX_VARIABLES 8 +#define SEARCH_INDEX_TYPEDEFS 9 +#define SEARCH_INDEX_SEQUENCES 10 +#define SEARCH_INDEX_DICTIONARIES 11 +#define SEARCH_INDEX_ENUMS 12 +#define SEARCH_INDEX_ENUMVALUES 13 +#define SEARCH_INDEX_PROPERTIES 14 +#define SEARCH_INDEX_EVENTS 15 +#define SEARCH_INDEX_RELATED 16 +#define SEARCH_INDEX_DEFINES 17 +#define SEARCH_INDEX_GROUPS 18 +#define SEARCH_INDEX_PAGES 19 + +static std::array<SearchIndexInfo,NUM_SEARCH_INDICES> g_searchIndexInfo = +{ { + // index name getText symbolList + { /* SEARCH_INDEX_ALL */ "all" , []() { return theTranslator->trAll(); }, {} }, + { /* SEARCH_INDEX_CLASSES */ "classes" , []() { return theTranslator->trClasses(); }, {} }, + { /* SEARCH_INDEX_INTERFACES */ "interfaces" , []() { return theTranslator->trSliceInterfaces(); }, {} }, + { /* SEARCH_INDEX_STRUCTS */ "structs" , []() { return theTranslator->trStructs(); }, {} }, + { /* SEARCH_INDEX_EXCEPTIONS */ "exceptions" , []() { return theTranslator->trExceptions(); }, {} }, + { /* SEARCH_INDEX_NAMESPACES */ "namespaces" , []() { return Config_getBool(OPTIMIZE_OUTPUT_SLICE) ? + theTranslator->trModules() : + theTranslator->trNamespace(TRUE,FALSE); }, {} }, + { /* SEARCH_INDEX_FILES */ "files" , []() { return theTranslator->trFile(TRUE,FALSE); }, {} }, + { /* SEARCH_INDEX_FUNCTIONS */ "functions" , []() { return Config_getBool(OPTIMIZE_OUTPUT_SLICE) ? + theTranslator->trOperations() : + theTranslator->trFunctions(); }, {} }, + { /* SEARCH_INDEX_VARIABLES */ "variables" , []() { return Config_getBool(OPTIMIZE_OUTPUT_SLICE) ? + theTranslator->trConstants() : + theTranslator->trVariables(); }, {} }, + { /* SEARCH_INDEX_TYPEDEFS */ "typedefs" , []() { return theTranslator->trTypedefs(); }, {} }, + { /* SEARCH_INDEX_SEQUENCES */ "sequences" , []() { return theTranslator->trSequences(); }, {} }, + { /* SEARCH_INDEX_DICTIONARIES */ "dictionaries", []() { return theTranslator->trDictionaries(); }, {} }, + { /* SEARCH_INDEX_ENUMS */ "enums" , []() { return theTranslator->trEnumerations(); }, {} }, + { /* SEARCH_INDEX_ENUMVALUES */ "enumvalues" , []() { return theTranslator->trEnumerationValues(); }, {} }, + { /* SEARCH_INDEX_PROPERTIES */ "properties" , []() { return theTranslator->trProperties(); }, {} }, + { /* SEARCH_INDEX_EVENTS */ "events" , []() { return theTranslator->trEvents(); }, {} }, + { /* SEARCH_INDEX_RELATED */ "related" , []() { return theTranslator->trFriends(); }, {} }, + { /* SEARCH_INDEX_DEFINES */ "defines" , []() { return theTranslator->trDefines(); }, {} }, + { /* SEARCH_INDEX_GROUPS */ "groups" , []() { return theTranslator->trGroup(TRUE,FALSE); }, {} }, + { /* SEARCH_INDEX_PAGES */ "pages" , []() { return theTranslator->trPage(TRUE,FALSE); }, {} } +} }; static void addMemberToSearchIndex(const MemberDef *md) { @@ -603,55 +643,56 @@ static void addMemberToSearchIndex(const MemberDef *md) QCString n = md->name(); if (!n.isEmpty()) { - uint letter = getUtf8CodeToLower(n,0); + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(n,letter,CaseModifier::ToLower); bool isFriendToHide = hideFriendCompounds && (QCString(md->typeString())=="friend class" || QCString(md->typeString())=="friend struct" || QCString(md->typeString())=="friend union"); if (!(md->isFriend() && isFriendToHide)) { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,md); } if (md->isFunction() || md->isSlot() || md->isSignal()) { - g_searchIndexInfo[SEARCH_INDEX_FUNCTIONS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_FUNCTIONS].add(letter,md); } else if (md->isVariable()) { - g_searchIndexInfo[SEARCH_INDEX_VARIABLES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_VARIABLES].add(letter,md); } else if (md->isSequence()) { - g_searchIndexInfo[SEARCH_INDEX_SEQUENCES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_SEQUENCES].add(letter,md); } else if (md->isDictionary()) { - g_searchIndexInfo[SEARCH_INDEX_DICTIONARIES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_DICTIONARIES].add(letter,md); } else if (md->isTypedef()) { - g_searchIndexInfo[SEARCH_INDEX_TYPEDEFS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_TYPEDEFS].add(letter,md); } else if (md->isEnumerate()) { - g_searchIndexInfo[SEARCH_INDEX_ENUMS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_ENUMS].add(letter,md); } else if (md->isEnumValue()) { - g_searchIndexInfo[SEARCH_INDEX_ENUMVALUES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_ENUMVALUES].add(letter,md); } else if (md->isProperty()) { - g_searchIndexInfo[SEARCH_INDEX_PROPERTIES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_PROPERTIES].add(letter,md); } else if (md->isEvent()) { - g_searchIndexInfo[SEARCH_INDEX_EVENTS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_EVENTS].add(letter,md); } else if (md->isRelated() || md->isForeign() || (md->isFriend() && !isFriendToHide)) { - g_searchIndexInfo[SEARCH_INDEX_RELATED].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_RELATED].add(letter,md); } } } @@ -664,264 +705,165 @@ static void addMemberToSearchIndex(const MemberDef *md) QCString n = md->name(); if (!n.isEmpty()) { - uint letter = getUtf8CodeToLower(n,0); - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,md); + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(n,letter,CaseModifier::ToLower); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,md); if (md->isFunction()) { - g_searchIndexInfo[SEARCH_INDEX_FUNCTIONS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_FUNCTIONS].add(letter,md); } else if (md->isVariable()) { - g_searchIndexInfo[SEARCH_INDEX_VARIABLES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_VARIABLES].add(letter,md); } else if (md->isSequence()) { - g_searchIndexInfo[SEARCH_INDEX_SEQUENCES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_SEQUENCES].add(letter,md); } else if (md->isDictionary()) { - g_searchIndexInfo[SEARCH_INDEX_DICTIONARIES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_DICTIONARIES].add(letter,md); } else if (md->isTypedef()) { - g_searchIndexInfo[SEARCH_INDEX_TYPEDEFS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_TYPEDEFS].add(letter,md); } else if (md->isEnumerate()) { - g_searchIndexInfo[SEARCH_INDEX_ENUMS].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_ENUMS].add(letter,md); } else if (md->isEnumValue()) { - g_searchIndexInfo[SEARCH_INDEX_ENUMVALUES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_ENUMVALUES].add(letter,md); } else if (md->isDefine()) { - g_searchIndexInfo[SEARCH_INDEX_DEFINES].symbolList.append(letter,md); + g_searchIndexInfo[SEARCH_INDEX_DEFINES].add(letter,md); } } } } -// see also function convertToId() in search.js, which should match in -// behaviour -static QCString searchId(const QCString &s) -{ - int c; - uint i; - QCString result; - for (i=0;i<s.length();i++) - { - c=s.at(i); - if (c>0x7f || c<0) // part of multibyte character - { - result+=(char)c; - } - else if (isalnum(c)) // simply alpha numerical character - { - result+=(char)tolower(c); - } - else // other 'unprintable' characters - { - char val[4]; - sprintf(val,"_%02x",(uchar)c); - result+=val; - } - } - return result; -} +//--------------------------------------------------------------------------------------------- void createJavaScriptSearchIndex() { - bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE); - - // set index names - g_searchIndexInfo[SEARCH_INDEX_ALL].name = "all"; - g_searchIndexInfo[SEARCH_INDEX_CLASSES].name = "classes"; - g_searchIndexInfo[SEARCH_INDEX_INTERFACES].name = "interfaces"; - g_searchIndexInfo[SEARCH_INDEX_STRUCTS].name = "structs"; - g_searchIndexInfo[SEARCH_INDEX_EXCEPTIONS].name = "exceptions"; - g_searchIndexInfo[SEARCH_INDEX_NAMESPACES].name = "namespaces"; - g_searchIndexInfo[SEARCH_INDEX_FILES].name = "files"; - g_searchIndexInfo[SEARCH_INDEX_FUNCTIONS].name = "functions"; - g_searchIndexInfo[SEARCH_INDEX_VARIABLES].name = "variables"; - g_searchIndexInfo[SEARCH_INDEX_TYPEDEFS].name = "typedefs"; - g_searchIndexInfo[SEARCH_INDEX_SEQUENCES].name = "sequences"; - g_searchIndexInfo[SEARCH_INDEX_DICTIONARIES].name = "dictionaries"; - g_searchIndexInfo[SEARCH_INDEX_ENUMS].name = "enums"; - g_searchIndexInfo[SEARCH_INDEX_ENUMVALUES].name = "enumvalues"; - g_searchIndexInfo[SEARCH_INDEX_PROPERTIES].name = "properties"; - g_searchIndexInfo[SEARCH_INDEX_EVENTS].name = "events"; - g_searchIndexInfo[SEARCH_INDEX_RELATED].name = "related"; - g_searchIndexInfo[SEARCH_INDEX_DEFINES].name = "defines"; - g_searchIndexInfo[SEARCH_INDEX_GROUPS].name = "groups"; - g_searchIndexInfo[SEARCH_INDEX_PAGES].name = "pages"; - - // set index texts - g_searchIndexInfo[SEARCH_INDEX_ALL].text = theTranslator->trAll(); - g_searchIndexInfo[SEARCH_INDEX_CLASSES].text = theTranslator->trClasses(); - g_searchIndexInfo[SEARCH_INDEX_INTERFACES].text = theTranslator->trSliceInterfaces(); - g_searchIndexInfo[SEARCH_INDEX_STRUCTS].text = theTranslator->trStructs(); - g_searchIndexInfo[SEARCH_INDEX_EXCEPTIONS].text = theTranslator->trExceptions(); - g_searchIndexInfo[SEARCH_INDEX_NAMESPACES].text = sliceOpt ? theTranslator->trModules() : - theTranslator->trNamespace(TRUE,FALSE); - g_searchIndexInfo[SEARCH_INDEX_FILES].text = theTranslator->trFile(TRUE,FALSE); - g_searchIndexInfo[SEARCH_INDEX_FUNCTIONS].text = sliceOpt ? theTranslator->trOperations() : - theTranslator->trFunctions(); - g_searchIndexInfo[SEARCH_INDEX_VARIABLES].text = sliceOpt ? theTranslator->trConstants() : - theTranslator->trVariables(); - g_searchIndexInfo[SEARCH_INDEX_TYPEDEFS].text = theTranslator->trTypedefs(); - g_searchIndexInfo[SEARCH_INDEX_SEQUENCES].text = theTranslator->trSequences(); - g_searchIndexInfo[SEARCH_INDEX_DICTIONARIES].text = theTranslator->trDictionaries(); - g_searchIndexInfo[SEARCH_INDEX_ENUMS].text = theTranslator->trEnumerations(); - g_searchIndexInfo[SEARCH_INDEX_ENUMVALUES].text = theTranslator->trEnumerationValues(); - g_searchIndexInfo[SEARCH_INDEX_PROPERTIES].text = theTranslator->trProperties(); - g_searchIndexInfo[SEARCH_INDEX_EVENTS].text = theTranslator->trEvents(); - g_searchIndexInfo[SEARCH_INDEX_RELATED].text = theTranslator->trFriends(); - g_searchIndexInfo[SEARCH_INDEX_DEFINES].text = theTranslator->trDefines(); - g_searchIndexInfo[SEARCH_INDEX_GROUPS].text = theTranslator->trGroup(TRUE,FALSE); - g_searchIndexInfo[SEARCH_INDEX_PAGES].text = theTranslator->trPage(TRUE,FALSE); - - // add symbols to letter -> symbol list map - // index classes - ClassSDict::Iterator cli(*Doxygen::classSDict); - ClassDef *cd; - for (;(cd=cli.current());++cli) + for (const auto &cd : *Doxygen::classLinkedMap) { - uint letter = getUtf8CodeToLower(cd->localName(),0); - if (cd->isLinkable() && isId(letter)) + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(cd->localName(),letter,CaseModifier::ToLower); + if (cd->isLinkable()) { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,cd); - if (sliceOpt) + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,cd.get()); + if (Config_getBool(OPTIMIZE_OUTPUT_SLICE)) { if (cd->compoundType()==ClassDef::Interface) { - g_searchIndexInfo[SEARCH_INDEX_INTERFACES].symbolList.append(letter,cd); + g_searchIndexInfo[SEARCH_INDEX_INTERFACES].add(letter,cd.get()); } else if (cd->compoundType()==ClassDef::Struct) { - g_searchIndexInfo[SEARCH_INDEX_STRUCTS].symbolList.append(letter,cd); + g_searchIndexInfo[SEARCH_INDEX_STRUCTS].add(letter,cd.get()); } else if (cd->compoundType()==ClassDef::Exception) { - g_searchIndexInfo[SEARCH_INDEX_EXCEPTIONS].symbolList.append(letter,cd); + g_searchIndexInfo[SEARCH_INDEX_EXCEPTIONS].add(letter,cd.get()); } else // cd->compoundType()==ClassDef::Class { - g_searchIndexInfo[SEARCH_INDEX_CLASSES].symbolList.append(letter,cd); + g_searchIndexInfo[SEARCH_INDEX_CLASSES].add(letter,cd.get()); } } else // non slice optimisation: group all types under classes { - g_searchIndexInfo[SEARCH_INDEX_CLASSES].symbolList.append(letter,cd); + g_searchIndexInfo[SEARCH_INDEX_CLASSES].add(letter,cd.get()); } } } // index namespaces - NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict); - NamespaceDef *nd; - for (;(nd=nli.current());++nli) + for (const auto &nd : *Doxygen::namespaceLinkedMap) { - uint letter = getUtf8CodeToLower(nd->name(),0); - if (nd->isLinkable() && isId(letter)) + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(nd->name(),letter,CaseModifier::ToLower); + if (nd->isLinkable()) { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,nd); - g_searchIndexInfo[SEARCH_INDEX_NAMESPACES].symbolList.append(letter,nd); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,nd.get()); + g_searchIndexInfo[SEARCH_INDEX_NAMESPACES].add(letter,nd.get()); } } // index files - FileNameListIterator fnli(*Doxygen::inputNameList); - FileName *fn; - for (;(fn=fnli.current());++fnli) + for (const auto &fn : *Doxygen::inputNameLinkedMap) { - FileNameIterator fni(*fn); - FileDef *fd; - for (;(fd=fni.current());++fni) + for (const auto &fd : *fn) { - uint letter = getUtf8CodeToLower(fd->name(),0); - if (fd->isLinkable() && isId(letter)) + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(fd->name(),letter,CaseModifier::ToLower); + if (fd->isLinkable()) { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,fd); - g_searchIndexInfo[SEARCH_INDEX_FILES].symbolList.append(letter,fd); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,fd.get()); + g_searchIndexInfo[SEARCH_INDEX_FILES].add(letter,fd.get()); } } } // index class members { - MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict); - MemberName *mn; // for each member name - for (mnli.toFirst();(mn=mnli.current());++mnli) + for (const auto &mn : *Doxygen::memberNameLinkedMap) { - MemberDef *md; - MemberNameIterator mni(*mn); // for each member definition - for (mni.toFirst();(md=mni.current());++mni) + for (const auto &md : *mn) { - addMemberToSearchIndex(md); + addMemberToSearchIndex(md.get()); } } } // index file/namespace members { - MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict); - MemberName *mn; // for each member name - for (fnli.toFirst();(mn=fnli.current());++fnli) + for (const auto &mn : *Doxygen::functionNameLinkedMap) { - MemberDef *md; - MemberNameIterator mni(*mn); // for each member definition - for (mni.toFirst();(md=mni.current());++mni) + for (const auto &md : *mn) { - addMemberToSearchIndex(md); + addMemberToSearchIndex(md.get()); } } } // index groups - GroupSDict::Iterator gli(*Doxygen::groupSDict); - GroupDef *gd; - for (gli.toFirst();(gd=gli.current());++gli) + for (const auto &gd : *Doxygen::groupLinkedMap) { if (gd->isLinkable()) { QCString title = gd->groupTitle(); if (!title.isEmpty()) // TODO: able searching for all word in the title { - uchar charCode = title.at(0); - uint letter = charCode<128 ? tolower(charCode) : charCode; - if (isId(letter)) - { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,gd); - g_searchIndexInfo[SEARCH_INDEX_GROUPS].symbolList.append(letter,gd); - } + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(title,letter,CaseModifier::ToLower); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,gd.get()); + g_searchIndexInfo[SEARCH_INDEX_GROUPS].add(letter,gd.get()); } } } // index pages - PageSDict::Iterator pdi(*Doxygen::pageSDict); - PageDef *pd=0; - for (pdi.toFirst();(pd=pdi.current());++pdi) + for (const auto &pd : *Doxygen::pageLinkedMap) { if (pd->isLinkable()) { QCString title = pd->title(); if (!title.isEmpty()) { - uchar charCode = title.at(0); - uint letter = charCode<128 ? tolower(charCode) : charCode; - if (isId(letter)) - { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,pd); - g_searchIndexInfo[SEARCH_INDEX_PAGES].symbolList.append(letter,pd); - } + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(title,letter,CaseModifier::ToLower); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,pd.get()); + g_searchIndexInfo[SEARCH_INDEX_PAGES].add(letter,pd.get()); } } } @@ -930,47 +872,45 @@ void createJavaScriptSearchIndex() QCString title = Doxygen::mainPage->title(); if (!title.isEmpty()) { - uchar charCode = title.at(0); - uint letter = charCode<128 ? tolower(charCode) : charCode; - if (isId(letter)) - { - g_searchIndexInfo[SEARCH_INDEX_ALL].symbolList.append(letter,Doxygen::mainPage); - g_searchIndexInfo[SEARCH_INDEX_PAGES].symbolList.append(letter,Doxygen::mainPage); - } + char letter[MAX_UTF8_CHAR_SIZE]; + getUtf8Char(title,letter,CaseModifier::ToLower); + g_searchIndexInfo[SEARCH_INDEX_ALL].add(letter,Doxygen::mainPage.get()); + g_searchIndexInfo[SEARCH_INDEX_PAGES].add(letter,Doxygen::mainPage.get()); } } // sort all lists - int i; - for (i=0;i<NUM_SEARCH_INDICES;i++) + for (auto &sii : g_searchIndexInfo) // for each index { - SIntDict<SearchIndexList>::Iterator it(g_searchIndexInfo[i].symbolList); - SearchIndexList *sl; - for (it.toFirst();(sl=it.current());++it) + for (auto &kv : sii.symbolMap) // for each symbol in the index { - sl->sort(); + // sort the symbols (first on "search" name, and then on full name) + std::sort(kv.second.begin(), + kv.second.end(), + [](const Definition *d1,const Definition *d2) + { + int eq = qstricmp(searchName(d1),searchName(d2)); // search name first + return eq==0 ? qstricmp(d1->name(),d2->name())<0 : eq<0; // then full name + }); } } } void writeJavaScriptSearchIndex() { - int i; int cnt = 0; // write index files QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search"; - for (i=0;i<NUM_SEARCH_INDICES;i++) // for each index + for (auto &sii : g_searchIndexInfo) { - SIntDict<SearchIndexList>::Iterator it(g_searchIndexInfo[i].symbolList); - SearchIndexList *sl; int p=0; - for (it.toFirst();(sl=it.current());++it,++p) // for each letter + for (const auto &kv : sii.symbolMap) { QCString baseName; - baseName.sprintf("%s_%x",g_searchIndexInfo[i].name.data(),p); + baseName.sprintf("%s_%x",sii.name.data(),p); - QCString fileName = searchDirName + "/"+baseName+".html"; + QCString fileName = searchDirName + "/"+baseName+Doxygen::htmlFileExtension; QCString dataFileName = searchDirName + "/"+baseName+".js"; QFile outFile(fileName); @@ -982,9 +922,10 @@ void writeJavaScriptSearchIndex() t << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"" " \"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl; - t << "<html><head><title></title>" << endl; + t << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl; + t << "<head><title></title>" << endl; t << "<meta http-equiv=\"Content-Type\" content=\"text/xhtml;charset=UTF-8\"/>" << endl; - t << "<meta name=\"generator\" content=\"Doxygen " << getVersion() << "\"/>" << endl; + t << "<meta name=\"generator\" content=\"Doxygen " << getDoxygenVersion() << "\"/>" << endl; t << "<link rel=\"stylesheet\" type=\"text/css\" href=\"search.css\"/>" << endl; t << "<script type=\"text/javascript\" src=\"" << baseName << ".js\"></script>" << endl; t << "<script type=\"text/javascript\" src=\"search.js\"></script>" << endl; @@ -993,24 +934,30 @@ void writeJavaScriptSearchIndex() t << "<div id=\"SRIndex\">" << endl; t << "<div class=\"SRStatus\" id=\"Loading\">" << theTranslator->trLoading() << "</div>" << endl; t << "<div id=\"SRResults\"></div>" << endl; // here the results will be inserted - t << "<script type=\"text/javascript\"><!--" << endl; - t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n"; + t << "<script type=\"text/javascript\">" << endl; + t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n"; t << "createResults();" << endl; // this function will insert the results - t << "/* @license-end */\n"; - t << "--></script>" << endl; + t << "/* @license-end */\n"; + t << "</script>" << endl; t << "<div class=\"SRStatus\" id=\"Searching\">" << theTranslator->trSearching() << "</div>" << endl; t << "<div class=\"SRStatus\" id=\"NoMatches\">" << theTranslator->trNoMatches() << "</div>" << endl; - t << "<script type=\"text/javascript\"><!--" << endl; - t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n"; + t << "<script type=\"text/javascript\">" << endl; + t << "/* @license magnet:?xt=urn:btih:cf05388f2679ee054f2beb29a391d25f4e673ac3&dn=gpl-2.0.txt GPL-v2 */\n"; t << "document.getElementById(\"Loading\").style.display=\"none\";" << endl; t << "document.getElementById(\"NoMatches\").style.display=\"none\";" << endl; t << "var searchResults = new SearchResults(\"searchResults\");" << endl; t << "searchResults.Search();" << endl; - t << "/* @license-end */\n"; - t << "--></script>" << endl; + t << "window.addEventListener(\"message\", function(event) {" << endl; + t << " if (event.data == \"take_focus\") {" << endl; + t << " var elem = searchResults.NavNext(0);" << endl; + t << " if (elem) elem.focus();" << endl; + t << " }" << endl; + t << "});" << endl; + t << "/* @license-end */\n"; + t << "</script>" << endl; t << "</div>" << endl; // SRIndex t << "</body>" << endl; t << "</html>" << endl; @@ -1031,44 +978,61 @@ void writeJavaScriptSearchIndex() ti << "[" << endl; bool firstEntry=TRUE; - SDict<SearchDefinitionList>::Iterator li(*sl); - SearchDefinitionList *dl; - int itemCount=0; - for (li.toFirst();(dl=li.current());++li) + int childCount=0; + QCString lastName; + const Definition *prevScope = 0; + for (auto it = kv.second.begin(); it!=kv.second.end();) { - Definition *d = dl->getFirst(); + const Definition *d = *it; + QCString sname = searchName(d); + QCString id = searchId(d); - if (!firstEntry) + if (sname!=lastName) // this item has a different search word { - ti << "," << endl; + if (!firstEntry) + { + ti << "]]]"; + ti << "," << endl; + } + firstEntry=FALSE; + + ti << " ['" << id << "_" << cnt++ << "',['" << convertToXML(sname) << "',["; + childCount=0; + prevScope=0; } - firstEntry=FALSE; - ti << " ['" << dl->id() << "_" << cnt++ << "',['" << convertToXML(dl->name()) << "',["; + ++it; + const Definition *scope = d->getOuterScope(); + const Definition *next = it!=kv.second.end() ? *it : 0; + const Definition *nextScope = 0; + const MemberDef *md = toMemberDef(d); + if (next) nextScope = next->getOuterScope(); + QCString anchor = d->anchor(); - if (dl->count()==1) // item with a unique name + if (childCount>0) { - MemberDef *md = dynamic_cast<MemberDef*>(d); - QCString anchor = d->anchor(); - - ti << "'" << externalRef("../",d->getReference(),TRUE) - << d->getOutputFileBase() << Doxygen::htmlFileExtension; - if (!anchor.isEmpty()) - { - ti << "#" << anchor; - } - ti << "',"; + ti << "],["; + } + ti << "'" << externalRef("../",d->getReference(),TRUE) + << addHtmlExtensionIfMissing(d->getOutputFileBase()); + if (!anchor.isEmpty()) + { + ti << "#" << anchor; + } + ti << "',"; - static bool extLinksInWindow = Config_getBool(EXT_LINKS_IN_WINDOW); - if (!extLinksInWindow || d->getReference().isEmpty()) - { - ti << "1,"; - } - else - { - ti << "0,"; - } + static bool extLinksInWindow = Config_getBool(EXT_LINKS_IN_WINDOW); + if (!extLinksInWindow || d->getReference().isEmpty()) + { + ti << "1,"; + } + else + { + ti << "0,"; + } + if (lastName!=sname && (next==0 || searchName(next)!=sname)) // unique name + { if (d->getOuterScope()!=Doxygen::globalScope) { ti << "'" << convertToXML(d->getOuterScope()->name()) << "'"; @@ -1086,127 +1050,84 @@ void writeJavaScriptSearchIndex() { ti << "''"; } - ti << "]]"; } - else // multiple items with the same name + else // multiple entries with the same name { - QListIterator<Definition> di(*dl); - bool overloadedFunction = FALSE; - Definition *prevScope = 0; - int childCount=0; - for (di.toFirst();(d=di.current());) + bool found=FALSE; + bool overloadedFunction = ((prevScope!=0 && scope==prevScope) || + (scope && scope==nextScope)) && md && (md->isFunction() || md->isSlot()); + QCString prefix; + if (md) prefix=convertToXML(md->localName()); + if (overloadedFunction) // overloaded member function { - ++di; - Definition *scope = d->getOuterScope(); - Definition *next = di.current(); - Definition *nextScope = 0; - MemberDef *md = dynamic_cast<MemberDef*>(d); - if (next) nextScope = next->getOuterScope(); - QCString anchor = d->anchor(); - - if (childCount>0) - { - ti << "],["; - } - ti << "'" << externalRef("../",d->getReference(),TRUE) - << d->getOutputFileBase() << Doxygen::htmlFileExtension; - if (!anchor.isEmpty()) - { - ti << "#" << anchor; - } - ti << "',"; - - static bool extLinksInWindow = Config_getBool(EXT_LINKS_IN_WINDOW); - if (!extLinksInWindow || d->getReference().isEmpty()) - { - ti << "1,"; - } - else - { - ti << "0,"; - } - bool found=FALSE; - overloadedFunction = ((prevScope!=0 && scope==prevScope) || - (scope && scope==nextScope) - ) && md && - (md->isFunction() || md->isSlot()); - QCString prefix; - if (md) prefix=convertToXML(md->localName()); - if (overloadedFunction) // overloaded member function - { - prefix+=convertToXML(md->argsString()); - // show argument list to disambiguate overloaded functions - } - else if (md) // unique member function - { - prefix+="()"; // only to show it is a function - } - QCString name; - if (d->definitionType()==Definition::TypeClass) - { - name = convertToXML((dynamic_cast<ClassDef*>(d))->displayName()); - found = TRUE; - } - else if (d->definitionType()==Definition::TypeNamespace) - { - name = convertToXML((dynamic_cast<NamespaceDef*>(d))->displayName()); - found = TRUE; - } - else if (scope==0 || scope==Doxygen::globalScope) // in global scope + prefix+=convertToXML(md->argsString()); + // show argument list to disambiguate overloaded functions + } + else if (md) // unique member function + { + prefix+="()"; // only to show it is a function + } + QCString name; + if (d->definitionType()==Definition::TypeClass) + { + name = convertToXML((toClassDef(d))->displayName()); + found = TRUE; + } + else if (d->definitionType()==Definition::TypeNamespace) + { + name = convertToXML((toNamespaceDef(d))->displayName()); + found = TRUE; + } + else if (scope==0 || scope==Doxygen::globalScope) // in global scope + { + if (md) { - if (md) + const FileDef *fd = md->getBodyDef(); + if (fd==0) fd = md->resolveAlias()->getFileDef(); + if (fd) { - const FileDef *fd = md->getBodyDef(); - if (fd==0) fd = md->resolveAlias()->getFileDef(); - if (fd) - { - if (!prefix.isEmpty()) prefix+=": "; - name = prefix + convertToXML(fd->localName()); - found = TRUE; - } + if (!prefix.isEmpty()) prefix+=": "; + name = prefix + convertToXML(fd->localName()); + found = TRUE; } } - else if (md && (md->resolveAlias()->getClassDef() || md->resolveAlias()->getNamespaceDef())) - // member in class or namespace scope - { - SrcLangExt lang = md->getLanguage(); - name = convertToXML(d->getOuterScope()->qualifiedName()) - + getLanguageSpecificSeparator(lang) + prefix; - found = TRUE; - } - else if (scope) // some thing else? -> show scope - { - name = prefix + convertToXML(scope->name()); - found = TRUE; - } - if (!found) // fallback - { - name = prefix + "("+theTranslator->trGlobalNamespace()+")"; - } - - ti << "'" << name << "'"; - - prevScope = scope; - childCount++; } + else if (md && (md->resolveAlias()->getClassDef() || md->resolveAlias()->getNamespaceDef())) + // member in class or namespace scope + { + SrcLangExt lang = md->getLanguage(); + name = convertToXML(d->getOuterScope()->qualifiedName()) + + getLanguageSpecificSeparator(lang) + prefix; + found = TRUE; + } + else if (scope) // some thing else? -> show scope + { + name = prefix + convertToXML(scope->name()); + found = TRUE; + } + if (!found) // fallback + { + name = prefix + "("+theTranslator->trGlobalNamespace()+")"; + } + + ti << "'" << name << "'"; - ti << "]]"; + prevScope = scope; + childCount++; } - ti << "]"; - itemCount++; + lastName = sname; } if (!firstEntry) { - ti << endl; + ti << "]]]" << endl; } - ti << "];" << endl; - } else { err("Failed to open file '%s' for writing...\n",fileName.data()); } + p++; } } @@ -1217,72 +1138,66 @@ void writeJavaScriptSearchIndex() FTextStream t(&f); t << "var indexSectionsWithContent =" << endl; t << "{" << endl; - bool first=TRUE; int j=0; - for (i=0;i<NUM_SEARCH_INDICES;i++) + for (const auto &sii : g_searchIndexInfo) { - if (g_searchIndexInfo[i].symbolList.count()>0) + if (!sii.symbolMap.empty()) { - if (!first) t << "," << endl; + if (j>0) t << "," << endl; t << " " << j << ": \""; - SIntDict<SearchIndexList>::Iterator it(g_searchIndexInfo[i].symbolList); - SearchIndexList *sl; - for (it.toFirst();(sl=it.current());++it) // for each letter + for (const auto &kv : sii.symbolMap) { - if ( sl->letter() == '"' ) t << QString( QChar( '\\' ) ).utf8(); - t << QString( QChar( sl->letter() ) ).utf8(); + if ( kv.first == "\"" ) t << "\\"; + t << kv.first.c_str(); } t << "\""; - first=FALSE; j++; } } - if (!first) t << "\n"; + if (j>0) t << "\n"; t << "};" << endl << endl; t << "var indexSectionNames =" << endl; t << "{" << endl; - first=TRUE; j=0; - for (i=0;i<NUM_SEARCH_INDICES;i++) + for (const auto &sii : g_searchIndexInfo) { - if (g_searchIndexInfo[i].symbolList.count()>0) + if (!sii.symbolMap.empty()) { - if (!first) t << "," << endl; - t << " " << j << ": \"" << g_searchIndexInfo[i].name << "\""; - first=FALSE; + if (j>0) t << "," << endl; + t << " " << j << ": \"" << sii.name << "\""; j++; } } - if (!first) t << "\n"; + if (j>0) t << "\n"; t << "};" << endl << endl; t << "var indexSectionLabels =" << endl; t << "{" << endl; - first=TRUE; j=0; - for (i=0;i<NUM_SEARCH_INDICES;i++) + for (const auto &sii : g_searchIndexInfo) { - if (g_searchIndexInfo[i].symbolList.count()>0) + if (!sii.symbolMap.empty()) { - if (!first) t << "," << endl; - t << " " << j << ": \"" << convertToXML(g_searchIndexInfo[i].text) << "\""; - first=FALSE; + if (j>0) t << "," << endl; + t << " " << j << ": \"" << convertToXML(sii.getText()) << "\""; j++; } } - if (!first) t << "\n"; + if (j>0) t << "\n"; t << "};" << endl << endl; } ResourceMgr::instance().copyResource("search.js",searchDirName); } + { - QFile f(searchDirName+"/nomatches.html"); + QFile f(searchDirName+"/nomatches"+Doxygen::htmlFileExtension); if (f.open(IO_WriteOnly)) { FTextStream t(&f); t << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " "\"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl; - t << "<html><head><title></title>" << endl; + t << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl; + t << "<head><title></title>" << endl; t << "<meta http-equiv=\"Content-Type\" content=\"text/xhtml;charset=UTF-8\"/>" << endl; t << "<link rel=\"stylesheet\" type=\"text/css\" href=\"search.css\"/>" << endl; t << "<script type=\"text/javascript\" src=\"search.js\"></script>" << endl; @@ -1299,53 +1214,23 @@ void writeJavaScriptSearchIndex() Doxygen::indexList->addStyleSheetFile("search/search.js"); } -const SearchIndexInfo *getSearchIndices() +void SearchIndexInfo::add(const std::string &letter,const Definition *def) { - return g_searchIndexInfo; -} - -//--------------------------------------------------------------------------------------------- - -SearchIndexList::SearchIndexList(uint letter) - : SDict< SearchDefinitionList >(17,FALSE), m_letter(letter) -{ - setAutoDelete(TRUE); -} - -SearchIndexList::~SearchIndexList() -{ -} - -void SearchIndexList::append(const Definition *d) -{ - QCString dispName = d->localName(); - SearchDefinitionList *l = find(dispName); - if (l==0) + //printf("%p: %s->%s (full=%s)\n",this,letter.data(),searchName(def).data(),def->name().data()); + auto it = symbolMap.find(letter); + if (it!=symbolMap.end()) { - if (d->definitionType()==Definition::TypeGroup) - { - dispName = (dynamic_cast<const GroupDef*>(d))->groupTitle(); - } - else if (d->definitionType()==Definition::TypePage) - { - dispName = (dynamic_cast<const PageDef*>(d))->title(); - } - l=new SearchDefinitionList(searchId(dispName),dispName); - SDict< SearchDefinitionList >::append(dispName,l); + it->second.push_back(def); + } + else + { + symbolMap.insert(std::make_pair(letter,std::vector<const Definition*>({def}))); } - l->append(d); -} - -uint SearchIndexList::letter() const -{ - return m_letter; } -int SearchIndexList::compareValues(const SearchDefinitionList *md1, const SearchDefinitionList *md2) const +const std::array<SearchIndexInfo,NUM_SEARCH_INDICES> &getSearchIndices() { - QCString n1 = md1->getFirst()->localName(); - QCString n2 = md2->getFirst()->localName(); - return qstricmp(n1.data(),n2.data()); + return g_searchIndexInfo; } //--------------------------------------------------------------------------------------------- |