Commit 6538fdca authored by Dimitri van Heesch's avatar Dimitri van Heesch

Bug 705910 - Indexing and searching cannot treat non ASCII identifiers

parent e193c540
...@@ -138,31 +138,6 @@ class MemberIndexList : public QList<MemberDef> ...@@ -138,31 +138,6 @@ class MemberIndexList : public QList<MemberDef>
uint m_letter; uint m_letter;
}; };
/** @brief maps a unicode character code to a list of T::ElementType's
*/
template<class T>
class LetterToIndexMap : public SIntDict<T>
{
public:
LetterToIndexMap() { SIntDict<T>::setAutoDelete(TRUE); }
int compareItems(QCollection::Item item1, QCollection::Item item2)
{
T *l1=(T *)item1;
T *l2=(T *)item2;
return (int)l1->letter()-(int)l2->letter();
}
void append(uint letter,typename T::ElementType *elem)
{
T *l = SIntDict<T>::find((int)letter);
if (l==0)
{
l = new T(letter);
SIntDict<T>::inSort((int)letter,l);
}
l->append(elem);
}
};
static LetterToIndexMap<MemberIndexList> g_memberIndexLetterUsed[CMHL_Total]; static LetterToIndexMap<MemberIndexList> g_memberIndexLetterUsed[CMHL_Total];
static LetterToIndexMap<MemberIndexList> g_fileIndexLetterUsed[FMHL_Total]; static LetterToIndexMap<MemberIndexList> g_fileIndexLetterUsed[FMHL_Total];
static LetterToIndexMap<MemberIndexList> g_namespaceIndexLetterUsed[NMHL_Total]; static LetterToIndexMap<MemberIndexList> g_namespaceIndexLetterUsed[NMHL_Total];
...@@ -1783,7 +1758,7 @@ class PrefixIgnoreClassList : public ClassList ...@@ -1783,7 +1758,7 @@ class PrefixIgnoreClassList : public ClassList
class AlphaIndexTableCell class AlphaIndexTableCell
{ {
public: public:
AlphaIndexTableCell(int row,int col,uchar letter,ClassDef *cd) : AlphaIndexTableCell(int row,int col,uint letter,ClassDef *cd) :
m_letter(letter), m_class(cd), m_row(row), m_col(col) m_letter(letter), m_class(cd), m_row(row), m_col(col)
{ //printf("AlphaIndexTableCell(%d,%d,%c,%s)\n",row,col,letter!=0 ? letter: '-', { //printf("AlphaIndexTableCell(%d,%d,%c,%s)\n",row,col,letter!=0 ? letter: '-',
// cd!=(ClassDef*)0x8 ? cd->name().data() : "<null>"); // cd!=(ClassDef*)0x8 ? cd->name().data() : "<null>");
...@@ -1914,7 +1889,7 @@ static void writeAlphabeticalClassList(OutputList &ol) ...@@ -1914,7 +1889,7 @@ static void writeAlphabeticalClassList(OutputList &ol)
if (cd->isLinkableInProject() && cd->templateMaster()==0) if (cd->isLinkableInProject() && cd->templateMaster()==0)
{ {
int index = getPrefixIndex(cd->className()); int index = getPrefixIndex(cd->className());
startLetter=toupper(cd->className().at(index))&0xFF; startLetter=getUtf8Code(cd->className(),index);
// Do some sorting again, since the classes are sorted by name with // Do some sorting again, since the classes are sorted by name with
// prefix, which should be ignored really. // prefix, which should be ignored really.
if (cd->getLanguage()==SrcLangExt_VHDL) if (cd->getLanguage()==SrcLangExt_VHDL)
...@@ -1954,7 +1929,7 @@ static void writeAlphabeticalClassList(OutputList &ol) ...@@ -1954,7 +1929,7 @@ static void writeAlphabeticalClassList(OutputList &ol)
{ {
uint l = cl->letter(); uint l = cl->letter();
// add special header cell // add special header cell
tableRows->append(new AlphaIndexTableCell(row,col,(uchar)l,(ClassDef*)0x8)); tableRows->append(new AlphaIndexTableCell(row,col,l,(ClassDef*)0x8));
row++; row++;
tableRows->append(new AlphaIndexTableCell(row,col,0,(ClassDef*)0x8)); tableRows->append(new AlphaIndexTableCell(row,col,0,(ClassDef*)0x8));
row++; row++;
...@@ -2017,7 +1992,7 @@ static void writeAlphabeticalClassList(OutputList &ol) ...@@ -2017,7 +1992,7 @@ static void writeAlphabeticalClassList(OutputList &ol)
ol.writeString("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">" ol.writeString("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">"
"<tr>" "<tr>"
"<td><div class=\"ah\">&#160;&#160;"); "<td><div class=\"ah\">&#160;&#160;");
ol.writeString(s); ol.writeString(QString(QChar(cell->letter())).utf8());
ol.writeString( "&#160;&#160;</div>" ol.writeString( "&#160;&#160;</div>"
"</td>" "</td>"
"</tr>" "</tr>"
......
...@@ -5,7 +5,7 @@ function convertToId(search) ...@@ -5,7 +5,7 @@ function convertToId(search)
{ {
var c = search.charAt(i); var c = search.charAt(i);
var cn = c.charCodeAt(0); var cn = c.charCodeAt(0);
if (c.match(/[a-z0-9]/)) if (c.match(/[a-z0-9\u0080-\uFFFF]/))
{ {
result+=c; result+=c;
} }
...@@ -310,22 +310,20 @@ function SearchBox(name, resultsPath, inFrame, label) ...@@ -310,22 +310,20 @@ function SearchBox(name, resultsPath, inFrame, label)
var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
var code = searchValue.toLowerCase().charCodeAt(0); var code = searchValue.toLowerCase().charCodeAt(0);
var hexCode; var idxChar = searchValue.substr(0, 1).toLowerCase();
if (code<16) if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair
{ {
hexCode="0"+code.toString(16); idxChar = searchValue.substr(0, 2);
}
else
{
hexCode=code.toString(16);
} }
var resultsPage; var resultsPage;
var resultsPageWithSearch; var resultsPageWithSearch;
var hasResultsPage; var hasResultsPage;
if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1') var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar);
if (idx!=-1)
{ {
var hexCode=idx.toString(16);
resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
resultsPageWithSearch = resultsPage+'?'+escape(searchValue); resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
hasResultsPage = true; hasResultsPage = true;
......
...@@ -358,7 +358,7 @@ function main() ...@@ -358,7 +358,7 @@ function main()
$sorted = run_query($query); $sorted = run_query($query);
// Now output the HTML stuff... // Now output the HTML stuff...
// End the HTML form // End the HTML form
end_form(preg_replace("/[^a-zA-Z0-9\-\_\.]/i", " ", $query )); end_form(preg_replace("/[^a-zA-Z0-9\-\_\.\x80-\xFF]/i", " ", $query ));
// report results to the user // report results to the user
report_results($sorted); report_results($sorted);
end_page(); end_page();
......
...@@ -358,7 +358,7 @@ ...@@ -358,7 +358,7 @@
" $sorted = run_query($query);\n" " $sorted = run_query($query);\n"
" // Now output the HTML stuff...\n" " // Now output the HTML stuff...\n"
" // End the HTML form\n" " // End the HTML form\n"
" end_form(preg_replace(\"/[^a-zA-Z0-9\\-\\_\\.]/i\", \" \", $query ));\n" " end_form(preg_replace(\"/[^a-zA-Z0-9\\-\\_\\.\\x80-\\xFF]/i\", \" \", $query ));\n"
" // report results to the user\n" " // report results to the user\n"
" report_results($sorted);\n" " report_results($sorted);\n"
" end_page();\n" " end_page();\n"
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
" {\n" " {\n"
" var c = search.charAt(i);\n" " var c = search.charAt(i);\n"
" var cn = c.charCodeAt(0);\n" " var cn = c.charCodeAt(0);\n"
" if (c.match(/[a-z0-9]/))\n" " if (c.match(/[a-z0-9\\u0080-\\uFFFF]/))\n"
" {\n" " {\n"
" result+=c;\n" " result+=c;\n"
" }\n" " }\n"
...@@ -310,22 +310,20 @@ ...@@ -310,22 +310,20 @@
" var searchValue = this.DOMSearchField().value.replace(/^ +/, \"\");\n" " var searchValue = this.DOMSearchField().value.replace(/^ +/, \"\");\n"
"\n" "\n"
" var code = searchValue.toLowerCase().charCodeAt(0);\n" " var code = searchValue.toLowerCase().charCodeAt(0);\n"
" var hexCode;\n" " var idxChar = searchValue.substr(0, 1).toLowerCase();\n"
" if (code<16) \n" " if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair\n"
" {\n" " {\n"
" hexCode=\"0\"+code.toString(16);\n" " idxChar = searchValue.substr(0, 2);\n"
" }\n"
" else \n"
" {\n"
" hexCode=code.toString(16);\n"
" }\n" " }\n"
"\n" "\n"
" var resultsPage;\n" " var resultsPage;\n"
" var resultsPageWithSearch;\n" " var resultsPageWithSearch;\n"
" var hasResultsPage;\n" " var hasResultsPage;\n"
"\n" "\n"
" if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1')\n" " var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar);\n"
" if (idx!=-1)\n"
" {\n" " {\n"
" var hexCode=idx.toString(16);\n"
" resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';\n" " resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';\n"
" resultsPageWithSearch = resultsPage+'?'+escape(searchValue);\n" " resultsPageWithSearch = resultsPage+'?'+escape(searchValue);\n"
" hasResultsPage = true;\n" " hasResultsPage = true;\n"
......
...@@ -587,8 +587,6 @@ static const char search_script[]= ...@@ -587,8 +587,6 @@ static const char search_script[]=
#include "search_js.h" #include "search_js.h"
; ;
#define MEMBER_INDEX_ENTRIES 256
#define SEARCH_INDEX_ALL 0 #define SEARCH_INDEX_ALL 0
#define SEARCH_INDEX_CLASSES 1 #define SEARCH_INDEX_CLASSES 1
#define SEARCH_INDEX_NAMESPACES 2 #define SEARCH_INDEX_NAMESPACES 2
...@@ -606,21 +604,31 @@ static const char search_script[]= ...@@ -606,21 +604,31 @@ static const char search_script[]=
#define SEARCH_INDEX_PAGES 14 #define SEARCH_INDEX_PAGES 14
#define NUM_SEARCH_INDICES 15 #define NUM_SEARCH_INDICES 15
class SearchIndexList : public SDict< QList<Definition> > class SearchDefinitionList : public QList<Definition>
{
public:
SearchDefinitionList(uint letter) : m_letter(letter) {}
uint letter() const { return m_letter; }
private:
uint m_letter;
};
class SearchIndexList : public SDict< SearchDefinitionList >
{ {
public: public:
SearchIndexList(int size=17) : SDict< QList<Definition> >(size,FALSE) typedef Definition ElementType;
SearchIndexList(uint letter) : SDict<SearchDefinitionList>(17,FALSE), m_letter(letter)
{ {
setAutoDelete(TRUE); setAutoDelete(TRUE);
} }
~SearchIndexList() {} ~SearchIndexList() {}
void append(Definition *d) void append(Definition *d)
{ {
QList<Definition> *l = find(d->name()); SearchDefinitionList *l = find(d->name());
if (l==0) if (l==0)
{ {
l=new QList<Definition>; l=new SearchDefinitionList(m_letter);
SDict< QList<Definition> >::append(d->name(),l); SDict<SearchDefinitionList>::append(d->name(),l);
} }
l->append(d); l->append(d);
} }
...@@ -632,10 +640,13 @@ class SearchIndexList : public SDict< QList<Definition> > ...@@ -632,10 +640,13 @@ class SearchIndexList : public SDict< QList<Definition> >
QCString n2 = md2->first()->localName(); QCString n2 = md2->first()->localName();
return qstricmp(n1.data(),n2.data()); return qstricmp(n1.data(),n2.data());
} }
uint letter() const { return m_letter; }
private:
uint m_letter;
}; };
static void addMemberToSearchIndex( static void addMemberToSearchIndex(
SearchIndexList symbols[NUM_SEARCH_INDICES][MEMBER_INDEX_ENTRIES], LetterToIndexMap<SearchIndexList> symbols[NUM_SEARCH_INDICES],
int symbolCount[NUM_SEARCH_INDICES], int symbolCount[NUM_SEARCH_INDICES],
MemberDef *md) MemberDef *md)
{ {
...@@ -653,58 +664,57 @@ static void addMemberToSearchIndex( ...@@ -653,58 +664,57 @@ static void addMemberToSearchIndex(
) )
{ {
QCString n = md->name(); QCString n = md->name();
uchar charCode = (uchar)n.at(0);
uint letter = charCode<128 ? tolower(charCode) : charCode;
if (!n.isEmpty()) if (!n.isEmpty())
{ {
uint letter = getUtf8CodeToLower(n,0);
bool isFriendToHide = hideFriendCompounds && bool isFriendToHide = hideFriendCompounds &&
(QCString(md->typeString())=="friend class" || (QCString(md->typeString())=="friend class" ||
QCString(md->typeString())=="friend struct" || QCString(md->typeString())=="friend struct" ||
QCString(md->typeString())=="friend union"); QCString(md->typeString())=="friend union");
if (!(md->isFriend() && isFriendToHide)) if (!(md->isFriend() && isFriendToHide))
{ {
symbols[SEARCH_INDEX_ALL][letter].append(md); symbols[SEARCH_INDEX_ALL].append(letter,md);
symbolCount[SEARCH_INDEX_ALL]++; symbolCount[SEARCH_INDEX_ALL]++;
} }
if (md->isFunction() || md->isSlot() || md->isSignal()) if (md->isFunction() || md->isSlot() || md->isSignal())
{ {
symbols[SEARCH_INDEX_FUNCTIONS][letter].append(md); symbols[SEARCH_INDEX_FUNCTIONS].append(letter,md);
symbolCount[SEARCH_INDEX_FUNCTIONS]++; symbolCount[SEARCH_INDEX_FUNCTIONS]++;
} }
else if (md->isVariable()) else if (md->isVariable())
{ {
symbols[SEARCH_INDEX_VARIABLES][letter].append(md); symbols[SEARCH_INDEX_VARIABLES].append(letter,md);
symbolCount[SEARCH_INDEX_VARIABLES]++; symbolCount[SEARCH_INDEX_VARIABLES]++;
} }
else if (md->isTypedef()) else if (md->isTypedef())
{ {
symbols[SEARCH_INDEX_TYPEDEFS][letter].append(md); symbols[SEARCH_INDEX_TYPEDEFS].append(letter,md);
symbolCount[SEARCH_INDEX_TYPEDEFS]++; symbolCount[SEARCH_INDEX_TYPEDEFS]++;
} }
else if (md->isEnumerate()) else if (md->isEnumerate())
{ {
symbols[SEARCH_INDEX_ENUMS][letter].append(md); symbols[SEARCH_INDEX_ENUMS].append(letter,md);
symbolCount[SEARCH_INDEX_ENUMS]++; symbolCount[SEARCH_INDEX_ENUMS]++;
} }
else if (md->isEnumValue()) else if (md->isEnumValue())
{ {
symbols[SEARCH_INDEX_ENUMVALUES][letter].append(md); symbols[SEARCH_INDEX_ENUMVALUES].append(letter,md);
symbolCount[SEARCH_INDEX_ENUMVALUES]++; symbolCount[SEARCH_INDEX_ENUMVALUES]++;
} }
else if (md->isProperty()) else if (md->isProperty())
{ {
symbols[SEARCH_INDEX_PROPERTIES][letter].append(md); symbols[SEARCH_INDEX_PROPERTIES].append(letter,md);
symbolCount[SEARCH_INDEX_PROPERTIES]++; symbolCount[SEARCH_INDEX_PROPERTIES]++;
} }
else if (md->isEvent()) else if (md->isEvent())
{ {
symbols[SEARCH_INDEX_EVENTS][letter].append(md); symbols[SEARCH_INDEX_EVENTS].append(letter,md);
symbolCount[SEARCH_INDEX_EVENTS]++; symbolCount[SEARCH_INDEX_EVENTS]++;
} }
else if (md->isRelated() || md->isForeign() || else if (md->isRelated() || md->isForeign() ||
(md->isFriend() && !isFriendToHide)) (md->isFriend() && !isFriendToHide))
{ {
symbols[SEARCH_INDEX_RELATED][letter].append(md); symbols[SEARCH_INDEX_RELATED].append(letter,md);
symbolCount[SEARCH_INDEX_RELATED]++; symbolCount[SEARCH_INDEX_RELATED]++;
} }
} }
...@@ -716,47 +726,48 @@ static void addMemberToSearchIndex( ...@@ -716,47 +726,48 @@ static void addMemberToSearchIndex(
) )
{ {
QCString n = md->name(); QCString n = md->name();
uchar charCode = (uchar)n.at(0);
uint letter = charCode<128 ? tolower(charCode) : charCode;
if (!n.isEmpty()) if (!n.isEmpty())
{ {
symbols[SEARCH_INDEX_ALL][letter].append(md); uint letter = getUtf8CodeToLower(n,0);
symbols[SEARCH_INDEX_ALL].append(letter,md);
symbolCount[SEARCH_INDEX_ALL]++; symbolCount[SEARCH_INDEX_ALL]++;
if (md->isFunction()) if (md->isFunction())
{ {
symbols[SEARCH_INDEX_FUNCTIONS][letter].append(md); symbols[SEARCH_INDEX_FUNCTIONS].append(letter,md);
symbolCount[SEARCH_INDEX_FUNCTIONS]++; symbolCount[SEARCH_INDEX_FUNCTIONS]++;
} }
else if (md->isVariable()) else if (md->isVariable())
{ {
symbols[SEARCH_INDEX_VARIABLES][letter].append(md); symbols[SEARCH_INDEX_VARIABLES].append(letter,md);
symbolCount[SEARCH_INDEX_VARIABLES]++; symbolCount[SEARCH_INDEX_VARIABLES]++;
} }
else if (md->isTypedef()) else if (md->isTypedef())
{ {
symbols[SEARCH_INDEX_TYPEDEFS][letter].append(md); symbols[SEARCH_INDEX_TYPEDEFS].append(letter,md);
symbolCount[SEARCH_INDEX_TYPEDEFS]++; symbolCount[SEARCH_INDEX_TYPEDEFS]++;
} }
else if (md->isEnumerate()) else if (md->isEnumerate())
{ {
symbols[SEARCH_INDEX_ENUMS][letter].append(md); symbols[SEARCH_INDEX_ENUMS].append(letter,md);
symbolCount[SEARCH_INDEX_ENUMS]++; symbolCount[SEARCH_INDEX_ENUMS]++;
} }
else if (md->isEnumValue()) else if (md->isEnumValue())
{ {
symbols[SEARCH_INDEX_ENUMVALUES][letter].append(md); symbols[SEARCH_INDEX_ENUMVALUES].append(letter,md);
symbolCount[SEARCH_INDEX_ENUMVALUES]++; symbolCount[SEARCH_INDEX_ENUMVALUES]++;
} }
else if (md->isDefine()) else if (md->isDefine())
{ {
symbols[SEARCH_INDEX_DEFINES][letter].append(md); symbols[SEARCH_INDEX_DEFINES].append(letter,md);
symbolCount[SEARCH_INDEX_DEFINES]++; symbolCount[SEARCH_INDEX_DEFINES]++;
} }
} }
} }
} }
// see also function convertToId() in search.js, which should match in
// behaviour
static QCString searchId(const QCString &s) static QCString searchId(const QCString &s)
{ {
int c; int c;
...@@ -765,11 +776,15 @@ static QCString searchId(const QCString &s) ...@@ -765,11 +776,15 @@ static QCString searchId(const QCString &s)
for (i=0;i<s.length();i++) for (i=0;i<s.length();i++)
{ {
c=s.at(i); c=s.at(i);
if ((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z')) if (c>0x7f || c<0) // part of multibyte character
{
result+=(char)c;
}
else if (isalnum(c)) // simply alpha numerical character
{ {
result+=(char)tolower(c); result+=(char)tolower(c);
} }
else else // other 'unprintable' characters
{ {
char val[4]; char val[4];
sprintf(val,"_%02x",(uchar)c); sprintf(val,"_%02x",(uchar)c);
...@@ -780,7 +795,7 @@ static QCString searchId(const QCString &s) ...@@ -780,7 +795,7 @@ static QCString searchId(const QCString &s)
} }
static int g_searchIndexCount[NUM_SEARCH_INDICES]; static int g_searchIndexCount[NUM_SEARCH_INDICES];
static SearchIndexList g_searchIndexSymbols[NUM_SEARCH_INDICES][MEMBER_INDEX_ENTRIES]; static LetterToIndexMap<SearchIndexList> g_searchIndexSymbols[NUM_SEARCH_INDICES];
static const char *g_searchIndexName[NUM_SEARCH_INDICES] = static const char *g_searchIndexName[NUM_SEARCH_INDICES] =
{ {
"all", "all",
...@@ -834,12 +849,11 @@ void writeJavascriptSearchIndex() ...@@ -834,12 +849,11 @@ void writeJavascriptSearchIndex()
ClassDef *cd; ClassDef *cd;
for (;(cd=cli.current());++cli) for (;(cd=cli.current());++cli)
{ {
uchar charCode = (uchar)cd->localName().at(0); uint letter = getUtf8CodeToLower(cd->localName(),0);
uint letter = charCode<128 ? tolower(charCode) : charCode;
if (cd->isLinkable() && isId(letter)) if (cd->isLinkable() && isId(letter))
{ {
g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(cd); g_searchIndexSymbols[SEARCH_INDEX_ALL].append(letter,cd);
g_searchIndexSymbols[SEARCH_INDEX_CLASSES][letter].append(cd); g_searchIndexSymbols[SEARCH_INDEX_CLASSES].append(letter,cd);
g_searchIndexCount[SEARCH_INDEX_ALL]++; g_searchIndexCount[SEARCH_INDEX_ALL]++;
g_searchIndexCount[SEARCH_INDEX_CLASSES]++; g_searchIndexCount[SEARCH_INDEX_CLASSES]++;
} }
...@@ -850,12 +864,11 @@ void writeJavascriptSearchIndex() ...@@ -850,12 +864,11 @@ void writeJavascriptSearchIndex()
NamespaceDef *nd; NamespaceDef *nd;
for (;(nd=nli.current());++nli) for (;(nd=nli.current());++nli)
{ {
uchar charCode = (uchar)nd->name().at(0); uint letter = getUtf8CodeToLower(nd->name(),0);
uint letter = charCode<128 ? tolower(charCode) : charCode;
if (nd->isLinkable() && isId(letter)) if (nd->isLinkable() && isId(letter))
{ {
g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(nd); g_searchIndexSymbols[SEARCH_INDEX_ALL].append(letter,nd);
g_searchIndexSymbols[SEARCH_INDEX_NAMESPACES][letter].append(nd); g_searchIndexSymbols[SEARCH_INDEX_NAMESPACES].append(letter,nd);
g_searchIndexCount[SEARCH_INDEX_ALL]++; g_searchIndexCount[SEARCH_INDEX_ALL]++;
g_searchIndexCount[SEARCH_INDEX_NAMESPACES]++; g_searchIndexCount[SEARCH_INDEX_NAMESPACES]++;
} }
...@@ -870,12 +883,11 @@ void writeJavascriptSearchIndex() ...@@ -870,12 +883,11 @@ void writeJavascriptSearchIndex()
FileDef *fd; FileDef *fd;
for (;(fd=fni.current());++fni) for (;(fd=fni.current());++fni)
{ {
uchar charCode = (uchar)fd->name().at(0); uint letter = getUtf8CodeToLower(fd->name(),0);
uint letter = charCode<128 ? tolower(charCode) : charCode;
if (fd->isLinkable() && isId(letter)) if (fd->isLinkable() && isId(letter))
{ {
g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(fd); g_searchIndexSymbols[SEARCH_INDEX_ALL].append(letter,fd);
g_searchIndexSymbols[SEARCH_INDEX_FILES][letter].append(fd); g_searchIndexSymbols[SEARCH_INDEX_FILES].append(letter,fd);
g_searchIndexCount[SEARCH_INDEX_ALL]++; g_searchIndexCount[SEARCH_INDEX_ALL]++;
g_searchIndexCount[SEARCH_INDEX_FILES]++; g_searchIndexCount[SEARCH_INDEX_FILES]++;
} }
...@@ -930,8 +942,8 @@ void writeJavascriptSearchIndex() ...@@ -930,8 +942,8 @@ void writeJavascriptSearchIndex()
uint letter = charCode<128 ? tolower(charCode) : charCode; uint letter = charCode<128 ? tolower(charCode) : charCode;
if (isId(letter)) if (isId(letter))
{ {
g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(gd); g_searchIndexSymbols[SEARCH_INDEX_ALL].append(letter,gd);
g_searchIndexSymbols[SEARCH_INDEX_GROUPS][letter].append(gd); g_searchIndexSymbols[SEARCH_INDEX_GROUPS].append(letter,gd);
g_searchIndexCount[SEARCH_INDEX_ALL]++; g_searchIndexCount[SEARCH_INDEX_ALL]++;
g_searchIndexCount[SEARCH_INDEX_GROUPS]++; g_searchIndexCount[SEARCH_INDEX_GROUPS]++;
} }
...@@ -953,8 +965,8 @@ void writeJavascriptSearchIndex() ...@@ -953,8 +965,8 @@ void writeJavascriptSearchIndex()
uint letter = charCode<128 ? tolower(charCode) : charCode; uint letter = charCode<128 ? tolower(charCode) : charCode;
if (isId(letter)) if (isId(letter))
{ {
g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(pd); g_searchIndexSymbols[SEARCH_INDEX_ALL].append(letter,pd);
g_searchIndexSymbols[SEARCH_INDEX_PAGES][letter].append(pd); g_searchIndexSymbols[SEARCH_INDEX_PAGES].append(letter,pd);
g_searchIndexCount[SEARCH_INDEX_ALL]++; g_searchIndexCount[SEARCH_INDEX_ALL]++;
g_searchIndexCount[SEARCH_INDEX_PAGES]++; g_searchIndexCount[SEARCH_INDEX_PAGES]++;
} }
...@@ -970,8 +982,8 @@ void writeJavascriptSearchIndex() ...@@ -970,8 +982,8 @@ void writeJavascriptSearchIndex()
uint letter = charCode<128 ? tolower(charCode) : charCode; uint letter = charCode<128 ? tolower(charCode) : charCode;
if (isId(letter)) if (isId(letter))
{ {
g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(Doxygen::mainPage); g_searchIndexSymbols[SEARCH_INDEX_ALL].append(letter,Doxygen::mainPage);
g_searchIndexSymbols[SEARCH_INDEX_PAGES][letter].append(Doxygen::mainPage); g_searchIndexSymbols[SEARCH_INDEX_PAGES].append(letter,Doxygen::mainPage);
g_searchIndexCount[SEARCH_INDEX_ALL]++; g_searchIndexCount[SEARCH_INDEX_ALL]++;
g_searchIndexCount[SEARCH_INDEX_PAGES]++; g_searchIndexCount[SEARCH_INDEX_PAGES]++;
} }
...@@ -979,122 +991,181 @@ void writeJavascriptSearchIndex() ...@@ -979,122 +991,181 @@ void writeJavascriptSearchIndex()
} }
// sort all lists // sort all lists
int i,p; int i;
for (i=0;i<NUM_SEARCH_INDICES;i++) for (i=0;i<NUM_SEARCH_INDICES;i++)
{ {
for (p=0;p<MEMBER_INDEX_ENTRIES;p++) SIntDict<SearchIndexList>::Iterator it(g_searchIndexSymbols[i]);
SearchIndexList *sl;
for (it.toFirst();(sl=it.current());++it)
{ {
if (g_searchIndexSymbols[i][p].count()>0) sl->sort();
{
g_searchIndexSymbols[i][p].sort();
}
} }
} }
// write index files // write index files
QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search"; QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
for (i=0;i<NUM_SEARCH_INDICES;i++) for (i=0;i<NUM_SEARCH_INDICES;i++) // for each index
{ {
for (p=0;p<MEMBER_INDEX_ENTRIES;p++) SIntDict<SearchIndexList>::Iterator it(g_searchIndexSymbols[i]);
SearchIndexList *sl;
int p=0;
for (it.toFirst();(sl=it.current());++it,++p) // for each letter
{ {
if (g_searchIndexSymbols[i][p].count()>0) QCString baseName;
{ baseName.sprintf("%s_%x",g_searchIndexName[i],p);
QCString baseName;
baseName.sprintf("%s_%02x",g_searchIndexName[i],p);
QCString fileName = searchDirName + "/"+baseName+".html"; QCString fileName = searchDirName + "/"+baseName+".html";
QCString dataFileName = searchDirName + "/"+baseName+".js"; QCString dataFileName = searchDirName + "/"+baseName+".js";
QFile outFile(fileName); QFile outFile(fileName);
QFile dataOutFile(dataFileName); QFile dataOutFile(dataFileName);
if (outFile.open(IO_WriteOnly) && dataOutFile.open(IO_WriteOnly)) if (outFile.open(IO_WriteOnly) && dataOutFile.open(IO_WriteOnly))
{
{
FTextStream t(&outFile);
t << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl;
t << "<html><head><title></title>" << endl;
t << "<meta http-equiv=\"Content-Type\" content=\"text/xhtml;charset=UTF-8\"/>" << endl;
t << "<meta name=\"generator\" content=\"Doxygen " << versionString << "\">" << 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;
t << "</head>" << endl;
t << "<body class=\"SRPage\">" << endl;
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 << "createResults();" << endl; // this function will insert the results
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 << "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 << "--></script>" << endl;
t << "</div>" << endl; // SRIndex
t << "</body>" << endl;
t << "</html>" << endl;
}
FTextStream ti(&dataOutFile);
ti << "var searchData=" << endl;
// format
// searchData[] = array of items
// searchData[x][0] = id
// searchData[x][1] = [ name + child1 + child2 + .. ]
// searchData[x][1][0] = name as shown
// searchData[x][1][y+1] = info for child y
// searchData[x][1][y+1][0] = url
// searchData[x][1][y+1][1] = 1 => target="_parent"
// searchData[x][1][y+1][2] = scope
ti << "[" << endl;
bool firstEntry=TRUE;
SDict<SearchDefinitionList>::Iterator li(*sl);
SearchDefinitionList *dl;
int itemCount=0;
for (li.toFirst();(dl=li.current());++li)
{ {
Definition *d = dl->first();
QCString id = d->localName();
if (!firstEntry)
{
ti << "," << endl;
}
firstEntry=FALSE;
QCString dispName = d->localName();
if (d->definitionType()==Definition::TypeGroup)
{ {
FTextStream t(&outFile); dispName = ((GroupDef*)d)->groupTitle();
t << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" << endl;
t << "<html><head><title></title>" << endl;
t << "<meta http-equiv=\"Content-Type\" content=\"text/xhtml;charset=UTF-8\"/>" << endl;
t << "<meta name=\"generator\" content=\"Doxygen " << versionString << "\">" << 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;
t << "</head>" << endl;
t << "<body class=\"SRPage\">" << endl;
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 << "createResults();" << endl; // this function will insert the results
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 << "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 << "--></script>" << endl;
t << "</div>" << endl; // SRIndex
t << "</body>" << endl;
t << "</html>" << endl;
} }
FTextStream ti(&dataOutFile); else if (d->definitionType()==Definition::TypePage)
ti << "var searchData=" << endl;
// format
// searchData[] = array of items
// searchData[x][0] = id
// searchData[x][1] = [ name + child1 + child2 + .. ]
// searchData[x][1][0] = name as shown
// searchData[x][1][y+1] = info for child y
// searchData[x][1][y+1][0] = url
// searchData[x][1][y+1][1] = 1 => target="_parent"
// searchData[x][1][y+1][2] = scope
ti << "[" << endl;
bool firstEntry=TRUE;
SDict<QList<Definition> >::Iterator li(g_searchIndexSymbols[i][p]);
QList<Definition> *dl;
int itemCount=0;
for (li.toFirst();(dl=li.current());++li)
{ {
Definition *d = dl->first(); dispName = ((PageDef*)d)->title();
QCString id = d->localName(); }
ti << " ['" << searchId(dispName) << "',['"
<< convertToXML(dispName) << "',[";
if (!firstEntry) if (dl->count()==1) // item with a unique name
{
MemberDef *md = 0;
bool isMemberDef = d->definitionType()==Definition::TypeMember;
if (isMemberDef) md = (MemberDef*)d;
QCString anchor = d->anchor();
ti << "'" << externalRef("../",d->getReference(),TRUE)
<< d->getOutputFileBase() << Doxygen::htmlFileExtension;
if (!anchor.isEmpty())
{ {
ti << "," << endl; ti << "#" << anchor;
} }
firstEntry=FALSE; ti << "',";
QCString dispName = d->localName(); static bool extLinksInWindow = Config_getBool("EXT_LINKS_IN_WINDOW");
if (d->definitionType()==Definition::TypeGroup) if (!extLinksInWindow || d->getReference().isEmpty())
{ {
dispName = ((GroupDef*)d)->groupTitle(); ti << "1,";
} }
else if (d->definitionType()==Definition::TypePage) else
{ {
dispName = ((PageDef*)d)->title(); ti << "0,";
} }
ti << " ['" << searchId(dispName) << "',['"
<< convertToXML(dispName) << "',[";
if (dl->count()==1) // item with a unique name if (d->getOuterScope()!=Doxygen::globalScope)
{
ti << "'" << convertToXML(d->getOuterScope()->name()) << "'";
}
else if (md)
{
FileDef *fd = md->getBodyDef();
if (fd==0) fd = md->getFileDef();
if (fd)
{
ti << "'" << convertToXML(fd->localName()) << "'";
}
}
else
{
ti << "''";
}
ti << "]]";
}
else // multiple items with the same name
{
QListIterator<Definition> di(*dl);
bool overloadedFunction = FALSE;
Definition *prevScope = 0;
int childCount=0;
for (di.toFirst();(d=di.current());)
{ {
MemberDef *md = 0; ++di;
Definition *scope = d->getOuterScope();
Definition *next = di.current();
Definition *nextScope = 0;
MemberDef *md = 0;
bool isMemberDef = d->definitionType()==Definition::TypeMember; bool isMemberDef = d->definitionType()==Definition::TypeMember;
if (isMemberDef) md = (MemberDef*)d; if (isMemberDef) md = (MemberDef*)d;
if (next) nextScope = next->getOuterScope();
QCString anchor = d->anchor(); QCString anchor = d->anchor();
if (childCount>0)
{
ti << "],[";
}
ti << "'" << externalRef("../",d->getReference(),TRUE) ti << "'" << externalRef("../",d->getReference(),TRUE)
<< d->getOutputFileBase() << Doxygen::htmlFileExtension; << d->getOutputFileBase() << Doxygen::htmlFileExtension;
if (!anchor.isEmpty()) if (!anchor.isEmpty())
{ {
ti << "#" << anchor; ti << "#" << anchor;
...@@ -1110,147 +1181,87 @@ void writeJavascriptSearchIndex() ...@@ -1110,147 +1181,87 @@ void writeJavascriptSearchIndex()
{ {
ti << "0,"; ti << "0,";
} }
bool found=FALSE;
if (d->getOuterScope()!=Doxygen::globalScope) 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
{ {
ti << "'" << convertToXML(d->getOuterScope()->name()) << "'"; prefix+=convertToXML(md->argsString());
// show argument list to disambiguate overloaded functions
} }
else if (md) else if (md) // unique member function
{ {
FileDef *fd = md->getBodyDef(); prefix+="()"; // only to show it is a function
if (fd==0) fd = md->getFileDef();
if (fd)
{
ti << "'" << convertToXML(fd->localName()) << "'";
}
} }
else QCString name;
if (d->definitionType()==Definition::TypeClass)
{ {
ti << "''"; name = convertToXML(((ClassDef*)d)->displayName());
found = TRUE;
} }
ti << "]]"; else if (d->definitionType()==Definition::TypeNamespace)
}
else // multiple items with the same name
{
QListIterator<Definition> di(*dl);
bool overloadedFunction = FALSE;
Definition *prevScope = 0;
int childCount=0;
for (di.toFirst();(d=di.current());)
{ {
++di; name = convertToXML(((NamespaceDef*)d)->displayName());
Definition *scope = d->getOuterScope(); found = TRUE;
Definition *next = di.current(); }
Definition *nextScope = 0; else if (scope==0 || scope==Doxygen::globalScope) // in global scope
MemberDef *md = 0; {
bool isMemberDef = d->definitionType()==Definition::TypeMember; if (md)
if (isMemberDef) md = (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(((ClassDef*)d)->displayName());
found = TRUE;
}
else if (d->definitionType()==Definition::TypeNamespace)
{
name = convertToXML(((NamespaceDef*)d)->displayName());
found = TRUE;
}
else if (scope==0 || scope==Doxygen::globalScope) // in global scope
{ {
if (md) FileDef *fd = md->getBodyDef();
if (fd==0) fd = md->getFileDef();
if (fd)
{ {
FileDef *fd = md->getBodyDef(); if (!prefix.isEmpty()) prefix+=":&#160;";
if (fd==0) fd = md->getFileDef(); name = prefix + convertToXML(fd->localName());
if (fd) found = TRUE;
{
if (!prefix.isEmpty()) prefix+=":&#160;";
name = prefix + convertToXML(fd->localName());
found = TRUE;
}
} }
} }
else if (md && (md->getClassDef() || md->getNamespaceDef())) }
// member in class or namespace scope else if (md && (md->getClassDef() || md->getNamespaceDef()))
{ // member in class or namespace scope
SrcLangExt lang = md->getLanguage(); {
name = convertToXML(d->getOuterScope()->qualifiedName()) SrcLangExt lang = md->getLanguage();
+ getLanguageSpecificSeparator(lang) + prefix; name = convertToXML(d->getOuterScope()->qualifiedName())
found = TRUE; + getLanguageSpecificSeparator(lang) + prefix;
} found = TRUE;
else if (scope) // some thing else? -> show scope }
{ else if (scope) // some thing else? -> show scope
name = prefix + convertToXML(scope->name()); {
found = TRUE; name = prefix + convertToXML(scope->name());
} found = TRUE;
if (!found) // fallback }
{ if (!found) // fallback
name = prefix + "("+theTranslator->trGlobalNamespace()+")"; {
} name = prefix + "("+theTranslator->trGlobalNamespace()+")";
ti << "'" << name << "'";
prevScope = scope;
childCount++;
} }
ti << "]]"; ti << "'" << name << "'";
}
ti << "]";
itemCount++;
}
if (!firstEntry)
{
ti << endl;
}
ti << "];" << endl; prevScope = scope;
childCount++;
}
ti << "]]";
}
ti << "]";
itemCount++;
} }
else if (!firstEntry)
{ {
err("Failed to open file '%s' for writing...\n",fileName.data()); ti << endl;
} }
ti << "];" << endl;
}
else
{
err("Failed to open file '%s' for writing...\n",fileName.data());
} }
} }
} }
...@@ -1275,9 +1286,12 @@ void writeJavascriptSearchIndex() ...@@ -1275,9 +1286,12 @@ void writeJavascriptSearchIndex()
{ {
if (!first) t << "," << endl; if (!first) t << "," << endl;
t << " " << j << ": \""; t << " " << j << ": \"";
for (p=0;p<MEMBER_INDEX_ENTRIES;p++)
SIntDict<SearchIndexList>::Iterator it(g_searchIndexSymbols[i]);
SearchIndexList *sl;
for (it.toFirst();(sl=it.current());++it) // for each letter
{ {
t << (g_searchIndexSymbols[i][p].count()>0 ? "1" : "0"); t << QString( QChar( sl->letter() ) ).utf8();
} }
t << "\""; t << "\"";
first=FALSE; first=FALSE;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <qlist.h> #include <qlist.h>
#include <ctype.h> #include <ctype.h>
#include "types.h" #include "types.h"
#include "sortdict.h"
//-------------------------------------------------------------------- //--------------------------------------------------------------------
...@@ -87,6 +88,33 @@ class TextGeneratorOLImpl : public TextGeneratorIntf ...@@ -87,6 +88,33 @@ class TextGeneratorOLImpl : public TextGeneratorIntf
//-------------------------------------------------------------------- //--------------------------------------------------------------------
/** @brief maps a unicode character code to a list of T::ElementType's
*/
template<class T>
class LetterToIndexMap : public SIntDict<T>
{
public:
LetterToIndexMap() { SIntDict<T>::setAutoDelete(TRUE); }
int compareItems(QCollection::Item item1, QCollection::Item item2)
{
T *l1=(T *)item1;
T *l2=(T *)item2;
return (int)l1->letter()-(int)l2->letter();
}
void append(uint letter,typename T::ElementType *elem)
{
T *l = SIntDict<T>::find((int)letter);
if (l==0)
{
l = new T(letter);
SIntDict<T>::inSort((int)letter,l);
}
l->append(elem);
}
};
//--------------------------------------------------------------------
QCString langToString(SrcLangExt lang); QCString langToString(SrcLangExt lang);
QCString getLanguageSpecificSeparator(SrcLangExt lang,bool classScope=FALSE); QCString getLanguageSpecificSeparator(SrcLangExt lang,bool classScope=FALSE);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment