/******************************************************************************
*
*
*
*
* Copyright (C) 1997-2010 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 <stdio.h>
#include <stdlib.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qcstring.h>
#include <qstack.h>
#include <qdict.h>
#include <qregexp.h>
#include <ctype.h>
#include "doxygen.h"
#include "debug.h"
#include "util.h"
#include "pagedef.h"
#include "docparser.h"
#include "doctokenizer.h"
#include "cmdmapper.h"
#include "printdocvisitor.h"
#include "message.h"
#include "section.h"
#include "searchindex.h"
#include "language.h"
#include "portable.h"
// debug off
#define DBG(x) do {} while(0)
// debug to stdout
//#define DBG(x) printf x
// debug to stderr
//#define myprintf(x...) fprintf(stderr,x)
//#define DBG(x) myprintf x
#define INTERNAL_ASSERT(x) do {} while(0)
//#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__));
//---------------------------------------------------------------------------
static const char *sectionLevelToName[] =
{
"page",
"section",
"subsection",
"subsubsection",
"paragraph"
};
//---------------------------------------------------------------------------
// Parser state: global variables during a call to validatingParseDoc
static Definition * g_scope;
static QString g_context;
static bool g_inSeeBlock;
static bool g_insideHtmlLink;
static QStack<DocNode> g_nodeStack;
static QStack<DocStyleChange> g_styleStack;
static QStack<DocStyleChange> g_initialStyleStack;
static QList<Definition> g_copyStack;
static QString g_fileName;
static QString g_relPath;
static bool g_hasParamCommand;
static bool g_hasReturnCommand;
static QDict<void> g_paramsFound;
static MemberDef * g_memberDef;
static bool g_isExample;
static QCString g_exampleName;
static SectionDict * g_sectionDict;
static QCString g_searchUrl;
static QString g_includeFileText;
static uint g_includeFileOffset;
static uint g_includeFileLength;
// parser's context to store all global variables
struct DocParserContext
{
Definition *scope;
QString context;
bool inSeeBlock;
bool insideHtmlLink;
QStack<DocNode> nodeStack;
QStack<DocStyleChange> styleStack;
QStack<DocStyleChange> initialStyleStack;
QList<Definition> copyStack;
QString fileName;
QString relPath;
bool hasParamCommand;
bool hasReturnCommand;
MemberDef * memberDef;
QDict<void> paramsFound;
bool isExample;
QCString exampleName;
SectionDict *sectionDict;
QCString searchUrl;
QString includeFileText;
uint includeFileOffset;
uint includeFileLength;
TokenInfo *token;
};
static QStack<DocParserContext> g_parserStack;
//---------------------------------------------------------------------------
static void docParserPushContext(bool saveParamInfo=TRUE)
{
//QCString indent;
//indent.fill(' ',g_parserStack.count()*2+2);
//printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count());
doctokenizerYYpushContext();
DocParserContext *ctx = new DocParserContext;
ctx->scope = g_scope;
ctx->context = g_context;
ctx->inSeeBlock = g_inSeeBlock;
ctx->insideHtmlLink = g_insideHtmlLink;
ctx->nodeStack = g_nodeStack;
ctx->styleStack = g_styleStack;
ctx->initialStyleStack = g_initialStyleStack;
ctx->copyStack = g_copyStack;
ctx->fileName = g_fileName;
ctx->relPath = g_relPath;
if (saveParamInfo)
{
ctx->hasParamCommand = g_hasParamCommand;
ctx->hasReturnCommand = g_hasReturnCommand;
ctx->paramsFound = g_paramsFound;
}
ctx->memberDef = g_memberDef;
ctx->isExample = g_isExample;
ctx->exampleName = g_exampleName;
ctx->sectionDict = g_sectionDict;
ctx->searchUrl = g_searchUrl;
ctx->includeFileText = g_includeFileText;
ctx->includeFileOffset = g_includeFileOffset;
ctx->includeFileLength = g_includeFileLength;
ctx->token = g_token;
g_token = new TokenInfo;
g_parserStack.push(ctx);
}
static void docParserPopContext(bool keepParamInfo=FALSE)
{
DocParserContext *ctx = g_parserStack.pop();
g_scope = ctx->scope;
g_context = ctx->context;
g_inSeeBlock = ctx->inSeeBlock;
g_insideHtmlLink = ctx->insideHtmlLink;
g_nodeStack = ctx->nodeStack;
g_styleStack = ctx->styleStack;
g_initialStyleStack = ctx->initialStyleStack;
g_copyStack = ctx->copyStack;
g_fileName = ctx->fileName;
g_relPath = ctx->relPath;
if (!keepParamInfo)
{
g_hasParamCommand = ctx->hasParamCommand;
g_hasReturnCommand = ctx->hasReturnCommand;
g_paramsFound = ctx->paramsFound;
}
g_memberDef = ctx->memberDef;
g_isExample = ctx->isExample;
g_exampleName = ctx->exampleName;
g_sectionDict = ctx->sectionDict;
g_searchUrl = ctx->searchUrl;
g_includeFileText = ctx->includeFileText;
g_includeFileOffset = ctx->includeFileOffset;
g_includeFileLength = ctx->includeFileLength;
delete g_token;
g_token = ctx->token;
delete ctx;
doctokenizerYYpopContext();
//QCString indent;
//indent.fill(' ',g_parserStack.count()*2+2);
//printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count());
}
//---------------------------------------------------------------------------
/*! search for an image in the imageNameDict and if found
* copies the image to the output directory (which depends on the \a type
* parameter).
*/
static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
{
QCString result;
bool ambig;
FileDef *fd;
//printf("Search for %s\n",fileName);
if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
{
QCString inputFile = fd->absFilePath();
QFile inImage(inputFile);
if (inImage.open(IO_ReadOnly))
{
result = fileName;
int i;
if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1)
{
result = result.right(result.length()-i-1);
}
//printf("fileName=%s result=%s\n",fileName,result.data());
QCString outputDir;
switch(type)
{
case DocImage::Html:
if (!Config_getBool("GENERATE_HTML")) return result;
outputDir = Config_getString("HTML_OUTPUT");
break;
case DocImage::Latex:
if (!Config_getBool("GENERATE_LATEX")) return result;
outputDir = Config_getString("LATEX_OUTPUT");
break;
case DocImage::Rtf:
if (!Config_getBool("GENERATE_RTF")) return result;
outputDir = Config_getString("RTF_OUTPUT");
break;
}
QCString outputFile = outputDir+"/"+result;
if (outputFile!=inputFile) // prevent copying to ourself
{
QFile outImage(outputFile.data());
if (outImage.open(IO_WriteOnly)) // copy the image
{
char *buffer = new char[inImage.size()];
inImage.readBlock(buffer,inImage.size());
outImage.writeBlock(buffer,inImage.size());
outImage.flush();
delete[] buffer;
if (type==DocImage::Html) Doxygen::indexList.addImageFile(result);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,
"Warning: could not write output image %s",outputFile.data());
}
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,
"Warning: could not open image %s",fileName);
}
if (type==DocImage::Latex && Config_getBool("USE_PDFLATEX") &&
fd->name().right(4)==".eps"
)
{ // we have an .eps image in pdflatex mode => convert it to a pdf.
QCString outputDir = Config_getString("LATEX_OUTPUT");
QCString baseName = fd->name().left(fd->name().length()-4);
QCString epstopdfArgs(4096);
epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"",
outputDir.data(), baseName.data(),
outputDir.data(), baseName.data());
if (portable_system("epstopdf",epstopdfArgs)!=0)
{
err("Error: Problems running epstopdf. Check your TeX installation!\n");
}
return baseName;
}
}
else if (ambig)
{
QCString text;
text.sprintf("Warning: image file name %s is ambigious.\n",fileName);
text+="Possible candidates:\n";
text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
warn_doc_error(g_fileName,doctokenizerYYlineno,text);
}
else
{
result=fileName;
if (result.left(5)!="http:" && result.left(6)!="https:")
{
warn_doc_error(g_fileName,doctokenizerYYlineno,
"Warning: image file %s is not found in IMAGE_PATH: "
"assuming external image.",fileName
);
}
}
return result;
}
/*! Collects the parameters found with \@param or \@retval commands
* in a global list g_paramsFound. If \a isParam is set to TRUE
* and the parameter is not an actual parameter of the current
* member g_memberDef, then a warning is raised (unless warnings
* are disabled altogether).
*/
static void checkArgumentName(const QString &name,bool isParam)
{
if (!Config_getBool("WARN_IF_DOC_ERROR")) return;
if (g_memberDef==0) return; // not a member
LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ?
g_memberDef->argumentList() :
g_memberDef->declArgumentList();
//printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition());
if (al==0) return; // no argument list
static QRegExp re("[a-zA-Z0-9_\\x80-\\xFF]+\\.*");
int p=0,i=0,l;
while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
{
QString aName=name.mid(i,l);
//printf("aName=`%s'\n",aName.data());
ArgumentListIterator ali(*al);
Argument *a;
bool found=FALSE;
for (ali.toFirst();(a=ali.current());++ali)
{
QString argName = g_memberDef->isDefine() ? a->type : a->name;
argName=argName.stripWhiteSpace();
//printf("argName=`%s'\n",argName.data());
if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
if (aName==argName)
{
//printf("adding `%s'\n",aName.data());
g_paramsFound.insert(aName,(void *)(0x8));
found=TRUE;
break;
}
}
if (!found && isParam)
{
//printf("member type=%d\n",memberDef->memberType());
QString scope=g_memberDef->getScopeString();
if (!scope.isEmpty()) scope+="::"; else scope="";
QString inheritedFrom = "";
QString docFile = g_memberDef->docFile();
int docLine = g_memberDef->docLine();
MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom();
if (inheritedMd) // documentation was inherited
{
inheritedFrom.sprintf(" inherited from member %s at line "
"%d in file %s",inheritedMd->name().data(),
inheritedMd->docLine(),inheritedMd->docFile().data());
docFile = g_memberDef->getDefFileName();
docLine = g_memberDef->getDefLine();
}
warn_doc_error(docFile,docLine,
"Warning: argument '%s' of command @param "
"is not found in the argument list of %s%s%s%s",
aName.data(),scope.data(),g_memberDef->name().data(),
argListToString(al.pointer()).data(),inheritedFrom.data());
}
p=i+l;
}
}
/*! Checks if the parameters that have been specified using \@param are
* indeed all paramters.
* Must be called after checkArgumentName() has been called for each
* argument.
*/
static void checkUndocumentedParams()
{
if (g_memberDef && g_hasParamCommand && Config_getBool("WARN_IF_DOC_ERROR"))
{
LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ?
g_memberDef->argumentList() :
g_memberDef->declArgumentList();
if (al!=0)
{
ArgumentListIterator ali(*al);
Argument *a;
bool found=FALSE;
for (ali.toFirst();(a=ali.current());++ali)
{
QString argName = g_memberDef->isDefine() ? a->type : a->name;
argName=argName.stripWhiteSpace();
if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
if (getLanguageFromFileName(g_memberDef->getDefFileName())==SrcLangExt_Python && argName=="self")
{
// allow undocumented self parameter for Python
}
else if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty())
{
found = TRUE;
break;
}
}
if (found)
{
bool first=TRUE;
QString errMsg=
"Warning: The following parameters of "+
QString(g_memberDef->qualifiedName()) +
QString(argListToString(al.pointer())) +
" are not documented:\n";
for (ali.toFirst();(a=ali.current());++ali)
{
QString argName = g_memberDef->isDefine() ? a->type : a->name;
argName=argName.stripWhiteSpace();
if (getLanguageFromFileName(g_memberDef->getDefFileName())==SrcLangExt_Python && argName=="self")
{
// allow undocumented self parameter for Python
}
else if (!argName.isEmpty() && g_paramsFound.find(argName)==0)
{
if (!first)
{
errMsg+="\n";
}
else
{
first=FALSE;
}
errMsg+=" parameter '"+argName+"'";
}
}
if (g_memberDef->inheritsDocsFrom())
{
warn_doc_error(g_memberDef->getDefFileName(),
g_memberDef->getDefLine(),
substitute(errMsg,"%","%%"));
}
else
{
warn_doc_error(g_memberDef->docFile(),
g_memberDef->docLine(),
substitute(errMsg,"%","%%"));
}
}
}
}
}
/*! Check if a member has documentation for its parameter and or return
* type, if applicable. If found this will be stored in the member, this
* is needed as a member can have brief and detailed documentation, while
* only one of these needs to document the parameters.
*/
static void detectNoDocumentedParams()
{
if (g_memberDef && Config_getBool("WARN_NO_PARAMDOC"))
{
LockingPtr<ArgumentList> al = g_memberDef->argumentList();
LockingPtr<ArgumentList> declAl = g_memberDef->declArgumentList();
QString returnType = g_memberDef->typeString();
bool isPython = getLanguageFromFileName(g_memberDef->getDefFileName())==SrcLangExt_Python;
if (!g_memberDef->hasDocumentedParams() &&
g_hasParamCommand)
{
//printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
g_memberDef->setHasDocumentedParams(TRUE);
}
else if (!g_memberDef->hasDocumentedParams())
{
bool allDoc=TRUE; // no paramater => all parameters are documented
if ( // member has parameters
al!=0 && // but the member has a parameter list
al->count()>0 // with at least one parameter (that is not void)
)
{
ArgumentListIterator ali(*al);
Argument *a;
// see if all parameters have documentation
for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
{
if (!a->name.isEmpty() && a->type!="void" &&
!(isPython && a->name=="self")
)
{
allDoc = !a->docs.isEmpty();
}
//printf("a->type=%s a->name=%s doc=%s\n",
// a->type.data(),a->name.data(),a->docs.data());
}
if (!allDoc && declAl!=0) // try declaration arguments as well
{
allDoc=TRUE;
ArgumentListIterator ali(*declAl);
Argument *a;
for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
{
if (!a->name.isEmpty() && a->type!="void" &&
!(isPython && a->name=="self")
)
{
allDoc = !a->docs.isEmpty();
}
//printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data());
}
}
}
if (allDoc)
{
//printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
g_memberDef->setHasDocumentedParams(TRUE);
}
}
//printf("Member %s hasReturnCommand=%d\n",g_memberDef->name().data(),g_hasReturnCommand);
if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found
g_hasReturnCommand)
{
g_memberDef->setHasDocumentedReturnType(TRUE);
}
else if ( // see if return needs to documented
g_memberDef->hasDocumentedReturnType() ||
returnType.isEmpty() || // empty return type
returnType.find("void")!=-1 || // void return type
g_memberDef->isConstructor() || // a constructor
g_memberDef->isDestructor() // or destructor
)
{
g_memberDef->setHasDocumentedReturnType(TRUE);
}
}
}
//---------------------------------------------------------------------------
/*! Strips known html and tex extensions from \a text. */
static QString stripKnownExtensions(const char *text)
{
QString result=text;
if (result.right(4)==".tex")
{
result=result.left(result.length()-4);
}
else if (result.right(Doxygen::htmlFileExtension.length())==
QString(Doxygen::htmlFileExtension))
{
result=result.left(result.length()-Doxygen::htmlFileExtension.length());
}
return result;
}
//---------------------------------------------------------------------------
/*! Returns TRUE iff node n is a child of a preformatted node */
static bool insidePRE(DocNode *n)
{
while (n)
{
if (n->isPreformatted()) return TRUE;
n=n->parent();
}
return FALSE;
}
//---------------------------------------------------------------------------
/*! Returns TRUE iff node n is a child of a html list item node */
static bool insideLI(DocNode *n)
{
while (n)
{
if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE;
n=n->parent();
}
return FALSE;
}
//---------------------------------------------------------------------------
/*! Returns TRUE iff node n is a child of a unordered html list node */
static bool insideUL(DocNode *n)
{
while (n)
{
if (n->kind()==DocNode::Kind_HtmlList &&
((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE;
n=n->parent();
}
return FALSE;
}
//---------------------------------------------------------------------------
/*! Returns TRUE iff node n is a child of a ordered html list node */
static bool insideOL(DocNode *n)
{
while (n)
{
if (n->kind()==DocNode::Kind_HtmlList &&
((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE;
n=n->parent();
}
return FALSE;
}
//---------------------------------------------------------------------------
static bool insideTable(DocNode *n)
{
while (n)
{
if (n->kind()==DocNode::Kind_HtmlTable) return TRUE;
n=n->parent();
}
return FALSE;
}
//---------------------------------------------------------------------------
///*! Returns TRUE iff node n is a child of a language node */
//static bool insideLang(DocNode *n)
//{
// while (n)
// {
// if (n->kind()==DocNode::Kind_Language) return TRUE;
// n=n->parent();
// }
// return FALSE;
//}
//---------------------------------------------------------------------------
/*! Looks for a documentation block with name commandName in the current
* context (g_context). The resulting documentation string is
* put in pDoc, the definition in which the documentation was found is
* put in pDef.
* @retval TRUE if name was found.
* @retval FALSE if name was not found.
*/
static bool findDocsForMemberOrCompound(const char *commandName,
QString *pDoc,
QString *pBrief,
Definition **pDef)
{
//printf("findDocsForMemberOrCompound(%s)\n",commandName);
*pDoc="";
*pBrief="";
*pDef=0;
QString cmdArg=substitute(commandName,"#","::");
int l=cmdArg.length();
if (l==0) return FALSE;
int funcStart=cmdArg.find('(');
if (funcStart==-1)
{
funcStart=l;
}
else
{
// Check for the case of operator() and the like.
// beware of scenarios like operator()((foo)bar)
int secondParen = cmdArg.find('(', funcStart+1);
int leftParen = cmdArg.find(')', funcStart+1);
if (leftParen!=-1 && secondParen!=-1)
{
if (leftParen<secondParen)
{
funcStart=secondParen;
}
}
}
QString name=removeRedundantWhiteSpace(cmdArg.left(funcStart).latin1());
QString args=cmdArg.right(l-funcStart);
// try if the link is to a member
MemberDef *md=0;
ClassDef *cd=0;
FileDef *fd=0;
NamespaceDef *nd=0;
GroupDef *gd=0;
PageDef *pd=0;
bool found = getDefs(
g_context.find('.')==-1?g_context.latin1():"", // `find('.') is a hack to detect files
name.latin1(),
args.isEmpty()?0:args.latin1(),
md,cd,fd,nd,gd,FALSE,0,TRUE);
//printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data());
if (found && md)
{
*pDoc=md->documentation();
*pBrief=md->briefDescription();
*pDef=md;
return TRUE;
}
int scopeOffset=g_context.length();
do // for each scope
{
QString fullName=cmdArg;
if (scopeOffset>0)
{
fullName.prepend(g_context.left(scopeOffset)+"::");
}
//printf("Trying fullName=`%s'\n",fullName.data());
// try class, namespace, group, page, file reference
cd = Doxygen::classSDict->find(fullName);
if (cd) // class
{
*pDoc=cd->documentation();
*pBrief=cd->briefDescription();
*pDef=cd;
return TRUE;
}
nd = Doxygen::namespaceSDict->find(fullName);
if (nd) // namespace
{
*pDoc=nd->documentation();
*pBrief=nd->briefDescription();
*pDef=nd;
return TRUE;
}
gd = Doxygen::groupSDict->find(cmdArg);
if (gd) // group
{
*pDoc=gd->documentation();
*pBrief=gd->briefDescription();
*pDef=gd;
return TRUE;
}
pd = Doxygen::pageSDict->find(cmdArg);
if (pd) // page
{
*pDoc=pd->documentation();
*pBrief=pd->briefDescription();
*pDef=pd;
return TRUE;
}
bool ambig;
fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig);
if (fd && !ambig) // file
{
*pDoc=fd->documentation();
*pBrief=fd->briefDescription();
*pDef=fd;
return TRUE;
}
if (scopeOffset==0)
{
scopeOffset=-1;
}
else
{
scopeOffset = g_context.findRev("::",scopeOffset-1);
if (scopeOffset==-1) scopeOffset=0;
}
} while (scopeOffset>=0);
return FALSE;
}
//---------------------------------------------------------------------------
// forward declaration
static bool defaultHandleToken(DocNode *parent,int tok,
QList<DocNode> &children,bool
handleWord=TRUE);
static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
const QString &cmdName)
{
DBG(("handleStyleArgument(%s)\n",cmdName.data()));
QString tokenName = g_token->name;
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return tok;
}
while ((tok=doctokenizerYYlex()) &&
tok!=TK_WHITESPACE &&
tok!=TK_NEWPARA &&
tok!=TK_LISTITEM &&
tok!=TK_ENDLIST
)
{
static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
if (tok==TK_WORD && g_token->name.length()==1 &&
g_token->name.find(specialChar)!=-1)
{
// special character that ends the markup command
return tok;
}
if (!defaultHandleToken(parent,tok,children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command \\%s as the argument of a \\%s command",
g_token->name.data(),cmdName.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found while handling command %s",
g_token->name.data(),cmdName.data());
break;
case TK_HTMLTAG:
if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
{ // ignore </li> as the end of a style command
continue;
}
return tok;
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s while handling command %s",
tokToString(tok),cmdName.data());
break;
}
break;
}
}
DBG(("handleStyleArgument(%s) end tok=%x\n",cmdName.data(),tok));
return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
) ? tok : RetVal_OK;
}
/*! Called when a style change starts. For instance a \<b\> command is
* encountered.
*/
static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
DocStyleChange::Style s,const HtmlAttribList *attribs)
{
DBG(("HandleStyleEnter\n"));
DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs);
children.append(sc);
g_styleStack.push(sc);
}
/*! Called when a style change ends. For instance a \</b\> command is
* encountered.
*/
static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
DocStyleChange::Style s,const char *tagName)
{
DBG(("HandleStyleLeave\n"));
if (g_styleStack.isEmpty() || // no style change
g_styleStack.top()->style()!=s || // wrong style change
g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
)
{
if (g_styleStack.isEmpty())
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag without matching <%s>",
tagName,tagName);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag while expecting </%s>",
tagName,g_styleStack.top()->styleString());
}
}
else // end the section
{
DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE);
children.append(sc);
g_styleStack.pop();
}
}
/*! Called at the end of a paragraph to close all open style changes
* (e.g. a <b> without a </b>). The closed styles are pushed onto a stack
* and entered again at the start of a new paragraph.
*/
static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
{
if (!g_styleStack.isEmpty())
{
DocStyleChange *sc = g_styleStack.top();
while (sc && sc->position()>=g_nodeStack.count())
{ // there are unclosed style modifiers in the paragraph
children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
g_initialStyleStack.push(sc);
g_styleStack.pop();
sc = g_styleStack.top();
}
}
}
static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
{
DocStyleChange *sc;
while ((sc=g_initialStyleStack.pop()))
{
handleStyleEnter(parent,children,sc->style(),&sc->attribs());
}
}
static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
{
HtmlAttribListIterator li(tagHtmlAttribs);
HtmlAttrib *opt;
int index=0;
int retval = RetVal_OK;
for (li.toFirst();(opt=li.current());++li,++index)
{
if (opt->name=="name") // <a name=label> tag
{
if (!opt->value.isEmpty())
{
DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE);
children.append(anc);
break; // stop looking for other tag attribs
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <a> tag with name option but without value!");
}
}
else if (opt->name=="href") // <a href=url>..</a> tag
{
// copy attributes
HtmlAttribList attrList = tagHtmlAttribs;
// and remove the href attribute
bool result = attrList.remove(index);
ASSERT(result);
DocHRef *href = new DocHRef(parent,attrList,opt->value);
children.append(href);
g_insideHtmlLink=TRUE;
retval = href->parse();
g_insideHtmlLink=FALSE;
break;
}
else // unsupported option for tag a
{
}
}
return retval;
}
const char *DocStyleChange::styleString() const
{
switch (m_style)
{
case DocStyleChange::Bold: return "b";
case DocStyleChange::Italic: return "em";
case DocStyleChange::Code: return "code";
case DocStyleChange::Center: return "center";
case DocStyleChange::Small: return "small";
case DocStyleChange::Subscript: return "subscript";
case DocStyleChange::Superscript: return "superscript";
case DocStyleChange::Preformatted: return "pre";
case DocStyleChange::Div: return "div";
case DocStyleChange::Span: return "span";
}
return "<invalid>";
}
static void handleUnclosedStyleCommands()
{
if (!g_initialStyleStack.isEmpty())
{
DocStyleChange *sc = g_initialStyleStack.top();
g_initialStyleStack.pop();
handleUnclosedStyleCommands();
warn_doc_error(g_fileName,doctokenizerYYlineno,
"Warning: end of comment block while expecting "
"command </%s>",sc->styleString());
}
}
static void handleLinkedWord(DocNode *parent,QList<DocNode> &children)
{
Definition *compound=0;
MemberDef *member=0;
QString name = linkToText(g_token->name,TRUE);
int len = g_token->name.length();
ClassDef *cd=0;
bool ambig;
FileDef *fd = findFileDef(Doxygen::inputNameDict,g_fileName,ambig);
//printf("handleLinkedWord(%s) g_context=%s\n",name.data(),g_context.data());
if (!g_insideHtmlLink &&
(resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member,TRUE,fd)
|| (!g_context.isEmpty() && // also try with global scope
resolveRef("",g_token->name,g_inSeeBlock,&compound,&member))
)
)
{
//printf("resolveRef %s = %p (linkable?=%d)\n",g_token->name.data(),member,member ? member->isLinkable() : FALSE);
if (member && member->isLinkable()) // member link
{
if (member->isObjCMethod())
{
bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
name = member->objCMethodName(localLink,g_inSeeBlock);
}
children.append(new
DocLinkedWord(parent,name,
member->getReference(),
member->getOutputFileBase(),
member->anchor(),
member->briefDescriptionAsTooltip()
)
);
}
else if (compound->isLinkable()) // compound link
{
if (compound->definitionType()==Definition::TypeFile)
{
name=g_token->name;
}
else if (compound->definitionType()==Definition::TypeGroup)
{
name=((GroupDef*)compound)->groupTitle();
}
children.append(new
DocLinkedWord(parent,name,
compound->getReference(),
compound->getOutputFileBase(),
"",
compound->briefDescriptionAsTooltip()
)
);
}
else if (compound->definitionType()==Definition::TypeFile &&
((FileDef*)compound)->generateSourceFile()
) // undocumented file that has source code we can link to
{
children.append(new
DocLinkedWord(parent,g_token->name,
compound->getReference(),
compound->getSourceFileBase(),
"",
compound->briefDescriptionAsTooltip()
)
);
}
else // not linkable
{
children.append(new DocWord(parent,name));
}
}
else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':')
{
// special case, where matching Foo: fails to be an Obj-C reference,
// but Foo itself might be linkable.
g_token->name=g_token->name.left(len-1);
handleLinkedWord(parent,children);
children.append(new DocWord(parent,":"));
}
else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p")))
{
// special case 2, where the token name is not a class, but could
// be a Obj-C protocol
children.append(new
DocLinkedWord(parent,name,
cd->getReference(),
cd->getOutputFileBase(),
"",
cd->briefDescriptionAsTooltip()
));
}
else // normal non-linkable word
{
if (g_token->name.at(0)=='#')
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: explicit link request to '%s' could not be resolved",name.data());
}
children.append(new DocWord(parent,name));
}
}
/* Helper function that deals with the most common tokens allowed in
* title like sections.
* @param parent Parent node, owner of the children list passed as
* the third argument.
* @param tok The token to process.
* @param children The list of child nodes to which the node representing
* the token can be added.
* @param handleWord Indicates if word token should be processed
* @retval TRUE The token was handled.
* @retval FALSE The token was not handled.
*/
static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool
handleWord)
{
DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
tok==TK_COMMAND || tok==TK_HTMLTAG
)
{
DBG((" name=%s",g_token->name.data()));
}
DBG(("\n"));
reparsetoken:
QString tokenName = g_token->name;
switch (tok)
{
case TK_COMMAND:
switch (Mappers::cmdMapper->map(tokenName))
{
case CMD_BSLASH:
children.append(new DocSymbol(parent,DocSymbol::BSlash));
break;
case CMD_AT:
children.append(new DocSymbol(parent,DocSymbol::At));
break;
case CMD_LESS:
children.append(new DocSymbol(parent,DocSymbol::Less));
break;
case CMD_GREATER:
children.append(new DocSymbol(parent,DocSymbol::Greater));
break;
case CMD_AMP:
children.append(new DocSymbol(parent,DocSymbol::Amp));
break;
case CMD_DOLLAR:
children.append(new DocSymbol(parent,DocSymbol::Dollar));
break;
case CMD_HASH:
children.append(new DocSymbol(parent,DocSymbol::Hash));
break;
case CMD_PERCENT:
children.append(new DocSymbol(parent,DocSymbol::Percent));
break;
case CMD_QUOTE:
children.append(new DocSymbol(parent,DocSymbol::Quot));
break;
case CMD_EMPHASIS:
{
children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
tok=handleStyleArgument(parent,children,tokenName);
children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
if (tok==TK_NEWPARA) goto handlepara;
else if (tok==TK_WORD || tok==TK_HTMLTAG)
{
DBG(("CMD_EMPHASIS: reparsing command %s\n",g_token->name.data()));
goto reparsetoken;
}
}
break;
case CMD_BOLD:
{
children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
tok=handleStyleArgument(parent,children,tokenName);
children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
if (tok==TK_NEWPARA) goto handlepara;
else if (tok==TK_WORD || tok==TK_HTMLTAG)
{
DBG(("CMD_BOLD: reparsing command %s\n",g_token->name.data()));
goto reparsetoken;
}
}
break;
case CMD_CODE:
{
children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE));
tok=handleStyleArgument(parent,children,tokenName);
children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE));
if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
if (tok==TK_NEWPARA) goto handlepara;
else if (tok==TK_WORD || tok==TK_HTMLTAG)
{
DBG(("CMD_CODE: reparsing command %s\n",g_token->name.data()));
goto reparsetoken;
}
}
break;
case CMD_HTMLONLY:
{
doctokenizerYYsetStateHtmlOnly();
tok = doctokenizerYYlex();
children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: htmlonly section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_MANONLY:
{
doctokenizerYYsetStateManOnly();
tok = doctokenizerYYlex();
children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: manonly section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_LATEXONLY:
{
doctokenizerYYsetStateLatexOnly();
tok = doctokenizerYYlex();
children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: latexonly section ended without end marker",doctokenizerYYlineno);
doctokenizerYYsetStatePara();
}
break;
case CMD_XMLONLY:
{
doctokenizerYYsetStateXmlOnly();
tok = doctokenizerYYlex();
children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: xmlonly section ended without end marker",doctokenizerYYlineno);
doctokenizerYYsetStatePara();
}
break;
case CMD_FORMULA:
{
DocFormula *form=new DocFormula(parent,g_token->id);
children.append(form);
}
break;
case CMD_ANCHOR:
{
tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
tokenName.data());
break;
}
tok=doctokenizerYYlex();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s",tokenName.data());
break;
}
else if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),tokenName.data());
break;
}
DocAnchor *anchor = new DocAnchor(parent,g_token->name,FALSE);
children.append(anchor);
}
break;
case CMD_INTERNALREF:
{
tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
tokenName.data());
break;
}
doctokenizerYYsetStateInternalRef();
tok=doctokenizerYYlex(); // get the reference id
DocInternalRef *ref=0;
if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),tokenName.data());
doctokenizerYYsetStatePara();
break;
}
ref = new DocInternalRef(parent,g_token->name);
children.append(ref);
ref->parse();
doctokenizerYYsetStatePara();
}
break;
default:
return FALSE;
}
break;
case TK_HTMLTAG:
{
switch (Mappers::htmlTagMapper->map(tokenName))
{
case HTML_DIV:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <div> tag in heading\n");
break;
case HTML_PRE:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <pre> tag in heading\n");
break;
case HTML_BOLD:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
}
break;
case HTML_CODE:
case XML_C:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Code,tokenName);
}
break;
case HTML_EMPHASIS:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName);
}
break;
case HTML_SUB:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName);
}
break;
case HTML_SUP:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName);
}
break;
case HTML_CENTER:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Center,tokenName);
}
break;
case HTML_SMALL:
if (!g_token->endTag)
{
handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs);
}
else
{
handleStyleLeave(parent,children,DocStyleChange::Small,tokenName);
}
break;
default:
return FALSE;
break;
}
}
break;
case TK_SYMBOL:
{
char letter='\0';
DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName,&letter);
if (s!=DocSymbol::Unknown)
{
children.append(new DocSymbol(parent,s,letter));
}
else
{
return FALSE;
}
}
break;
case TK_WHITESPACE:
case TK_NEWPARA:
handlepara:
if (insidePRE(parent) || !children.isEmpty())
{
children.append(new DocWhiteSpace(parent,g_token->chars));
}
break;
case TK_LNKWORD:
if (handleWord)
{
handleLinkedWord(parent,children);
}
else
return FALSE;
break;
case TK_WORD:
if (handleWord)
{
children.append(new DocWord(parent,g_token->name));
}
else
return FALSE;
break;
case TK_URL:
if (g_insideHtmlLink)
{
children.append(new DocWord(parent,g_token->name));
}
else
{
children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr));
}
break;
default:
return FALSE;
}
return TRUE;
}
//---------------------------------------------------------------------------
DocSymbol::SymType DocSymbol::decodeSymbol(const QString &symName,char *letter)
{
int l=symName.length();
DBG(("decodeSymbol(%s) l=%d\n",symName.data(),l));
if (symName=="©") return DocSymbol::Copy;
else if (symName=="™") return DocSymbol::Tm;
else if (symName=="&tm;") return DocSymbol::Tm; // alias for ™
else if (symName=="®") return DocSymbol::Reg;
else if (symName=="<") return DocSymbol::Less;
else if (symName==">") return DocSymbol::Greater;
else if (symName=="&") return DocSymbol::Amp;
else if (symName=="'") return DocSymbol::Apos;
else if (symName==""") return DocSymbol::Quot;
else if (symName=="‘") return DocSymbol::Lsquo;
else if (symName=="’") return DocSymbol::Rsquo;
else if (symName=="“") return DocSymbol::Ldquo;
else if (symName=="”") return DocSymbol::Rdquo;
else if (symName=="–") return DocSymbol::Ndash;
else if (symName=="—") return DocSymbol::Mdash;
else if (symName=="ß") return DocSymbol::Szlig;
else if (symName==" ") return DocSymbol::Nbsp;
else if (symName=="Æ") return DocSymbol::AElig;
else if (symName=="æ") return DocSymbol::Aelig;
else if (l==6 && symName.right(4)=="uml;")
{
*letter=symName.at(1);
return DocSymbol::Uml;
}
else if (l==8 && symName.right(6)=="acute;")
{
*letter=symName.at(1);
return DocSymbol::Acute;
}
else if (l==8 && symName.right(6)=="grave;")
{
*letter=symName.at(1);
return DocSymbol::Grave;
}
else if (l==7 && symName.right(5)=="circ;")
{
*letter=symName.at(1);
return DocSymbol::Circ;
}
else if (l==8 && symName.right(6)=="tilde;")
{
*letter=symName.at(1);
return DocSymbol::Tilde;
}
else if (l==8 && symName.right(6)=="cedil;")
{
*letter=symName.at(1);
return DocSymbol::Cedil;
}
else if (l==7 && symName.right(5)=="ring;")
{
*letter=symName.at(1);
return DocSymbol::Ring;
}
else if (l==8 && symName.right(6)=="slash;")
{
*letter=symName.at(1);
return DocSymbol::Slash;
}
return DocSymbol::Unknown;
}
//---------------------------------------------------------------------------
static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
const QString &doc)
{
int retval = RetVal_OK;
if (doc.isEmpty()) return retval;
doctokenizerYYinit(doc,g_fileName);
// first parse any number of paragraphs
bool isFirst=TRUE;
DocPara *lastPar=0;
if (!children.isEmpty() && children.last()->kind()==DocNode::Kind_Para)
{ // last child item was a paragraph
lastPar = (DocPara*)children.last();
isFirst=FALSE;
}
do
{
DocPara *par = new DocPara(parent);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
retval=par->parse();
if (!par->isEmpty())
{
children.append(par);
if (lastPar) lastPar->markLast(FALSE);
lastPar=par;
}
else
{
delete par;
}
} while (retval==TK_NEWPARA);
if (lastPar) lastPar->markLast();
return retval;
}
//---------------------------------------------------------------------------
static void readTextFileByName(const QString &file,QString &text)
{
bool ambig;
FileDef *fd;
if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
{
text = fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES"));
}
else if (ambig)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included file name %s is ambigious"
"Possible candidates:\n%s",file.data(),
showFileDefMatches(Doxygen::exampleNameDict,file).data()
);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included file %s is not found. "
"Check your EXAMPLE_PATH",file.data());
}
}
//---------------------------------------------------------------------------
DocWord::DocWord(DocNode *parent,const QString &word) :
m_parent(parent), m_word(word)
{
//printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
{
Doxygen::searchIndex->addWord(word,FALSE);
}
}
//---------------------------------------------------------------------------
DocLinkedWord::DocLinkedWord(DocNode *parent,const QString &word,
const QString &ref,const QString &file,
const QString &anchor,const QString &tooltip) :
m_parent(parent), m_word(word), m_ref(ref),
m_file(file), m_relPath(g_relPath), m_anchor(anchor),
m_tooltip(tooltip)
{
//printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
{
Doxygen::searchIndex->addWord(word,FALSE);
}
}
//---------------------------------------------------------------------------
DocAnchor::DocAnchor(DocNode *parent,const QString &id,bool newAnchor)
: m_parent(parent)
{
if (id.isEmpty())
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Empty anchor label");
}
if (newAnchor) // found <a name="label">
{
m_anchor = id;
}
else // found \anchor label
{
SectionInfo *sec = Doxygen::sectionDict[id];
if (sec)
{
//printf("Found anchor %s\n",id.data());
m_file = sec->fileName;
m_anchor = sec->label;
if (g_sectionDict && g_sectionDict->find(id)==0)
{
//printf("Inserting in dictionary!\n");
g_sectionDict->insert(id,sec);
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid anchor id `%s'",id.data());
m_anchor = "invalid";
m_file = "invalid";
}
}
}
//---------------------------------------------------------------------------
DocVerbatim::DocVerbatim(DocNode *parent,const QString &context,
const QString &text, Type t,bool isExample,
const QString &exampleFile)
: m_parent(parent), m_context(context), m_text(text), m_type(t),
m_isExample(isExample), m_exampleFile(exampleFile), m_relPath(g_relPath)
{
}
//---------------------------------------------------------------------------
void DocInclude::parse()
{
DBG(("DocInclude::parse(file=%s,text=%s)\n",m_file.data(),m_text.data()));
switch(m_type)
{
case IncWithLines:
// fall through
case Include:
// fall through
case DontInclude:
readTextFileByName(m_file,m_text);
g_includeFileText = m_text;
g_includeFileOffset = 0;
g_includeFileLength = m_text.length();
//printf("g_includeFile=<<%s>>\n",g_includeFileText.data());
break;
case VerbInclude:
// fall through
case HtmlInclude:
readTextFileByName(m_file,m_text);
break;
}
}
//---------------------------------------------------------------------------
void DocIncOperator::parse()
{
const char *p = g_includeFileText;
uint l = g_includeFileLength;
uint o = g_includeFileOffset;
DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",p,o,l));
uint so = o,bo;
bool nonEmpty = FALSE;
switch(type())
{
case Line:
while (o<l)
{
char c = p[o];
if (c=='\n')
{
if (nonEmpty) break; // we have a pattern to match
so=o+1; // no pattern, skip empty line
}
else if (!isspace((uchar)c)) // no white space char
{
nonEmpty=TRUE;
}
o++;
}
if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
{
m_text = g_includeFileText.mid(so,o-so);
DBG(("DocIncOperator::parse() Line: %s\n",m_text.data()));
}
g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
break;
case SkipLine:
while (o<l)
{
so=o;
while (o<l)
{
char c = p[o];
if (c=='\n')
{
if (nonEmpty) break; // we have a pattern to match
so=o+1; // no pattern, skip empty line
}
else if (!isspace((uchar)c)) // no white space char
{
nonEmpty=TRUE;
}
o++;
}
if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
{
m_text = g_includeFileText.mid(so,o-so);
DBG(("DocIncOperator::parse() SkipLine: %s\n",m_text.data()));
break;
}
o++; // skip new line
}
g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
break;
case Skip:
while (o<l)
{
so=o;
while (o<l)
{
char c = p[o];
if (c=='\n')
{
if (nonEmpty) break; // we have a pattern to match
so=o+1; // no pattern, skip empty line
}
else if (!isspace((uchar)c)) // no white space char
{
nonEmpty=TRUE;
}
o++;
}
if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
{
break;
}
o++; // skip new line
}
g_includeFileOffset = so; // set pointer to start of new line
break;
case Until:
bo=o;
while (o<l)
{
so=o;
while (o<l)
{
char c = p[o];
if (c=='\n')
{
if (nonEmpty) break; // we have a pattern to match
so=o+1; // no pattern, skip empty line
}
else if (!isspace((uchar)c)) // no white space char
{
nonEmpty=TRUE;
}
o++;
}
if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
{
m_text = g_includeFileText.mid(bo,o-bo);
DBG(("DocIncOperator::parse() Until: %s\n",m_text.data()));
break;
}
o++; // skip new line
}
g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
break;
}
}
//---------------------------------------------------------------------------
void DocCopy::parse()
{
QString doc,brief;
Definition *def;
if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
{
if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
{
bool hasParamCommand = g_hasParamCommand;
bool hasReturnCommand = g_hasReturnCommand;
QDict<void> paramsFound = g_paramsFound;
//printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
// g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
docParserPushContext(FALSE);
g_scope = def;
if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
{
g_context=def->getOuterScope()->name();
}
else
{
g_context=def->name();
}
g_styleStack.clear();
g_nodeStack.clear();
g_copyStack.append(def);
// make sure the descriptions end with a newline, so the parser will correctly
// handle them in all cases.
//printf("doc='%s'\n",doc.data());
//printf("brief='%s'\n",brief.data());
if (m_copyBrief)
{
brief+='\n';
internalValidatingParseDoc(this,m_children,brief);
//printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
// g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
hasParamCommand = hasParamCommand || g_hasParamCommand;
hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
QDictIterator<void> it(g_paramsFound);
void *item;
for (;(item=it.current());++it)
{
paramsFound.insert(it.currentKey(),it.current());
}
}
if (m_copyDetails)
{
doc+='\n';
internalValidatingParseDoc(this,m_children,doc);
//printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
// g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
hasParamCommand = hasParamCommand || g_hasParamCommand;
hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
QDictIterator<void> it(g_paramsFound);
void *item;
for (;(item=it.current());++it)
{
paramsFound.insert(it.currentKey(),it.current());
}
}
g_copyStack.remove(def);
ASSERT(g_styleStack.isEmpty());
ASSERT(g_nodeStack.isEmpty());
docParserPopContext(TRUE);
g_hasParamCommand = hasParamCommand;
g_hasReturnCommand = hasReturnCommand;
g_paramsFound = paramsFound;
//printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
// g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
}
else // oops, recursion
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: recursive call chain of \\copydoc commands detected at %d\n",
doctokenizerYYlineno);
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: target %s of \\copydoc command not found",
m_link.data());
}
}
//---------------------------------------------------------------------------
DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) :
m_parent(parent), m_id(id), m_key(key), m_relPath(g_relPath)
{
}
bool DocXRefItem::parse()
{
QString listName;
RefList *refList = Doxygen::xrefLists->find(m_key);
if (refList &&
(
// either not a built-in list or the list is enabled
(m_key!="todo" || Config_getBool("GENERATE_TODOLIST")) &&
(m_key!="test" || Config_getBool("GENERATE_TESTLIST")) &&
(m_key!="bug" || Config_getBool("GENERATE_BUGLIST")) &&
(m_key!="deprecated" || Config_getBool("GENERATE_DEPRECATEDLIST"))
)
)
{
RefItem *item = refList->getRefItem(m_id);
ASSERT(item!=0);
if (item)
{
if (g_memberDef && g_memberDef->name().at(0)=='@')
{
m_file = "@"; // can't cross reference anonymous enum
m_anchor = "@";
}
else
{
m_file = convertNameToFile(refList->listName());
m_anchor = item->listAnchor;
}
m_title = refList->sectionTitle();
//printf("DocXRefItem: file=%s anchor=%s title=%s\n",
// m_file.data(),m_anchor.data(),m_title.data());
if (!item->text.isEmpty())
{
docParserPushContext();
internalValidatingParseDoc(this,m_children,item->text);
docParserPopContext();
}
}
return TRUE;
}
return FALSE;
}
//---------------------------------------------------------------------------
DocFormula::DocFormula(DocNode *parent,int id) :
m_parent(parent), m_relPath(g_relPath)
{
QString formCmd;
formCmd.sprintf("\\form#%d",id);
Formula *formula=Doxygen::formulaNameDict[formCmd];
if (formula)
{
m_id = formula->getId();
m_name.sprintf("form_%d",m_id);
m_text = formula->getFormulaText();
}
}
//---------------------------------------------------------------------------
//int DocLanguage::parse()
//{
// int retval;
// DBG(("DocLanguage::parse() start\n"));
// g_nodeStack.push(this);
//
// // parse one or more paragraphs
// bool isFirst=TRUE;
// DocPara *par=0;
// do
// {
// par = new DocPara(this);
// if (isFirst) { par->markFirst(); isFirst=FALSE; }
// m_children.append(par);
// retval=par->parse();
// }
// while (retval==TK_NEWPARA);
// if (par) par->markLast();
//
// DBG(("DocLanguage::parse() end\n"));
// DocNode *n = g_nodeStack.pop();
// ASSERT(n==this);
// return retval;
//}
//---------------------------------------------------------------------------
void DocSecRefItem::parse()
{
DBG(("DocSecRefItem::parse() start\n"));
g_nodeStack.push(this);
doctokenizerYYsetStateTitle();
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\refitem",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
doctokenizerYYsetStatePara();
handlePendingStyleCommands(this,m_children);
SectionInfo *sec=0;
if (!m_target.isEmpty())
{
sec=Doxygen::sectionDict[m_target];
if (sec)
{
m_file = sec->fileName;
m_anchor = sec->label;
if (g_sectionDict && g_sectionDict->find(m_target)==0)
{
g_sectionDict->insert(m_target,sec);
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning reference to unknown section %s",
m_target.data());
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning reference to empty target");
}
DBG(("DocSecRefItem::parse() end\n"));
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
}
//---------------------------------------------------------------------------
void DocSecRefList::parse()
{
DBG(("DocSecRefList::parse() start\n"));
g_nodeStack.push(this);
int tok=doctokenizerYYlex();
// skip white space
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// handle items
while (tok)
{
if (tok==TK_COMMAND)
{
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_SECREFITEM:
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after \\refitem command");
break;
}
tok=doctokenizerYYlex();
if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of \\refitem",
tokToString(tok));
break;
}
DocSecRefItem *item = new DocSecRefItem(this,g_token->name);
m_children.append(item);
item->parse();
}
break;
case CMD_ENDSECREFLIST:
goto endsecreflist;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\secreflist",
g_token->name.data());
goto endsecreflist;
}
}
else if (tok==TK_WHITESPACE)
{
// ignore whitespace
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s inside section reference list",
tokToString(tok));
goto endsecreflist;
}
tok=doctokenizerYYlex();
}
endsecreflist:
DBG(("DocSecRefList::parse() end\n"));
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
}
//---------------------------------------------------------------------------
DocInternalRef::DocInternalRef(DocNode *parent,const QString &ref)
: m_parent(parent), m_relPath(g_relPath)
{
int i=ref.find('#');
if (i!=-1)
{
m_anchor = ref.right(ref.length()-i-1);
m_file = ref.left(i);
}
else
{
m_file = ref;
}
}
void DocInternalRef::parse()
{
g_nodeStack.push(this);
DBG(("DocInternalRef::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\ref",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
handlePendingStyleCommands(this,m_children);
DBG(("DocInternalRef::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
}
//---------------------------------------------------------------------------
DocRef::DocRef(DocNode *parent,const QString &target,const QString &context) :
m_parent(parent), m_refToSection(FALSE), m_refToAnchor(FALSE)
{
Definition *compound = 0;
QCString anchor;
//printf("DocRef::DocRef(target=%s,context=%s\n",target.data(),context.data());
ASSERT(!target.isEmpty());
m_relPath = g_relPath;
SectionInfo *sec = Doxygen::sectionDict[target];
if (sec) // ref to section or anchor
{
m_text = sec->title;
if (m_text.isEmpty()) m_text = sec->label;
m_ref = sec->ref;
m_file = stripKnownExtensions(sec->fileName);
if (sec->type!=SectionInfo::Page) m_anchor = sec->label;
m_refToAnchor = sec->type==SectionInfo::Anchor;
m_refToSection = sec->type!=SectionInfo::Anchor;
//printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d type=%d\n",
// m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor,sec->type);
return;
}
else if (resolveLink(context,target,TRUE,&compound,anchor))
{
bool isFile = compound ?
(compound->definitionType()==Definition::TypeFile ? TRUE : FALSE) :
FALSE;
m_text = linkToText(target,isFile);
m_anchor = anchor;
if (compound && compound->isLinkable()) // ref to compound
{
if (anchor.isEmpty() && /* compound link */
compound->definitionType()==Definition::TypeGroup && /* is group */
((GroupDef *)compound)->groupTitle() /* with title */
)
{
m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link
}
else if (compound->definitionType()==Definition::TypeMember &&
((MemberDef*)compound)->isObjCMethod())
{
// Objective C Method
MemberDef *member = (MemberDef*)compound;
bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
m_text = member->objCMethodName(localLink,g_inSeeBlock);
}
m_file = compound->getOutputFileBase();
m_ref = compound->getReference();
return;
}
else if (compound->definitionType()==Definition::TypeFile &&
((FileDef*)compound)->generateSourceFile()
) // undocumented file that has source code we can link to
{
m_file = compound->getSourceFileBase();
m_ref = compound->getReference();
return;
}
}
m_text = linkToText(target,FALSE);
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unable to resolve reference to `%s' for \\ref command",
target.data());
setDefinition(compound);
}
static void flattenParagraphs(QList<DocNode> &children)
{
QListIterator<DocNode> li(children);
QList<DocNode> newChildren;
DocNode *dn;
for (li.toFirst();(dn=li.current());++li)
{
if (dn->kind()==DocNode::Kind_Para)
{
DocPara *para = (DocPara*)dn;
QList<DocNode> ¶Children = para->children();
paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node
QListIterator<DocNode> li2(paraChildren);
DocNode *dn2;
for (li2.toFirst();(dn2=li2.current());++li2)
{
newChildren.append(dn2); // add them to new node
}
}
}
children.clear();
QListIterator<DocNode> li3(newChildren);
for (li3.toFirst();(dn=li3.current());++li3)
{
children.append(dn);
}
}
void DocRef::parse()
{
g_nodeStack.push(this);
DBG(("DocRef::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\ref",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
case TK_HTMLTAG:
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
if (m_children.isEmpty() && !m_text.isEmpty())
{
g_insideHtmlLink=TRUE;
docParserPushContext();
internalValidatingParseDoc(this,m_children,m_text);
docParserPopContext();
g_insideHtmlLink=FALSE;
flattenParagraphs(m_children);
}
handlePendingStyleCommands(this,m_children);
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
}
//---------------------------------------------------------------------------
DocLink::DocLink(DocNode *parent,const QString &target) :
m_parent(parent)
{
Definition *compound = 0;
//PageInfo *page;
QCString anchor;
m_refText = target;
m_relPath = g_relPath;
if (!m_refText.isEmpty() && m_refText.at(0)=='#')
{
m_refText = m_refText.right(m_refText.length()-1);
}
if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock,
&compound,anchor))
{
m_anchor = anchor;
if (compound && compound->isLinkable())
{
m_file = compound->getOutputFileBase();
m_ref = compound->getReference();
}
else if (compound->definitionType()==Definition::TypeFile &&
((FileDef*)compound)->generateSourceFile()
) // undocumented file that has source code we can link to
{
m_file = compound->getSourceFileBase();
m_ref = compound->getReference();
}
setDefinition(compound);
return;
}
setDefinition(compound);
// bogus link target
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unable to resolve link to `%s' for \\link command",
target.data());
}
QString DocLink::parse(bool isJavaLink,bool isXmlLink)
{
QString result;
g_nodeStack.push(this);
DBG(("DocLink::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children,FALSE))
{
switch (tok)
{
case TK_COMMAND:
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_ENDLINK:
if (isJavaLink)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: {@link.. ended with @endlink command");
}
goto endlink;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\link",
g_token->name.data());
break;
}
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
case TK_HTMLTAG:
if (g_token->name!="see" || !isXmlLink)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected xml/html command %s found",
g_token->name.data());
}
goto endlink;
case TK_LNKWORD:
case TK_WORD:
if (isJavaLink) // special case to detect closing }
{
QString w = g_token->name;
int p;
if (w=="}")
{
goto endlink;
}
else if ((p=w.find('}'))!=-1)
{
uint l=w.length();
m_children.append(new DocWord(this,w.left(p)));
if ((uint)p<l-1) // something left after the } (for instance a .)
{
result=w.right(l-p-1);
}
goto endlink;
}
}
m_children.append(new DocWord(this,g_token->name));
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
" link command\n");
}
endlink:
if (m_children.isEmpty()) // no link text
{
m_children.append(new DocWord(this,m_refText));
}
handlePendingStyleCommands(this,m_children);
DBG(("DocLink::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return result;
}
//---------------------------------------------------------------------------
DocDotFile::DocDotFile(DocNode *parent,const QString &name,const QString &context) :
m_parent(parent), m_name(name), m_relPath(g_relPath), m_context(context)
{
}
void DocDotFile::parse()
{
g_nodeStack.push(this);
DBG(("DocDotFile::parse() start\n"));
doctokenizerYYsetStateTitle();
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\dotfile",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
tok=doctokenizerYYlex();
while (tok==TK_WORD) // there are values following the title
{
if (g_token->name=="width")
{
m_width=g_token->chars;
}
else if (g_token->name=="height")
{
m_height=g_token->chars;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unknown option %s after image title",
g_token->name.data());
}
tok=doctokenizerYYlex();
}
ASSERT(tok==0);
doctokenizerYYsetStatePara();
handlePendingStyleCommands(this,m_children);
bool ambig;
FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig);
if (fd)
{
m_file = fd->absFilePath();
}
else if (ambig)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included dot file name %s is ambigious.\n"
"Possible candidates:\n%s",m_name.data(),
showFileDefMatches(Doxygen::exampleNameDict,m_name).data()
);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included dot file %s is not found "
"in any of the paths specified via DOTFILE_DIRS!",m_name.data());
}
DBG(("DocDotFile::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
}
//---------------------------------------------------------------------------
DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QString &name,Type t) :
m_parent(parent), m_attribs(attribs), m_name(name),
m_type(t), m_relPath(g_relPath)
{
}
void DocImage::parse()
{
g_nodeStack.push(this);
DBG(("DocImage::parse() start\n"));
// parse title
doctokenizerYYsetStateTitle();
int tok;
while ((tok=doctokenizerYYlex()))
{
if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height="))
{
// special case: no title, but we do have a size indicator
doctokenizerYYsetStateTitleAttrValue();
// strip =
g_token->name=g_token->name.left(g_token->name.length()-1);
break;
}
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\image",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
// parse size attributes
tok=doctokenizerYYlex();
while (tok==TK_WORD) // there are values following the title
{
if (g_token->name=="width")
{
m_width=g_token->chars;
}
else if (g_token->name=="height")
{
m_height=g_token->chars;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unknown option %s after image title",
g_token->name.data());
}
tok=doctokenizerYYlex();
}
doctokenizerYYsetStatePara();
handlePendingStyleCommands(this,m_children);
DBG(("DocImage::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
}
//---------------------------------------------------------------------------
int DocHtmlHeader::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlHeader::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <h%d> tag",
g_token->name.data(),m_level);
break;
case TK_HTMLTAG:
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
{
if (m_level!=1)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h1>",
m_level);
}
goto endheader;
}
else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag
{
if (m_level!=2)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h2>",
m_level);
}
goto endheader;
}
else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag
{
if (m_level!=3)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h3>",
m_level);
}
goto endheader;
}
else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag
{
if (m_level!=4)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h4>",
m_level);
}
goto endheader;
}
else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag
{
if (m_level!=5)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h5>",
m_level);
}
goto endheader;
}
else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag
{
if (m_level!=6)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h6>",
m_level);
}
goto endheader;
}
else if (tagId==HTML_A)
{
if (!g_token->endTag)
{
handleAHref(this,m_children,g_token->attribs);
}
}
else if (tagId==HTML_BR)
{
DocLineBreak *lb = new DocLineBreak(this);
m_children.append(lb);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <h%d> context",
g_token->endTag?"/":"",g_token->name.data(),m_level);
}
}
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
" <h%d> tag\n",m_level);
}
endheader:
handlePendingStyleCommands(this,m_children);
DBG(("DocHtmlHeader::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHRef::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHRef::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <a>..</a> block",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
case TK_HTMLTAG:
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_A && g_token->endTag) // found </a> tag
{
goto endhref;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <a href=...> context",
g_token->endTag?"/":"",g_token->name.data(),doctokenizerYYlineno);
}
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok),doctokenizerYYlineno);
break;
}
}
}
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
" <a href=...> tag",doctokenizerYYlineno);
}
endhref:
handlePendingStyleCommands(this,m_children);
DBG(("DocHRef::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocInternal::parse(int level)
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocInternal::parse() start\n"));
// first parse any number of paragraphs
bool isFirst=TRUE;
DocPara *lastPar=0;
do
{
DocPara *par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
retval=par->parse();
if (!par->isEmpty())
{
m_children.append(par);
lastPar=par;
}
else
{
delete par;
}
if (retval==TK_LISTITEM)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid list item found",doctokenizerYYlineno);
}
} while (retval!=0 &&
retval!=RetVal_Section &&
retval!=RetVal_Subsection &&
retval!=RetVal_Subsubsection &&
retval!=RetVal_Paragraph
);
if (lastPar) lastPar->markLast();
// then parse any number of level-n sections
while ((level==1 && retval==RetVal_Section) ||
(level==2 && retval==RetVal_Subsection) ||
(level==3 && retval==RetVal_Subsubsection) ||
(level==4 && retval==RetVal_Paragraph)
)
{
DocSection *s=new DocSection(this,
QMIN(level+Doxygen::subpageNestingLevel,5),g_token->sectionId);
m_children.append(s);
retval = s->parse();
}
if (retval==RetVal_Internal)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: \\internal command found inside internal section");
}
DBG(("DocInternal::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocIndexEntry::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocIndexEntry::parse() start\n"));
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after \\addindex command");
goto endindexentry;
}
doctokenizerYYsetStateTitle();
m_entry="";
while ((tok=doctokenizerYYlex()))
{
switch (tok)
{
case TK_WHITESPACE:
m_entry+=" ";
break;
case TK_WORD:
case TK_LNKWORD:
m_entry+=g_token->name;
break;
case TK_SYMBOL:
{
char letter='\0';
DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
switch (s)
{
case DocSymbol::BSlash: m_entry+='\\'; break;
case DocSymbol::At: m_entry+='@'; break;
case DocSymbol::Less: m_entry+='<'; break;
case DocSymbol::Greater: m_entry+='>'; break;
case DocSymbol::Amp: m_entry+='&'; break;
case DocSymbol::Dollar: m_entry+='$'; break;
case DocSymbol::Hash: m_entry+='#'; break;
case DocSymbol::Percent: m_entry+='%'; break;
case DocSymbol::Apos: m_entry+='\''; break;
case DocSymbol::Quot: m_entry+='"'; break;
case DocSymbol::Lsquo: m_entry+='`'; break;
case DocSymbol::Rsquo: m_entry+='\''; break;
case DocSymbol::Ldquo: m_entry+="``"; break;
case DocSymbol::Rdquo: m_entry+="''"; break;
case DocSymbol::Ndash: m_entry+="--"; break;
case DocSymbol::Mdash: m_entry+="---"; break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected symbol found as argument of \\addindex");
break;
}
}
break;
case TK_COMMAND:
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_BSLASH: m_entry+='\\'; break;
case CMD_AT: m_entry+='@'; break;
case CMD_LESS: m_entry+='<'; break;
case CMD_GREATER: m_entry+='>'; break;
case CMD_AMP: m_entry+='&'; break;
case CMD_DOLLAR: m_entry+='$'; break;
case CMD_HASH: m_entry+='#'; break;
case CMD_PERCENT: m_entry+='%'; break;
case CMD_QUOTE: m_entry+='"'; break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected command %s found as argument of \\addindex",
g_token->name.data());
break;
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
if (tok!=0) retval=tok;
doctokenizerYYsetStatePara();
m_entry = m_entry.stripWhiteSpace();
endindexentry:
DBG(("DocIndexEntry::parse() end retval=%x\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlCaption::parse()
{
int retval=0;
g_nodeStack.push(this);
DBG(("DocHtmlCaption::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <caption> tag",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
case TK_HTMLTAG:
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
{
retval = RetVal_OK;
goto endcaption;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <caption> context",
g_token->endTag?"/":"",g_token->name.data());
}
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
" <caption> tag",doctokenizerYYlineno);
}
endcaption:
handlePendingStyleCommands(this,m_children);
DBG(("DocHtmlCaption::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlCell::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlCell::parse() start\n"));
// parse one or more paragraphs
bool isFirst=TRUE;
DocPara *par=0;
do
{
par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
m_children.append(par);
retval=par->parse();
if (retval==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
{
retval=TK_NEWPARA; // ignore the tag
}
else if (tagId==HTML_TH && g_token->endTag) // found </th> tag
{
retval=TK_NEWPARA; // ignore the tag
}
}
}
while (retval==TK_NEWPARA);
if (par) par->markLast();
DBG(("DocHtmlCell::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
int DocHtmlCell::parseXml()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlCell::parseXml() start\n"));
// parse one or more paragraphs
bool isFirst=TRUE;
DocPara *par=0;
do
{
par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
m_children.append(par);
retval=par->parse();
if (retval==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==XML_ITEM && g_token->endTag) // found </item> tag
{
retval=TK_NEWPARA; // ignore the tag
}
else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag
{
retval=TK_NEWPARA; // ignore the tag
}
}
}
while (retval==TK_NEWPARA);
if (par) par->markLast();
DBG(("DocHtmlCell::parseXml() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlRow::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlRow::parse() start\n"));
bool isHeading=FALSE;
bool isFirst=TRUE;
DocHtmlCell *cell=0;
// get next token
int tok=doctokenizerYYlex();
// skip whitespace
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
{
}
else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag
{
isHeading=TRUE;
}
else // found some other tag
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <td> or <th> tag but "
"found <%s> instead!",g_token->name.data());
doctokenizerYYpushBackHtmlTag(g_token->name);
goto endrow;
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a html description title");
goto endrow;
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <td> or <th> tag but found %s token instead!",
tokToString(tok));
goto endrow;
}
// parse one or more cells
do
{
cell=new DocHtmlCell(this,g_token->attribs,isHeading);
cell->markFirst(isFirst);
isFirst=FALSE;
m_children.append(cell);
retval=cell->parse();
isHeading = retval==RetVal_TableHCell;
}
while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
if (cell) cell->markLast(TRUE);
endrow:
DBG(("DocHtmlRow::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
int DocHtmlRow::parseXml(bool isHeading)
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlRow::parseXml() start\n"));
bool isFirst=TRUE;
DocHtmlCell *cell=0;
// get next token
int tok=doctokenizerYYlex();
// skip whitespace
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==XML_TERM && !g_token->endTag) // found <term> tag
{
}
else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag
{
}
else // found some other tag
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <term> or <description> tag but "
"found <%s> instead!",g_token->name.data());
doctokenizerYYpushBackHtmlTag(g_token->name);
goto endrow;
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a html description title");
goto endrow;
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <td> or <th> tag but found %s token instead!",
tokToString(tok));
goto endrow;
}
do
{
cell=new DocHtmlCell(this,g_token->attribs,isHeading);
cell->markFirst(isFirst);
isFirst=FALSE;
m_children.append(cell);
retval=cell->parseXml();
}
while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
if (cell) cell->markLast(TRUE);
endrow:
DBG(("DocHtmlRow::parseXml() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlTable::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlTable::parse() start\n"));
getrow:
// get next token
int tok=doctokenizerYYlex();
// skip whitespace
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
{
// no caption, just rows
retval=RetVal_TableRow;
}
else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag
{
if (m_caption)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: table already has a caption, found another one");
}
else
{
m_caption = new DocHtmlCaption(this,g_token->attribs);
retval=m_caption->parse();
if (retval==RetVal_OK) // caption was parsed ok
{
goto getrow;
}
}
}
else // found wrong token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <tr> or <caption> tag but "
"found <%s%s> instead!", g_token->endTag ? "/" : "", g_token->name.data());
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a <tr> or <caption> tag");
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <tr> tag but found %s token instead!",
tokToString(tok));
}
// parse one or more rows
while (retval==RetVal_TableRow)
{
DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
m_children.append(tr);
retval=tr->parse();
}
DBG(("DocHtmlTable::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval==RetVal_EndTable ? RetVal_OK : retval;
}
int DocHtmlTable::parseXml()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlTable::parseXml() start\n"));
// get next token
int tok=doctokenizerYYlex();
// skip whitespace
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
int tagId=0;
bool isHeader=FALSE;
if (tok==TK_HTMLTAG)
{
tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
{
retval=RetVal_TableRow;
}
if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag
{
retval=RetVal_TableRow;
isHeader=TRUE;
}
}
// parse one or more rows
while (retval==RetVal_TableRow)
{
DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
m_children.append(tr);
retval=tr->parseXml(isHeader);
isHeader=FALSE;
}
DBG(("DocHtmlTable::parseXml() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval==RetVal_EndTable ? RetVal_OK : retval;
}
uint DocHtmlTable::numCols() const
{
uint cols=0;
QListIterator<DocNode> cli(m_children);
DocNode *n;
for (cli.toFirst();(n=cli.current());++cli)
{
ASSERT(n->kind()==DocNode::Kind_HtmlRow);
cols=QMAX(cols,((DocHtmlRow *)n)->numCells());
}
return cols;
}
void DocHtmlTable::accept(DocVisitor *v)
{
v->visitPre(this);
// for HTML output we put the caption first
if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v);
QListIterator<DocNode> cli(m_children);
DocNode *n;
for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
// for other output formats we put the caption last
if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v);
v->visitPost(this);
}
//---------------------------------------------------------------------------
int DocHtmlDescTitle::parse()
{
int retval=0;
g_nodeStack.push(this);
DBG(("DocHtmlDescTitle::parse() start\n"));
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
{
QString cmdName=g_token->name;
bool isJavaLink=FALSE;
switch (Mappers::cmdMapper->map(cmdName))
{
case CMD_REF:
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
g_token->name.data());
}
else
{
doctokenizerYYsetStateRef();
tok=doctokenizerYYlex(); // get the reference id
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
}
else
{
DocRef *ref = new DocRef(this,g_token->name,g_context);
m_children.append(ref);
ref->parse();
}
doctokenizerYYsetStatePara();
}
}
break;
case CMD_JAVALINK:
isJavaLink=TRUE;
// fall through
case CMD_LINK:
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
}
else
{
doctokenizerYYsetStateLink();
tok=doctokenizerYYlex();
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
}
else
{
doctokenizerYYsetStatePara();
DocLink *lnk = new DocLink(this,g_token->name);
m_children.append(lnk);
QString leftOver = lnk->parse(isJavaLink);
if (!leftOver.isEmpty())
{
m_children.append(new DocWord(this,leftOver));
}
}
}
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <dt> tag",
g_token->name.data());
}
}
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
case TK_HTMLTAG:
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
{
retval = RetVal_DescData;
goto endtitle;
}
else if (tagId==HTML_DT && g_token->endTag)
{
// ignore </dt> tag.
}
else if (tagId==HTML_DT)
{
// missing <dt> tag.
retval = RetVal_DescTitle;
goto endtitle;
}
else if (tagId==HTML_DL && g_token->endTag)
{
retval=RetVal_EndDesc;
goto endtitle;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <dt> context",
g_token->endTag?"/":"",g_token->name.data());
}
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
" <dt> tag");
}
endtitle:
handlePendingStyleCommands(this,m_children);
DBG(("DocHtmlDescTitle::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlDescData::parse()
{
m_attribs = g_token->attribs;
int retval=0;
g_nodeStack.push(this);
DBG(("DocHtmlDescData::parse() start\n"));
bool isFirst=TRUE;
DocPara *par=0;
do
{
par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
m_children.append(par);
retval=par->parse();
}
while (retval==TK_NEWPARA);
if (par) par->markLast();
DBG(("DocHtmlDescData::parse() end\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlDescList::parse()
{
int retval=RetVal_OK;
g_nodeStack.push(this);
DBG(("DocHtmlDescList::parse() start\n"));
// get next token
int tok=doctokenizerYYlex();
// skip whitespace
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
{
// continue
}
else // found some other tag
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <dt> tag but "
"found <%s> instead!",g_token->name.data());
doctokenizerYYpushBackHtmlTag(g_token->name);
goto enddesclist;
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a html description title");
goto enddesclist;
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <dt> tag but found %s token instead!",
tokToString(tok));
goto enddesclist;
}
do
{
DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs);
m_children.append(dt);
DocHtmlDescData *dd=new DocHtmlDescData(this);
m_children.append(dd);
retval=dt->parse();
if (retval==RetVal_DescData)
{
retval=dd->parse();
}
else if (retval!=RetVal_DescTitle)
{
// error
break;
}
} while (retval==RetVal_DescTitle);
if (retval==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <dl> block");
}
enddesclist:
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocHtmlDescList::parse() end\n"));
return retval==RetVal_EndDesc ? RetVal_OK : retval;
}
//---------------------------------------------------------------------------
int DocHtmlListItem::parse()
{
DBG(("DocHtmlListItem::parse() start\n"));
int retval=0;
g_nodeStack.push(this);
// parse one or more paragraphs
bool isFirst=TRUE;
DocPara *par=0;
do
{
par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
m_children.append(par);
retval=par->parse();
}
while (retval==TK_NEWPARA);
if (par) par->markLast();
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocHtmlListItem::parse() end retval=%x\n",retval));
return retval;
}
int DocHtmlListItem::parseXml()
{
DBG(("DocHtmlListItem::parseXml() start\n"));
int retval=0;
g_nodeStack.push(this);
// parse one or more paragraphs
bool isFirst=TRUE;
DocPara *par=0;
do
{
par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
m_children.append(par);
retval=par->parse();
if (retval==0) break;
//printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
// retval,g_token->name.data(),g_token->endTag);
if (retval==RetVal_ListItem)
{
break;
}
}
while (retval!=RetVal_CloseXml);
if (par) par->markLast();
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
return retval;
}
//---------------------------------------------------------------------------
int DocHtmlList::parse()
{
DBG(("DocHtmlList::parse() start\n"));
int retval=RetVal_OK;
int num=1;
g_nodeStack.push(this);
// get next token
int tok=doctokenizerYYlex();
// skip whitespace and paragraph breaks
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
{
// ok, we can go on.
}
else // found some other tag
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <li> tag but "
"found <%s> instead!",g_token->name.data());
doctokenizerYYpushBackHtmlTag(g_token->name);
goto endlist;
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a html list item");
goto endlist;
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <li> tag but found %s token instead!",
tokToString(tok));
goto endlist;
}
do
{
DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
m_children.append(li);
retval=li->parse();
} while (retval==RetVal_ListItem);
if (retval==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <%cl> block",
m_type==Unordered ? 'u' : 'o');
}
endlist:
DBG(("DocHtmlList::parse() end retval=%x\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval==RetVal_EndList ? RetVal_OK : retval;
}
int DocHtmlList::parseXml()
{
DBG(("DocHtmlList::parseXml() start\n"));
int retval=RetVal_OK;
int num=1;
g_nodeStack.push(this);
// get next token
int tok=doctokenizerYYlex();
// skip whitespace and paragraph breaks
while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
// should find a html tag now
if (tok==TK_HTMLTAG)
{
int tagId=Mappers::htmlTagMapper->map(g_token->name);
//printf("g_token->name=%s g_token->endTag=%d\n",g_token->name.data(),g_token->endTag);
if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
{
// ok, we can go on.
}
else // found some other tag
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <item> tag but "
"found <%s> instead!",g_token->name.data());
doctokenizerYYpushBackHtmlTag(g_token->name);
goto endlist;
}
}
else if (tok==0) // premature end of comment
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
" for a html list item");
goto endlist;
}
else // token other than html token
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <item> tag but found %s token instead!",
tokToString(tok));
goto endlist;
}
do
{
DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
m_children.append(li);
retval=li->parseXml();
if (retval==0) break;
//printf("retval=%x g_token->name=%s\n",retval,g_token->name.data());
} while (retval==RetVal_ListItem);
if (retval==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <list type=\"%s\"> block",
m_type==Unordered ? "bullet" : "number");
}
endlist:
DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval==RetVal_EndList ||
(retval==RetVal_CloseXml || g_token->name=="list") ?
RetVal_OK : retval;
}
//---------------------------------------------------------------------------
int DocSimpleListItem::parse()
{
g_nodeStack.push(this);
int rv=m_paragraph->parse();
m_paragraph->markFirst();
m_paragraph->markLast();
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return rv;
}
//--------------------------------------------------------------------------
int DocSimpleList::parse()
{
g_nodeStack.push(this);
int rv;
do
{
DocSimpleListItem *li=new DocSimpleListItem(this);
m_children.append(li);
rv=li->parse();
} while (rv==RetVal_ListItem);
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
}
//--------------------------------------------------------------------------
int DocAutoListItem::parse()
{
int retval = RetVal_OK;
g_nodeStack.push(this);
retval=m_paragraph->parse();
m_paragraph->markFirst();
m_paragraph->markLast();
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//--------------------------------------------------------------------------
int DocAutoList::parse()
{
int retval = RetVal_OK;
int num=1;
g_nodeStack.push(this);
// first item or sub list => create new list
do
{
DocAutoListItem *li = new DocAutoListItem(this,num++);
m_children.append(li);
retval=li->parse();
}
while (retval==TK_LISTITEM && // new list item
m_indent==g_token->indent && // at same indent level
m_isEnumList==g_token->isEnumList // of the same kind
);
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//--------------------------------------------------------------------------
void DocTitle::parse()
{
DBG(("DocTitle::parse() start\n"));
g_nodeStack.push(this);
doctokenizerYYsetStateTitle();
int tok;
while ((tok=doctokenizerYYlex()))
{
if (!defaultHandleToken(this,tok,m_children))
{
switch (tok)
{
case TK_COMMAND:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a title section",
g_token->name.data());
break;
case TK_SYMBOL:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
}
doctokenizerYYsetStatePara();
handlePendingStyleCommands(this,m_children);
DBG(("DocTitle::parse() end\n"));
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
}
void DocTitle::parseFromString(const QString &text)
{
m_children.append(new DocWord(this,text));
}
//--------------------------------------------------------------------------
DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) :
m_parent(parent), m_type(t)
{
m_title=0;
}
DocSimpleSect::~DocSimpleSect()
{
delete m_title;
}
void DocSimpleSect::accept(DocVisitor *v)
{
v->visitPre(this);
if (m_title) m_title->accept(v);
QListIterator<DocNode> cli(m_children);
DocNode *n;
for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
v->visitPost(this);
}
int DocSimpleSect::parse(bool userTitle,bool needsSeparator)
{
DBG(("DocSimpleSect::parse() start\n"));
g_nodeStack.push(this);
// handle case for user defined title
if (userTitle)
{
m_title = new DocTitle(this);
m_title->parse();
}
// add new paragraph as child
DocPara *par = new DocPara(this);
if (m_children.isEmpty())
{
par->markFirst();
}
else
{
ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
((DocPara *)m_children.last())->markLast(FALSE);
}
par->markLast();
if (needsSeparator) m_children.append(new DocSimpleSectSep(this));
m_children.append(par);
// parse the contents of the paragraph
int retval = par->parse();
DBG(("DocSimpleSect::parse() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec
}
int DocSimpleSect::parseRcs()
{
DBG(("DocSimpleSect::parseRcs() start\n"));
g_nodeStack.push(this);
m_title = new DocTitle(this);
m_title->parseFromString(g_token->name);
QString text = g_token->text;
docParserPushContext(); // this will create a new g_token
internalValidatingParseDoc(this,m_children,text);
docParserPopContext(); // this will restore the old g_token
DBG(("DocSimpleSect::parseRcs()\n"));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return RetVal_OK;
}
int DocSimpleSect::parseXml()
{
DBG(("DocSimpleSect::parse() start\n"));
g_nodeStack.push(this);
int retval = RetVal_OK;
for (;;)
{
// add new paragraph as child
DocPara *par = new DocPara(this);
if (m_children.isEmpty())
{
par->markFirst();
}
else
{
ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
((DocPara *)m_children.last())->markLast(FALSE);
}
par->markLast();
m_children.append(par);
// parse the contents of the paragraph
retval = par->parse();
if (retval == 0) break;
if (retval == RetVal_CloseXml)
{
retval = RetVal_OK;
break;
}
}
DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
void DocSimpleSect::appendLinkWord(const QString &word)
{
DocPara *p;
if (m_children.isEmpty() || m_children.last()->kind()!=DocNode::Kind_Para)
{
p = new DocPara(this);
m_children.append(p);
}
else
{
p = (DocPara *)m_children.last();
// Comma-seperate <seealso> links.
p->injectToken(TK_WORD,",");
p->injectToken(TK_WHITESPACE," ");
}
g_inSeeBlock=TRUE;
p->injectToken(TK_LNKWORD,word);
g_inSeeBlock=FALSE;
}
QCString DocSimpleSect::typeString() const
{
switch (m_type)
{
case Unknown: break;
case See: return "see";
case Return: return "return";
case Author: // fall through
case Authors: return "author";
case Version: return "version";
case Since: return "since";
case Date: return "date";
case Note: return "note";
case Warning: return "warning";
case Pre: return "pre";
case Post: return "post";
case Invar: return "invariant";
case Remark: return "remark";
case Attention: return "attention";
case User: return "user";
case Rcs: return "rcs";
}
return "unknown";
}
//--------------------------------------------------------------------------
int DocParamList::parse(const QString &cmdName)
{
int retval=RetVal_OK;
DBG(("DocParamList::parse() start\n"));
g_nodeStack.push(this);
DocPara *par=0;
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
}
doctokenizerYYsetStateParam();
tok=doctokenizerYYlex();
while (tok==TK_WORD) /* there is a parameter name */
{
if (m_type==DocParamSect::Param)
{
g_hasParamCommand=TRUE;
checkArgumentName(g_token->name,TRUE);
}
else if (m_type==DocParamSect::RetVal)
{
g_hasReturnCommand=TRUE;
checkArgumentName(g_token->name,FALSE);
}
//m_params.append(g_token->name);
handleLinkedWord(this,m_params);
tok=doctokenizerYYlex();
}
doctokenizerYYsetStatePara();
if (tok==0) /* premature end of comment block */
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s",cmdName.data());
retval=0;
goto endparamlist;
}
ASSERT(tok==TK_WHITESPACE);
par = new DocPara(this);
m_paragraphs.append(par);
retval = par->parse();
par->markFirst();
par->markLast();
endparamlist:
DBG(("DocParamList::parse() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
int DocParamList::parseXml(const QString ¶mName)
{
int retval=RetVal_OK;
DBG(("DocParamList::parseXml() start\n"));
g_nodeStack.push(this);
g_token->name = paramName;
if (m_type==DocParamSect::Param)
{
g_hasParamCommand=TRUE;
checkArgumentName(g_token->name,TRUE);
}
else if (m_type==DocParamSect::RetVal)
{
g_hasReturnCommand=TRUE;
checkArgumentName(g_token->name,FALSE);
}
handleLinkedWord(this,m_params);
do
{
DocPara *par = new DocPara(this);
retval = par->parse();
if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
// after </para> and before </param>
{
delete par;
break;
}
else // append the paragraph to the list
{
if (m_paragraphs.isEmpty())
{
par->markFirst();
}
else
{
m_paragraphs.last()->markLast(FALSE);
}
par->markLast();
m_paragraphs.append(par);
}
if (retval == 0) break;
} while (retval==RetVal_CloseXml &&
Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM &&
Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
if (retval==0) /* premature end of comment block */
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unterminated param or exception tag");
}
else
{
retval=RetVal_OK;
}
DBG(("DocParamList::parse() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//--------------------------------------------------------------------------
int DocParamSect::parse(const QString &cmdName,bool xmlContext, Direction d)
{
int retval=RetVal_OK;
DBG(("DocParamSect::parse() start\n"));
g_nodeStack.push(this);
DocParamList *pl = new DocParamList(this,m_type,d);
if (m_children.isEmpty())
{
pl->markFirst();
pl->markLast();
}
else
{
ASSERT(m_children.last()->kind()==DocNode::Kind_ParamList);
((DocParamList *)m_children.last())->markLast(FALSE);
pl->markLast();
}
m_children.append(pl);
if (xmlContext)
{
retval = pl->parseXml(cmdName);
}
else
{
retval = pl->parse(cmdName);
}
DBG(("DocParamSect::parse() end retval=%d\n",retval));
DocNode *n=g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//--------------------------------------------------------------------------
int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
{
DocSimpleSect *ss=0;
bool needsSeparator = FALSE;
if (!m_children.isEmpty() && // previous element
m_children.last()->kind()==Kind_SimpleSect && // was a simple sect
((DocSimpleSect *)m_children.last())->type()==t && // of same type
t!=DocSimpleSect::User) // but not user defined
{
// append to previous section
ss=(DocSimpleSect *)m_children.last();
needsSeparator = TRUE;
}
else // start new section
{
ss=new DocSimpleSect(this,t);
m_children.append(ss);
}
int rv = RetVal_OK;
if (xmlContext)
{
return ss->parseXml();
}
else
{
rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
}
return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
}
int DocPara::handleParamSection(const QString &cmdName,
DocParamSect::Type t,
bool xmlContext=FALSE,
int direction=DocParamSect::Unspecified)
{
DocParamSect *ps=0;
if (!m_children.isEmpty() && // previous element
m_children.last()->kind()==Kind_ParamSect && // was a param sect
((DocParamSect *)m_children.last())->type()==t) // of same type
{
// append to previous section
ps=(DocParamSect *)m_children.last();
}
else // start new section
{
ps=new DocParamSect(this,t);
m_children.append(ps);
}
int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
}
int DocPara::handleXRefItem()
{
int retval=doctokenizerYYlex();
ASSERT(retval==TK_WHITESPACE);
doctokenizerYYsetStateXRefItem();
retval=doctokenizerYYlex();
if (retval==RetVal_OK)
{
DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name);
if (ref->parse())
{
m_children.append(ref);
}
else
{
delete ref;
}
}
doctokenizerYYsetStatePara();
return retval;
}
void DocPara::handleIncludeOperator(const QString &cmdName,DocIncOperator::Type t)
{
DBG(("handleIncludeOperator(%s)\n",cmdName.data()));
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
doctokenizerYYsetStatePattern();
tok=doctokenizerYYlex();
doctokenizerYYsetStatePara();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s", cmdName.data());
return;
}
else if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
DocNode *n1 = m_children.last();
DocNode *n2 = n1!=0 ? m_children.prev() : 0;
bool isFirst = n1==0 || // no last node
(n1->kind()!=DocNode::Kind_IncOperator &&
n1->kind()!=DocNode::Kind_WhiteSpace
) || // last node is not operator or whitespace
(n1->kind()==DocNode::Kind_WhiteSpace &&
n2!=0 && n2->kind()!=DocNode::Kind_IncOperator
); // previous not is not operator
op->markFirst(isFirst);
op->markLast(TRUE);
if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator)
{
((DocIncOperator *)n1)->markLast(FALSE);
}
else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace &&
n2!=0 && n2->kind()==DocNode::Kind_IncOperator
)
{
((DocIncOperator *)n2)->markLast(FALSE);
}
m_children.append(op);
op->parse();
}
void DocPara::handleImage(const QString &cmdName)
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
tok=doctokenizerYYlex();
if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
DocImage::Type t;
QString imgType = g_token->name.lower();
if (imgType=="html") t=DocImage::Html;
else if (imgType=="latex") t=DocImage::Latex;
else if (imgType=="rtf") t=DocImage::Rtf;
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: image type %s specified as the first argument of "
"%s is not valid",
imgType.data(),cmdName.data());
return;
}
doctokenizerYYsetStateFile();
tok=doctokenizerYYlex();
doctokenizerYYsetStatePara();
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
HtmlAttribList attrList;
DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t);
m_children.append(img);
img->parse();
}
void DocPara::handleDotFile(const QString &cmdName)
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
doctokenizerYYsetStateFile();
tok=doctokenizerYYlex();
doctokenizerYYsetStatePara();
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
QString name = g_token->name;
DocDotFile *df = new DocDotFile(this,name,g_context);
m_children.append(df);
df->parse();
}
void DocPara::handleLink(const QString &cmdName,bool isJavaLink)
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
doctokenizerYYsetStateLink();
tok=doctokenizerYYlex();
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
doctokenizerYYsetStatePara();
DocLink *lnk = new DocLink(this,g_token->name);
m_children.append(lnk);
QString leftOver = lnk->parse(isJavaLink);
if (!leftOver.isEmpty())
{
m_children.append(new DocWord(this,leftOver));
}
}
void DocPara::handleRef(const QString &cmdName)
{
DBG(("handleRef(%s)\n",cmdName.data()));
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
doctokenizerYYsetStateRef();
tok=doctokenizerYYlex(); // get the reference id
DocRef *ref=0;
if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
goto endref;
}
ref = new DocRef(this,g_token->name,g_context);
m_children.append(ref);
ref->parse();
endref:
doctokenizerYYsetStatePara();
}
void DocPara::handleInclude(const QString &cmdName,DocInclude::Type t)
{
DBG(("handleInclude(%s)\n",cmdName.data()));
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
doctokenizerYYsetStateFile();
tok=doctokenizerYYlex();
doctokenizerYYsetStatePara();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s",cmdName.data());
return;
}
else if (tok!=TK_WORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
DocInclude *inc = new DocInclude(this,g_token->name,g_context,t,g_isExample,g_exampleName);
m_children.append(inc);
inc->parse();
}
void DocPara::handleSection(const QString &cmdName)
{
// get the argument of the section command.
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
return;
}
tok=doctokenizerYYlex();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s\n", cmdName.data());
return;
}
else if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
return;
}
g_token->sectionId = g_token->name;
doctokenizerYYsetStateSkipTitle();
doctokenizerYYlex();
doctokenizerYYsetStatePara();
}
int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
{
DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level);
m_children.append(header);
int retval = header->parse();
return (retval==RetVal_OK) ? TK_NEWPARA : retval;
}
// For XML tags whose content is stored in attributes rather than
// contained within the element, we need a way to inject the attribute
// text into the current paragraph.
bool DocPara::injectToken(int tok,const QString &tokText)
{
g_token->name = tokText;
return defaultHandleToken(this,tok,m_children);
}
int DocPara::handleStartCode()
{
int retval = doctokenizerYYlex();
// search for the first non-whitespace line, index is stored in li
int i=0,li=0,l=g_token->verb.length();
while (i<l && (g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n'))
{
if (g_token->verb.at(i)=='\n') li=i+1;
i++;
}
m_children.append(new DocVerbatim(this,g_context,g_token->verb.mid(li),DocVerbatim::Code,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: code section ended without end marker");
doctokenizerYYsetStatePara();
return retval;
}
void DocPara::handleInheritDoc()
{
if (g_memberDef) // inheriting docs from a member
{
MemberDef *reMd = g_memberDef->reimplements();
if (reMd) // member from which was inherited.
{
MemberDef *thisMd = g_memberDef;
//printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data());
docParserPushContext();
g_scope=reMd->getOuterScope();
g_context=g_scope->name();
g_memberDef=reMd;
g_styleStack.clear();
g_nodeStack.clear();
g_copyStack.append(reMd);
internalValidatingParseDoc(this,m_children,reMd->briefDescription());
internalValidatingParseDoc(this,m_children,reMd->documentation());
g_copyStack.remove(reMd);
docParserPopContext(TRUE);
g_memberDef = thisMd;
}
}
}
int DocPara::handleCommand(const QString &cmdName)
{
DBG(("handleCommand(%s)\n",cmdName.data()));
int retval = RetVal_OK;
int cmdId = Mappers::cmdMapper->map(cmdName);
switch (cmdId)
{
case CMD_UNKNOWN:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Found unknown command `\\%s'",cmdName.data());
break;
case CMD_EMPHASIS:
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
retval=handleStyleArgument(this,m_children,cmdName);
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
break;
case CMD_BOLD:
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
retval=handleStyleArgument(this,m_children,cmdName);
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
break;
case CMD_CODE:
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
retval=handleStyleArgument(this,m_children,cmdName);
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
break;
case CMD_BSLASH:
m_children.append(new DocSymbol(this,DocSymbol::BSlash));
break;
case CMD_AT:
m_children.append(new DocSymbol(this,DocSymbol::At));
break;
case CMD_LESS:
m_children.append(new DocSymbol(this,DocSymbol::Less));
break;
case CMD_GREATER:
m_children.append(new DocSymbol(this,DocSymbol::Greater));
break;
case CMD_AMP:
m_children.append(new DocSymbol(this,DocSymbol::Amp));
break;
case CMD_DOLLAR:
m_children.append(new DocSymbol(this,DocSymbol::Dollar));
break;
case CMD_HASH:
m_children.append(new DocSymbol(this,DocSymbol::Hash));
break;
case CMD_PERCENT:
m_children.append(new DocSymbol(this,DocSymbol::Percent));
break;
case CMD_QUOTE:
m_children.append(new DocSymbol(this,DocSymbol::Quot));
break;
case CMD_SA:
g_inSeeBlock=TRUE;
retval = handleSimpleSection(DocSimpleSect::See);
g_inSeeBlock=FALSE;
break;
case CMD_RETURN:
retval = handleSimpleSection(DocSimpleSect::Return);
g_hasReturnCommand=TRUE;
break;
case CMD_AUTHOR:
retval = handleSimpleSection(DocSimpleSect::Author);
break;
case CMD_AUTHORS:
retval = handleSimpleSection(DocSimpleSect::Authors);
break;
case CMD_VERSION:
retval = handleSimpleSection(DocSimpleSect::Version);
break;
case CMD_SINCE:
retval = handleSimpleSection(DocSimpleSect::Since);
break;
case CMD_DATE:
retval = handleSimpleSection(DocSimpleSect::Date);
break;
case CMD_NOTE:
retval = handleSimpleSection(DocSimpleSect::Note);
break;
case CMD_WARNING:
retval = handleSimpleSection(DocSimpleSect::Warning);
break;
case CMD_PRE:
retval = handleSimpleSection(DocSimpleSect::Pre);
break;
case CMD_POST:
retval = handleSimpleSection(DocSimpleSect::Post);
break;
case CMD_INVARIANT:
retval = handleSimpleSection(DocSimpleSect::Invar);
break;
case CMD_REMARK:
retval = handleSimpleSection(DocSimpleSect::Remark);
break;
case CMD_ATTENTION:
retval = handleSimpleSection(DocSimpleSect::Attention);
break;
case CMD_PAR:
retval = handleSimpleSection(DocSimpleSect::User);
break;
case CMD_LI:
{
DocSimpleList *sl=new DocSimpleList(this);
m_children.append(sl);
retval = sl->parse();
}
break;
case CMD_SECTION:
{
handleSection(cmdName);
retval = RetVal_Section;
}
break;
case CMD_SUBSECTION:
{
handleSection(cmdName);
retval = RetVal_Subsection;
}
break;
case CMD_SUBSUBSECTION:
{
handleSection(cmdName);
retval = RetVal_Subsubsection;
}
break;
case CMD_PARAGRAPH:
{
handleSection(cmdName);
retval = RetVal_Paragraph;
}
break;
case CMD_STARTCODE:
{
doctokenizerYYsetStateCode();
retval = handleStartCode();
}
break;
case CMD_HTMLONLY:
{
doctokenizerYYsetStateHtmlOnly();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: htmlonly section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_MANONLY:
{
doctokenizerYYsetStateManOnly();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: manonly section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_LATEXONLY:
{
doctokenizerYYsetStateLatexOnly();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: latexonly section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_XMLONLY:
{
doctokenizerYYsetStateXmlOnly();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: xmlonly section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_VERBATIM:
{
doctokenizerYYsetStateVerbatim();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: verbatim section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_DOT:
{
doctokenizerYYsetStateDot();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: dot section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_MSC:
{
doctokenizerYYsetStateMsc();
retval = doctokenizerYYlex();
m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName));
if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: msc section ended without end marker");
doctokenizerYYsetStatePara();
}
break;
case CMD_ENDCODE:
case CMD_ENDHTMLONLY:
case CMD_ENDMANONLY:
case CMD_ENDLATEXONLY:
case CMD_ENDXMLONLY:
case CMD_ENDLINK:
case CMD_ENDVERBATIM:
case CMD_ENDDOT:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
break;
case CMD_ENDMSC:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
break;
case CMD_PARAM:
retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
break;
case CMD_TPARAM:
retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir);
break;
case CMD_RETVAL:
retval = handleParamSection(cmdName,DocParamSect::RetVal);
break;
case CMD_EXCEPTION:
retval = handleParamSection(cmdName,DocParamSect::Exception);
break;
case CMD_XREFITEM:
retval = handleXRefItem();
break;
case CMD_LINEBREAK:
{
DocLineBreak *lb = new DocLineBreak(this);
m_children.append(lb);
}
break;
case CMD_ANCHOR:
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
break;
}
tok=doctokenizerYYlex();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s",cmdName.data());
break;
}
else if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
break;
}
DocAnchor *anchor = new DocAnchor(this,g_token->name,FALSE);
m_children.append(anchor);
}
break;
case CMD_ADDINDEX:
{
DocIndexEntry *ie = new DocIndexEntry(this,
g_scope!=Doxygen::globalScope?g_scope:0,
g_memberDef);
m_children.append(ie);
retval = ie->parse();
}
break;
case CMD_INTERNAL:
retval = RetVal_Internal;
break;
case CMD_COPYDOC: // fall through
case CMD_COPYBRIEF: // fall through
case CMD_COPYDETAILS:
{
int tok=doctokenizerYYlex();
if (tok!=TK_WHITESPACE)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
cmdName.data());
break;
}
tok=doctokenizerYYlex();
if (tok==0)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
"argument of command %s\n", cmdName.data());
break;
}
else if (tok!=TK_WORD && tok!=TK_LNKWORD)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
tokToString(tok),cmdName.data());
break;
}
DocCopy *cpy = new DocCopy(this,g_token->name,
cmdId==CMD_COPYDOC || cmdId==CMD_COPYBRIEF,
cmdId==CMD_COPYDOC || cmdId==CMD_COPYDETAILS);
m_children.append(cpy);
cpy->parse();
}
break;
case CMD_INCLUDE:
handleInclude(cmdName,DocInclude::Include);
break;
case CMD_INCWITHLINES:
handleInclude(cmdName,DocInclude::IncWithLines);
break;
case CMD_DONTINCLUDE:
handleInclude(cmdName,DocInclude::DontInclude);
break;
case CMD_HTMLINCLUDE:
handleInclude(cmdName,DocInclude::HtmlInclude);
break;
case CMD_VERBINCLUDE:
handleInclude(cmdName,DocInclude::VerbInclude);
break;
case CMD_SKIP:
handleIncludeOperator(cmdName,DocIncOperator::Skip);
break;
case CMD_UNTIL:
handleIncludeOperator(cmdName,DocIncOperator::Until);
break;
case CMD_SKIPLINE:
handleIncludeOperator(cmdName,DocIncOperator::SkipLine);
break;
case CMD_LINE:
handleIncludeOperator(cmdName,DocIncOperator::Line);
break;
case CMD_IMAGE:
handleImage(cmdName);
break;
case CMD_DOTFILE:
handleDotFile(cmdName);
break;
case CMD_LINK:
handleLink(cmdName,FALSE);
break;
case CMD_JAVALINK:
handleLink(cmdName,TRUE);
break;
case CMD_REF: // fall through
case CMD_SUBPAGE:
handleRef(cmdName);
break;
case CMD_SECREFLIST:
{
DocSecRefList *list = new DocSecRefList(this);
m_children.append(list);
list->parse();
}
break;
case CMD_SECREFITEM:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
break;
case CMD_ENDSECREFLIST:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
break;
case CMD_FORMULA:
{
DocFormula *form=new DocFormula(this,g_token->id);
m_children.append(form);
}
break;
//case CMD_LANGSWITCH:
// retval = handleLanguageSwitch();
// break;
case CMD_INTERNALREF:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
break;
case CMD_INHERITDOC:
handleInheritDoc();
break;
default:
// we should not get here!
ASSERT(0);
break;
}
INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec ||
retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA ||
retval==RetVal_Section || retval==RetVal_EndList ||
retval==RetVal_Internal || retval==RetVal_SwitchLang
);
DBG(("handleCommand(%s) end retval=%x\n",cmdName.data(),retval));
return retval;
}
static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
const char *attrName,
QString *result)
{
HtmlAttribListIterator li(tagHtmlAttribs);
HtmlAttrib *opt;
for (li.toFirst();(opt=li.current());++li)
{
if (opt->name==attrName)
{
*result = opt->value;
return TRUE;
}
}
return FALSE;
}
int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tagHtmlAttribs)
{
DBG(("handleHtmlStartTag(%s,%d)\n",tagName.data(),tagHtmlAttribs.count()));
int retval=RetVal_OK;
int tagId = Mappers::htmlTagMapper->map(tagName);
if (g_token->emptyTag && !(tagId&XML_CmdMask) &&
tagId!=HTML_UNKNOWN && tagId!=HTML_IMG && tagId!=HTML_BR)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: HTML tags may not use the 'empty tag' XHTML syntax.");
}
switch (tagId)
{
case HTML_UL:
{
DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered);
m_children.append(list);
retval=list->parse();
}
break;
case HTML_OL:
{
DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered);
m_children.append(list);
retval=list->parse();
}
break;
case HTML_LI:
if (!insideUL(this) && !insideOL(this))
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: lonely <li> tag found");
}
else
{
retval=RetVal_ListItem;
}
break;
case HTML_BOLD:
handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
break;
case HTML_CODE:
if (g_fileName.right(3)==".cs")
// for C# code we treat <code> as an XML tag
{
doctokenizerYYsetStateXmlCode();
retval = handleStartCode();
}
else // normal HTML markup
{
handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
}
break;
case HTML_EMPHASIS:
handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
break;
case HTML_DIV:
handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs);
break;
case HTML_SPAN:
handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs);
break;
case HTML_SUB:
handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs);
break;
case HTML_SUP:
handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs);
break;
case HTML_CENTER:
handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs);
break;
case HTML_SMALL:
handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs);
break;
case HTML_PRE:
handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
setInsidePreformatted(TRUE);
//doctokenizerYYsetInsidePre(TRUE);
break;
case HTML_P:
retval=TK_NEWPARA;
break;
case HTML_DL:
{
DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs);
m_children.append(list);
retval=list->parse();
}
break;
case HTML_DT:
retval = RetVal_DescTitle;
break;
case HTML_DD:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag <dd> found");
break;
case HTML_TABLE:
{
DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
m_children.append(table);
retval=table->parse();
}
break;
case HTML_TR:
retval = RetVal_TableRow;
break;
case HTML_TD:
retval = RetVal_TableCell;
break;
case HTML_TH:
retval = RetVal_TableHCell;
break;
case HTML_CAPTION:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag <caption> found");
break;
case HTML_BR:
{
DocLineBreak *lb = new DocLineBreak(this);
m_children.append(lb);
}
break;
case HTML_HR:
{
DocHorRuler *hr = new DocHorRuler(this);
m_children.append(hr);
}
break;
case HTML_A:
retval=handleAHref(this,m_children,tagHtmlAttribs);
break;
case HTML_H1:
retval=handleHtmlHeader(tagHtmlAttribs,1);
break;
case HTML_H2:
retval=handleHtmlHeader(tagHtmlAttribs,2);
break;
case HTML_H3:
retval=handleHtmlHeader(tagHtmlAttribs,3);
break;
case HTML_H4:
retval=handleHtmlHeader(tagHtmlAttribs,4);
break;
case HTML_H5:
retval=handleHtmlHeader(tagHtmlAttribs,5);
break;
case HTML_H6:
retval=handleHtmlHeader(tagHtmlAttribs,6);
break;
case HTML_IMG:
{
HtmlAttribListIterator li(tagHtmlAttribs);
HtmlAttrib *opt;
bool found=FALSE;
int index=0;
for (li.toFirst();(opt=li.current());++li,++index)
{
//printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
if (opt->name=="src" && !opt->value.isEmpty())
{
// copy attributes
HtmlAttribList attrList = tagHtmlAttribs;
// and remove the href attribute
bool result = attrList.remove(index);
ASSERT(result);
DocImage *img = new DocImage(this,attrList,opt->value,DocImage::Html);
m_children.append(img);
found = TRUE;
}
}
if (!found)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: IMG tag does not have a SRC attribute!\n");
}
}
break;
case XML_SUMMARY:
case XML_REMARKS:
case XML_VALUE:
case XML_PARA:
if (!m_children.isEmpty())
{
retval = TK_NEWPARA;
}
break;
case XML_EXAMPLE:
case XML_DESCRIPTION:
if (insideTable(this))
{
retval=RetVal_TableCell;
}
break;
case XML_C:
handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
break;
case XML_PARAM:
case XML_TYPEPARAM:
{
QString paramName;
if (findAttribute(tagHtmlAttribs,"name",¶mName))
{
retval = handleParamSection(paramName,
tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam,
TRUE);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <param> tag.");
}
}
break;
case XML_PARAMREF:
case XML_TYPEPARAMREF:
{
QString paramName;
if (findAttribute(tagHtmlAttribs,"name",¶mName))
{
//printf("paramName=%s\n",paramName.data());
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
m_children.append(new DocWord(this,paramName));
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type");
}
}
break;
case XML_EXCEPTION:
{
QString exceptName;
if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
{
retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <exception> tag.");
}
}
break;
case XML_ITEM:
case XML_LISTHEADER:
if (insideTable(this))
{
retval=RetVal_TableRow;
}
else if (insideUL(this) || insideOL(this))
{
retval=RetVal_ListItem;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: lonely <item> tag found");
}
break;
case XML_RETURNS:
retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
g_hasReturnCommand=TRUE;
break;
case XML_TERM:
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
if (insideTable(this))
{
retval=RetVal_TableCell;
}
break;
case XML_SEE:
// I'm not sure if <see> is the same as <seealso> or if it
// should you link a member without producing a section. The
// C# specification is extremely vague about this (but what else
// can we expect from Microsoft...)
{
QString cref;
//printf("XML_SEE: empty tag=%d\n",g_token->emptyTag);
if (findAttribute(tagHtmlAttribs,"cref",&cref))
{
if (g_token->emptyTag) // <see cref="..."/> style
{
bool inSeeBlock = g_inSeeBlock;
g_token->name = cref;
g_inSeeBlock = TRUE;
handleLinkedWord(this,m_children);
g_inSeeBlock = inSeeBlock;
}
else // <see cref="...">...</see> style
{
//DocRef *ref = new DocRef(this,cref);
//m_children.append(ref);
//ref->parse();
doctokenizerYYsetStatePara();
DocLink *lnk = new DocLink(this,cref);
m_children.append(lnk);
QString leftOver = lnk->parse(FALSE,TRUE);
if (!leftOver.isEmpty())
{
m_children.append(new DocWord(this,leftOver));
}
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'cref' attribute from <see> tag.");
}
}
break;
case XML_SEEALSO:
{
QString cref;
if (findAttribute(tagHtmlAttribs,"cref",&cref))
{
// Look for an existing "see" section
DocSimpleSect *ss=0;
QListIterator<DocNode> cli(m_children);
DocNode *n;
for (cli.toFirst();(n=cli.current());++cli)
{
if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
{
ss = (DocSimpleSect *)n;
}
}
if (!ss) // start new section
{
ss=new DocSimpleSect(this,DocSimpleSect::See);
m_children.append(ss);
}
ss->appendLinkWord(cref);
retval = RetVal_OK;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'cref' attribute from <seealso> tag.");
}
}
break;
case XML_LIST:
{
QString type;
findAttribute(tagHtmlAttribs,"type",&type);
DocHtmlList::Type listType = DocHtmlList::Unordered;
if (type=="number")
{
listType=DocHtmlList::Ordered;
}
if (type=="table")
{
DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
m_children.append(table);
retval=table->parseXml();
}
else
{
HtmlAttribList emptyList;
DocHtmlList *list = new DocHtmlList(this,emptyList,listType);
m_children.append(list);
retval=list->parseXml();
}
}
break;
case XML_INCLUDE:
case XML_PERMISSION:
// These tags are defined in .Net but are currently unsupported
break;
case HTML_UNKNOWN:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported xml/html tag <%s> found", tagName.data());
m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
break;
default:
// we should not get here!
ASSERT(0);
break;
}
return retval;
}
int DocPara::handleHtmlEndTag(const QString &tagName)
{
DBG(("handleHtmlEndTag(%s)\n",tagName.data()));
int tagId = Mappers::htmlTagMapper->map(tagName);
int retval=RetVal_OK;
switch (tagId)
{
case HTML_UL:
if (!insideUL(this))
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </ul> tag without matching <ul>");
}
else
{
retval=RetVal_EndList;
}
break;
case HTML_OL:
if (!insideOL(this))
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </ol> tag without matching <ol>");
}
else
{
retval=RetVal_EndList;
}
break;
case HTML_LI:
if (!insideLI(this))
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </li> tag without matching <li>");
}
else
{
// ignore </li> tags
}
break;
//case HTML_PRE:
// if (!insidePRE(this))
// {
// warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </pre> tag without matching <pre>");
// }
// else
// {
// retval=RetVal_EndPre;
// }
// break;
case HTML_BOLD:
handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
break;
case HTML_CODE:
handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
break;
case HTML_EMPHASIS:
handleStyleLeave(this,m_children,DocStyleChange::Italic,"em");
break;
case HTML_DIV:
handleStyleLeave(this,m_children,DocStyleChange::Div,"div");
break;
case HTML_SPAN:
handleStyleLeave(this,m_children,DocStyleChange::Span,"span");
break;
case HTML_SUB:
handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub");
break;
case HTML_SUP:
handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup");
break;
case HTML_CENTER:
handleStyleLeave(this,m_children,DocStyleChange::Center,"center");
break;
case HTML_SMALL:
handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
break;
case HTML_PRE:
handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
setInsidePreformatted(FALSE);
//doctokenizerYYsetInsidePre(FALSE);
break;
case HTML_P:
// ignore </p> tag
break;
case HTML_DL:
retval=RetVal_EndDesc;
break;
case HTML_DT:
// ignore </dt> tag
break;
case HTML_DD:
// ignore </dd> tag
break;
case HTML_TABLE:
retval=RetVal_EndTable;
break;
case HTML_TR:
// ignore </tr> tag
break;
case HTML_TD:
// ignore </td> tag
break;
case HTML_TH:
// ignore </th> tag
break;
case HTML_CAPTION:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </caption> found");
break;
case HTML_BR:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal </br> tag found\n");
break;
case HTML_H1:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </h1> found");
break;
case HTML_H2:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </h2> found");
break;
case HTML_H3:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </h3> found");
break;
case HTML_IMG:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </img> found");
break;
case HTML_HR:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </hr> found");
break;
case HTML_A:
//warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </a> found");
// ignore </a> tag (can be part of <a name=...></a>
break;
case XML_TERM:
m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
break;
case XML_SUMMARY:
case XML_REMARKS:
case XML_PARA:
case XML_VALUE:
case XML_LIST:
case XML_EXAMPLE:
case XML_PARAM:
case XML_TYPEPARAM:
case XML_RETURNS:
case XML_SEEALSO:
case XML_EXCEPTION:
retval = RetVal_CloseXml;
break;
case XML_C:
handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
break;
case XML_ITEM:
case XML_LISTHEADER:
case XML_INCLUDE:
case XML_PERMISSION:
case XML_DESCRIPTION:
case XML_PARAMREF:
case XML_TYPEPARAMREF:
// These tags are defined in .Net but are currently unsupported
break;
case HTML_UNKNOWN:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported xml/html tag </%s> found", tagName.data());
m_children.append(new DocWord(this,"</"+tagName+">"));
break;
default:
// we should not get here!
warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",tagName.data());
ASSERT(0);
break;
}
return retval;
}
int DocPara::parse()
{
DBG(("DocPara::parse() start\n"));
g_nodeStack.push(this);
// handle style commands "inherited" from the previous paragraph
handleInitialStyleCommands(this,m_children);
int tok;
int retval=0;
while ((tok=doctokenizerYYlex())) // get the next token
{
reparsetoken:
DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
tok==TK_COMMAND || tok==TK_HTMLTAG
)
{
DBG((" name=%s",g_token->name.data()));
}
DBG(("\n"));
switch(tok)
{
case TK_WORD:
m_children.append(new DocWord(this,g_token->name));
break;
case TK_LNKWORD:
handleLinkedWord(this,m_children);
break;
case TK_URL:
m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr));
break;
case TK_WHITESPACE:
{
// prevent leading whitespace and collapse multiple whitespace areas
DocNode::Kind k;
if (insidePRE(this) || // all whitespace is relevant
(
// remove leading whitespace
!m_children.isEmpty() &&
// and whitespace after certain constructs
(k=m_children.last()->kind())!=DocNode::Kind_HtmlDescList &&
k!=DocNode::Kind_HtmlTable &&
k!=DocNode::Kind_HtmlList &&
k!=DocNode::Kind_SimpleSect &&
k!=DocNode::Kind_AutoList &&
k!=DocNode::Kind_SimpleList &&
/*k!=DocNode::Kind_Verbatim &&*/
k!=DocNode::Kind_HtmlHeader &&
k!=DocNode::Kind_ParamSect &&
k!=DocNode::Kind_XRefItem
)
)
{
m_children.append(new DocWhiteSpace(this,g_token->chars));
}
}
break;
case TK_LISTITEM:
{
DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind()));
DocNode *n=parent();
while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent();
if (n) // we found an auto list up in the hierarchy
{
DocAutoList *al = (DocAutoList *)n;
DBG(("previous list item at %d\n",al->indent()));
if (al->indent()>=g_token->indent)
// new item at the same or lower indent level
{
retval=TK_LISTITEM;
goto endparagraph;
}
}
// determine list depth
int depth = 0;
n=parent();
while(n)
{
if(n->kind() == DocNode::Kind_AutoList) ++depth;
n=n->parent();
}
// first item or sub list => create new list
DocAutoList *al=0;
do
{
al = new DocAutoList(this,g_token->indent,g_token->isEnumList,
depth);
m_children.append(al);
retval = al->parse();
} while (retval==TK_LISTITEM && // new list
al->indent()==g_token->indent // at same indent level
);
// check the return value
if (retval==RetVal_SimpleSec) // auto list ended due to simple section command
{
// Reparse the token that ended the section at this level,
// so a new simple section will be started at this level.
// This is the same as unputting the last read token and continuing.
g_token->name = g_token->simpleSectName;
if (g_token->name.left(4)=="rcs:") // RCS section
{
g_token->name = g_token->name.mid(4);
g_token->text = g_token->simpleSectText;
tok = TK_RCSTAG;
}
else // other section
{
tok = TK_COMMAND;
}
DBG(("reparsing command %s\n",g_token->name.data()));
goto reparsetoken;
}
else if (retval==TK_ENDLIST)
{
if (al->indent()>g_token->indent) // end list
{
goto endparagraph;
}
else // continue with current paragraph
{
}
}
else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF
{
goto endparagraph;
}
}
break;
case TK_ENDLIST:
DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno));
if (parent()->kind()==DocNode::Kind_AutoListItem)
{
ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList);
DocAutoList *al = (DocAutoList *)parent()->parent();
if (al->indent()>=g_token->indent)
{
// end of list marker ends this paragraph
retval=TK_ENDLIST;
goto endparagraph;
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: End of list marker found "
"has invalid indent level");
}
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: End of list marker found without any preceding "
"list items");
}
break;
case TK_COMMAND:
{
// see if we have to start a simple section
int cmd = Mappers::cmdMapper->map(g_token->name);
DocNode *n=parent();
while (n &&
n->kind()!=DocNode::Kind_SimpleSect &&
n->kind()!=DocNode::Kind_ParamSect
)
{
n=n->parent();
}
if (cmd&SIMPLESECT_BIT)
{
if (n) // already in a simple section
{
// simple section cannot start in this paragraph, need
// to unwind the stack and remember the command.
g_token->simpleSectName = g_token->name.copy();
retval=RetVal_SimpleSec;
goto endparagraph;
}
}
// see if we are in a simple list
n=parent();
while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent();
if (n)
{
if (cmd==CMD_LI)
{
retval=RetVal_ListItem;
goto endparagraph;
}
}
// handle the command
retval=handleCommand(g_token->name.copy());
DBG(("handleCommand returns %x\n",retval));
// check the return value
if (retval==RetVal_SimpleSec)
{
// Reparse the token that ended the section at this level,
// so a new simple section will be started at this level.
// This is the same as unputting the last read token and continuing.
g_token->name = g_token->simpleSectName;
if (g_token->name.left(4)=="rcs:") // RCS section
{
g_token->name = g_token->name.mid(4);
g_token->text = g_token->simpleSectText;
tok = TK_RCSTAG;
}
else // other section
{
tok = TK_COMMAND;
}
DBG(("reparsing command %s\n",g_token->name.data()));
goto reparsetoken;
}
else if (retval==RetVal_OK)
{
// the command ended normally, keep scanning for new tokens.
retval = 0;
}
else if (retval>0 && retval<RetVal_OK)
{
// the command ended with a new command, reparse this token
tok = retval;
goto reparsetoken;
}
else // end of file, end of paragraph, start or end of section
// or some auto list marker
{
goto endparagraph;
}
}
break;
case TK_HTMLTAG:
{
if (!g_token->endTag) // found a start tag
{
retval = handleHtmlStartTag(g_token->name,g_token->attribs);
}
else // found an end tag
{
retval = handleHtmlEndTag(g_token->name);
}
if (retval==RetVal_OK)
{
// the command ended normally, keep scanner for new tokens.
retval = 0;
}
else
{
goto endparagraph;
}
}
break;
case TK_SYMBOL:
{
char letter='\0';
DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
if (s!=DocSymbol::Unknown)
{
m_children.append(new DocSymbol(this,s,letter));
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
}
break;
}
case TK_NEWPARA:
retval=TK_NEWPARA;
goto endparagraph;
case TK_RCSTAG:
{
DocNode *n=parent();
while (n &&
n->kind()!=DocNode::Kind_SimpleSect &&
n->kind()!=DocNode::Kind_ParamSect
)
{
n=n->parent();
}
if (n) // already in a simple section
{
// simple section cannot start in this paragraph, need
// to unwind the stack and remember the command.
g_token->simpleSectName = "rcs:"+g_token->name;
g_token->simpleSectText = g_token->text;
retval=RetVal_SimpleSec;
goto endparagraph;
}
// see if we are in a simple list
DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs);
m_children.append(ss);
ss->parseRcs();
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,
"Warning: Found unexpected token (id=%x)\n",tok);
break;
}
}
retval=0;
endparagraph:
handlePendingStyleCommands(this,m_children);
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocPara::parse() end retval=%x\n",retval));
INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM ||
retval==TK_ENDLIST || retval>RetVal_OK
);
return retval;
}
//--------------------------------------------------------------------------
int DocSection::parse()
{
DBG(("DocSection::parse() start %s level=%d\n",g_token->sectionId.data(),m_level));
int retval=RetVal_OK;
g_nodeStack.push(this);
SectionInfo *sec;
if (!m_id.isEmpty())
{
sec=Doxygen::sectionDict[m_id];
if (sec)
{
m_file = sec->fileName;
m_anchor = sec->label;
m_title = sec->title;
if (m_title.isEmpty()) m_title = sec->label;
if (g_sectionDict && g_sectionDict->find(m_id)==0)
{
g_sectionDict->insert(m_id,sec);
}
}
}
// first parse any number of paragraphs
bool isFirst=TRUE;
DocPara *lastPar=0;
do
{
DocPara *par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
retval=par->parse();
if (!par->isEmpty())
{
m_children.append(par);
lastPar=par;
}
else
{
delete par;
}
if (retval==TK_LISTITEM)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid list item found");
}
} while (retval!=0 &&
retval!=RetVal_Internal &&
retval!=RetVal_Section &&
retval!=RetVal_Subsection &&
retval!=RetVal_Subsubsection &&
retval!=RetVal_Paragraph
);
if (lastPar) lastPar->markLast();
//printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel);
if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1)
{
// then parse any number of nested sections
while (retval==RetVal_Subsection) // more sections follow
{
//SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
DocSection *s=new DocSection(this,
QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
m_children.append(s);
retval = s->parse();
}
}
else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2)
{
// then parse any number of nested sections
while (retval==RetVal_Subsubsection) // more sections follow
{
//SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
DocSection *s=new DocSection(this,
QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
m_children.append(s);
retval = s->parse();
}
}
else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3))
{
// then parse any number of nested sections
while (retval==RetVal_Paragraph) // more sections follow
{
//SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
DocSection *s=new DocSection(this,
QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
m_children.append(s);
retval = s->parse();
}
}
else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) ||
(m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph)
)
{
int level;
if (retval==RetVal_Subsection) level=2;
else if (retval==RetVal_Subsubsection) level=3;
else level=4;
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected %s "
"command found inside %s!",
sectionLevelToName[level],sectionLevelToName[m_level]);
retval=0; // stop parsing
}
else if (retval==RetVal_Internal)
{
DocInternal *in = new DocInternal(this);
m_children.append(in);
retval = in->parse(m_level+1);
}
else
{
}
INTERNAL_ASSERT(retval==0 ||
retval==RetVal_Section ||
retval==RetVal_Subsection ||
retval==RetVal_Subsubsection ||
retval==RetVal_Paragraph ||
retval==RetVal_Internal
);
DBG(("DocSection::parse() end\n"));
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
return retval;
}
//--------------------------------------------------------------------------
void DocText::parse()
{
DBG(("DocText::parse() start\n"));
g_nodeStack.push(this);
doctokenizerYYsetStateText();
int tok;
while ((tok=doctokenizerYYlex())) // get the next token
{
switch(tok)
{
case TK_WORD:
m_children.append(new DocWord(this,g_token->name));
break;
case TK_WHITESPACE:
m_children.append(new DocWhiteSpace(this,g_token->chars));
break;
case TK_SYMBOL:
{
char letter='\0';
DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
if (s!=DocSymbol::Unknown)
{
m_children.append(new DocSymbol(this,s,letter));
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
g_token->name.data());
}
}
break;
case TK_COMMAND:
switch (Mappers::cmdMapper->map(g_token->name))
{
case CMD_BSLASH:
m_children.append(new DocSymbol(this,DocSymbol::BSlash));
break;
case CMD_AT:
m_children.append(new DocSymbol(this,DocSymbol::At));
break;
case CMD_LESS:
m_children.append(new DocSymbol(this,DocSymbol::Less));
break;
case CMD_GREATER:
m_children.append(new DocSymbol(this,DocSymbol::Greater));
break;
case CMD_AMP:
m_children.append(new DocSymbol(this,DocSymbol::Amp));
break;
case CMD_DOLLAR:
m_children.append(new DocSymbol(this,DocSymbol::Dollar));
break;
case CMD_HASH:
m_children.append(new DocSymbol(this,DocSymbol::Hash));
break;
case CMD_PERCENT:
m_children.append(new DocSymbol(this,DocSymbol::Percent));
break;
case CMD_QUOTE:
m_children.append(new DocSymbol(this,DocSymbol::Quot));
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected command `%s' found",
g_token->name.data());
break;
}
break;
default:
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
tokToString(tok));
break;
}
}
handleUnclosedStyleCommands();
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocText::parse() end\n"));
}
//--------------------------------------------------------------------------
void DocRoot::parse()
{
DBG(("DocRoot::parse() start\n"));
g_nodeStack.push(this);
doctokenizerYYsetStatePara();
int retval=0;
// first parse any number of paragraphs
bool isFirst=TRUE;
DocPara *lastPar=0;
do
{
DocPara *par = new DocPara(this);
if (isFirst) { par->markFirst(); isFirst=FALSE; }
retval=par->parse();
if (!par->isEmpty())
{
m_children.append(par);
lastPar=par;
}
else
{
delete par;
}
if (retval==TK_LISTITEM)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid list item found");
}
else if (retval==RetVal_Subsection)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found subsection command outside of section context!");
}
else if (retval==RetVal_Subsubsection)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found subsubsection command outside of subsection context!");
}
else if (retval==RetVal_Paragraph)
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found paragraph command outside of subsubsection context!");
}
} while (retval!=0 && retval!=RetVal_Section && retval!=RetVal_Internal);
if (lastPar) lastPar->markLast();
//printf("DocRoot::parse() retval=%d %d\n",retval,RetVal_Section);
// then parse any number of level1 sections
while (retval==RetVal_Section)
{
SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
if (sec)
{
DocSection *s=new DocSection(this,
QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
m_children.append(s);
retval = s->parse();
}
else
{
warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid section id `%s'; ignoring section",g_token->sectionId.data());
retval = 0;
}
}
if (retval==RetVal_Internal)
{
DocInternal *in = new DocInternal(this);
m_children.append(in);
retval = in->parse(1);
}
handleUnclosedStyleCommands();
DocNode *n = g_nodeStack.pop();
ASSERT(n==this);
DBG(("DocRoot::parse() end\n"));
}
//--------------------------------------------------------------------------
DocNode *validatingParseDoc(const char *fileName,int startLine,
Definition *ctx,MemberDef *md,
const char *input,bool indexWords,
bool isExample, const char *exampleName,
bool singleLine, bool linkFromIndex)
{
//printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>",
// md?md->name().data():"<none>",
// input);
//printf("========== validating %s at line %d\n",fileName,startLine);
//printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input);
//g_token = new TokenInfo;
// store parser state so we can re-enter this function if needed
bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
docParserPushContext();
if (ctx &&
(ctx->definitionType()==Definition::TypeClass ||
ctx->definitionType()==Definition::TypeNamespace
)
)
{
g_context = ctx->name();
}
else if (ctx && ctx->definitionType()==Definition::TypePage)
{
Definition *scope = ((PageDef*)ctx)->getPageScope();
if (scope) g_context = scope->name();
}
else if (ctx && ctx->definitionType()==Definition::TypeGroup)
{
Definition *scope = ((GroupDef*)ctx)->getGroupScope();
if (scope) g_context = scope->name();
}
else
{
g_context = "";
}
g_scope = ctx;
//printf("g_context=%s\n",g_context.data());
if (indexWords && md && Doxygen::searchIndex)
{
g_searchUrl=md->getOutputFileBase();
Doxygen::searchIndex->setCurrentDoc(
(fortranOpt?theTranslator->trSubprogram(TRUE,TRUE):theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(),
g_searchUrl,
md->anchor());
}
else if (indexWords && ctx && Doxygen::searchIndex)
{
g_searchUrl=ctx->getOutputFileBase();
QCString name = ctx->qualifiedName();
if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
{
name = substitute(name,"::",".");
}
switch (ctx->definitionType())
{
case Definition::TypePage:
{
PageDef *pd = (PageDef *)ctx;
if (!pd->title().isEmpty())
{
name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title();
}
else
{
name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name();
}
}
break;
case Definition::TypeClass:
{
ClassDef *cd = (ClassDef *)ctx;
name.prepend(cd->compoundTypeString()+" ");
}
break;
case Definition::TypeNamespace:
{
if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
{
name = theTranslator->trPackage(name);
}
else if(fortranOpt)
{
name.prepend(theTranslator->trModule(TRUE,TRUE)+" ");
}
else
{
name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" ");
}
}
break;
case Definition::TypeGroup:
{
GroupDef *gd = (GroupDef *)ctx;
if (gd->groupTitle())
{
name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle();
}
else
{
name.prepend(theTranslator->trGroup(TRUE,TRUE)+" ");
}
}
break;
default:
break;
}
Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl);
}
else
{
g_searchUrl="";
}
g_fileName = fileName;
g_relPath = (!linkFromIndex && ctx) ?
QString(relativePathToRoot(ctx->getOutputFileBase())) :
QString("");
//printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data());
g_memberDef = md;
g_nodeStack.clear();
g_styleStack.clear();
g_initialStyleStack.clear();
g_inSeeBlock = FALSE;
g_insideHtmlLink = FALSE;
g_includeFileText = "";
g_includeFileOffset = 0;
g_includeFileLength = 0;
g_isExample = isExample;
g_exampleName = exampleName;
g_hasParamCommand = FALSE;
g_hasReturnCommand = FALSE;
g_paramsFound.setAutoDelete(FALSE);
g_paramsFound.clear();
g_sectionDict = 0; //sections;
//printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
doctokenizerYYlineno=startLine;
doctokenizerYYinit(input,g_fileName);
// build abstract syntax tree
DocRoot *root = new DocRoot(md!=0,singleLine);
root->parse();
if (Debug::isFlagSet(Debug::PrintTree))
{
// pretty print the result
PrintDocVisitor *v = new PrintDocVisitor;
root->accept(v);
delete v;
}
checkUndocumentedParams();
detectNoDocumentedParams();
// TODO: These should be called at the end of the program.
//doctokenizerYYcleanup();
//Mappers::cmdMapper->freeInstance();
//Mappers::htmlTagMapper->freeInstance();
// restore original parser state
docParserPopContext();
//printf(">>>>>> end validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>",
// md?md->name().data():"<none>");
return root;
}
DocNode *validatingParseText(const char *input)
{
// store parser state so we can re-enter this function if needed
docParserPushContext();
//printf("------------ input ---------\n%s\n"
// "------------ end input -----\n",input);
//g_token = new TokenInfo;
g_context = "";
g_fileName = "<parseText>";
g_relPath = "";
g_memberDef = 0;
g_nodeStack.clear();
g_styleStack.clear();
g_initialStyleStack.clear();
g_inSeeBlock = FALSE;
g_insideHtmlLink = FALSE;
g_includeFileText = "";
g_includeFileOffset = 0;
g_includeFileLength = 0;
g_isExample = FALSE;
g_exampleName = "";
g_hasParamCommand = FALSE;
g_hasReturnCommand = FALSE;
g_paramsFound.setAutoDelete(FALSE);
g_paramsFound.clear();
g_searchUrl="";
DocText *txt = new DocText;
if (input)
{
doctokenizerYYlineno=1;
doctokenizerYYinit(input,g_fileName);
// build abstract syntax tree
txt->parse();
if (Debug::isFlagSet(Debug::PrintTree))
{
// pretty print the result
PrintDocVisitor *v = new PrintDocVisitor;
txt->accept(v);
delete v;
}
}
// restore original parser state
docParserPopContext();
return txt;
}
void docFindSections(const char *input,
Definition *d,
MemberGroup *mg,
const char *fileName)
{
doctokenizerYYFindSections(input,d,mg,fileName);
}
void initDocParser()
{
static bool searchEngine = Config_getBool("SEARCHENGINE");
static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
if (searchEngine && serverBasedSearch)
{
Doxygen::searchIndex = new SearchIndex;
}
else // no search engine or pure javascript based search function
{
Doxygen::searchIndex = 0;
}
}
void finializeDocParser()
{
delete Doxygen::searchIndex;
}