diff options
author | dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7> | 2002-08-26 17:33:07 (GMT) |
---|---|---|
committer | dimitri <dimitri@afe2bf4a-e733-0410-8a33-86f594647bc7> | 2002-08-26 17:33:07 (GMT) |
commit | 55d2ef8412008e1560b0d5a2ecc2031f269af4a1 (patch) | |
tree | 6d5ee0db5c717ebabc57f2d2a15a1365d5e3fa19 /src/docparser.cpp | |
parent | 17e35fd285d98df3c7fe59ee8805152726c3572e (diff) | |
download | Doxygen-55d2ef8412008e1560b0d5a2ecc2031f269af4a1.zip Doxygen-55d2ef8412008e1560b0d5a2ecc2031f269af4a1.tar.gz Doxygen-55d2ef8412008e1560b0d5a2ecc2031f269af4a1.tar.bz2 |
Release-1.2.17-20020826
Diffstat (limited to 'src/docparser.cpp')
-rw-r--r-- | src/docparser.cpp | 530 |
1 files changed, 510 insertions, 20 deletions
diff --git a/src/docparser.cpp b/src/docparser.cpp index da1d808..9502eeb 100644 --- a/src/docparser.cpp +++ b/src/docparser.cpp @@ -24,6 +24,7 @@ #include <qcstring.h> #include <qstack.h> #include <qdict.h> +#include <ctype.h> #include "doxygen.h" #include "debug.h" @@ -40,11 +41,18 @@ //--------------------------------------------------------------------------- +// include file state +static QCString g_includeFileText; +static uint g_includeFileOffset; +static uint g_includeFileLength; + +// parser state static QCString g_context; static bool g_inSeeBlock; static bool g_insideHtmlLink; static QStack<DocNode> g_nodeStack; static QStack<DocStyleChange> g_styleStack; +static QList<Definition> g_copyStack; struct DocParserContext { @@ -53,6 +61,7 @@ struct DocParserContext bool insideHtmlLink; QStack<DocNode> nodeStack; QStack<DocStyleChange> styleStack; + QList<Definition> copyStack; }; static QStack<DocParserContext> g_parserStack; @@ -63,22 +72,24 @@ static void docParserPushContext() { doctokenizerYYpushContext(); DocParserContext *ctx = new DocParserContext; - ctx->context = g_context; - ctx->inSeeBlock = g_inSeeBlock; + ctx->context = g_context; + ctx->inSeeBlock = g_inSeeBlock; ctx->insideHtmlLink = g_insideHtmlLink; - ctx->nodeStack = g_nodeStack; - ctx->styleStack = g_styleStack; + ctx->nodeStack = g_nodeStack; + ctx->styleStack = g_styleStack; + ctx->copyStack = g_copyStack; g_parserStack.push(ctx); } static void docParserPopContext() { DocParserContext *ctx = g_parserStack.pop(); - g_context = ctx->context; - g_inSeeBlock = ctx->inSeeBlock; + g_context = ctx->context; + g_inSeeBlock = ctx->inSeeBlock; g_insideHtmlLink = ctx->insideHtmlLink; - g_nodeStack = ctx->nodeStack; - g_styleStack = ctx->styleStack; + g_nodeStack = ctx->nodeStack; + g_styleStack = ctx->styleStack; + g_copyStack = ctx->copyStack; delete ctx; doctokenizerYYpopContext(); } @@ -171,6 +182,112 @@ static bool insideLang(DocNode *n) //--------------------------------------------------------------------------- +/*! 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, + QCString *pDoc, + Definition **pDef) +{ + pDoc->resize(0); + *pDef=0; + QCString cmdArg=commandName; + int l=cmdArg.length(); + if (l==0) return FALSE; + + int funcStart=cmdArg.find('('); + if (funcStart==-1) funcStart=l; + //int lastScopeStart=cmdArg.findRev("::",funcStart); + //int lastScopeEnd = lastScopeStart==-1 ? 0 : lastScopeStart+2; + //QCString scope=cmdArg.left(QMAX(lastScopeStart,0)); + //QCString name=cmdArg.mid(lastScopeEnd,funcStart-lastScopeEnd); + QCString name=cmdArg.left(funcStart); + QCString 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; + PageInfo *pi=0; + bool found = getDefs(g_context,name,args,md,cd,fd,nd,gd,FALSE,0,TRUE); + if (found && md) + { + *pDoc=md->documentation(); + *pDef=md; + return TRUE; + } + + + int scopeOffset=g_context.length(); + do // for each scope + { + QCString 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[fullName]; + if (cd) // class + { + *pDoc=cd->documentation(); + *pDef=cd; + return TRUE; + } + nd = Doxygen::namespaceSDict[fullName]; + if (nd) // namespace + { + *pDoc=nd->documentation(); + *pDef=nd; + return TRUE; + } + gd = Doxygen::groupSDict[cmdArg]; + if (gd) // group + { + *pDoc=gd->documentation(); + *pDef=gd; + return TRUE; + } + pi = Doxygen::pageSDict->find(cmdArg); + if (pi) // page + { + *pDoc=pi->doc; + *pDef=(Definition *)pi; + return TRUE; + } + bool ambig; + fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig); + if (fd && !ambig) // file + { + *pDoc=fd->documentation(); + *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 @@ -422,7 +539,7 @@ static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children tokToString(tok),tokenName.data(),doctokenizerYYlineno); break; } - DocAnchor *anchor = new DocAnchor(parent,g_token->name); + DocAnchor *anchor = new DocAnchor(parent,g_token->name,FALSE); children.append(anchor); } break; @@ -657,6 +774,10 @@ static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children, children.append(par); lastPar=par; } + else + { + delete par; + } } while (retval==TK_NEWPARA); if (lastPar) lastPar->markLast(); @@ -665,6 +786,231 @@ static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children, //--------------------------------------------------------------------------- +static void readTextFileByName(const QCString &file,QCString &text) +{ + bool ambig; + FileDef *fd; + if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig))) + { + text = fileToString(fd->absFilePath()); + } + else if (ambig) + { + printf("Error: included file name %s at line %d is ambigious.\n" + "Possible candidates:\n%s",file.data(),doctokenizerYYlineno, + showFileDefMatches(Doxygen::exampleNameDict,file).data() + ); + } + else + { + printf("Error: included file %s at line %d is not found. " + "Check you EXAMPLE_PATH",file.data(),doctokenizerYYlineno); + } +} + +//--------------------------------------------------------------------------- + +DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor) + : m_parent(parent) +{ + if (id.isEmpty()) + { + printf("Error: Empty anchor label at line %d!\n",doctokenizerYYlineno); + } + if (newAnchor) // found <a name="label"> + { + m_anchor = id; + } + else // found \anchor label + { + SectionInfo *sec = Doxygen::sectionDict[id]; + if (sec) + { + m_file = sec->fileName; + m_anchor = sec->label; + } + else + { + printf("Error: Invalid anchor id `%s' at line %d\n",id.data(),doctokenizerYYlineno); + } + } +} + +//--------------------------------------------------------------------------- + +void DocInclude::parse() +{ + switch(m_type) + { + case Include: + // fall through + case DontInclude: + readTextFileByName(m_file,m_text); + g_includeFileText = m_text; + g_includeFileOffset = 0; + g_includeFileLength = m_text.length(); + 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; + //printf("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(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); + } + 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(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); + 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(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(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); + break; + } + o++; // skip new line + } + g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line + break; + } +} + +//--------------------------------------------------------------------------- + +void DocCopy::parse() +{ + QCString doc; + Definition *def; + if (findDocsForMemberOrCompound(m_link,&doc,&def)) + { + if (g_copyStack.findRef(def)==-1) // definition not parsed earlier + { + docParserPushContext(); + g_context=def->name(); + g_styleStack.clear(); + g_nodeStack.clear(); + g_copyStack.append(def); + internalValidatingParseDoc(this,m_children,doc); + ASSERT(g_copyStack.remove(def)); + ASSERT(g_styleStack.isEmpty()); + ASSERT(g_nodeStack.isEmpty()); + docParserPopContext(); + } + else // oops, recursion + { + printf("Error: recursive call chain of \\copydoc commands detected at %d\n", + doctokenizerYYlineno); + } + } + else + { + printf("Error: target %s of \\copydoc command at line %d not found\n", + m_link.data(),doctokenizerYYlineno); + } +} + +//--------------------------------------------------------------------------- + void DocXRefItem::parse() { QCString listName; @@ -765,6 +1111,28 @@ void DocSecRefItem::parse() } 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; + } + else + { + printf("Error reference to unknown section %s at line %d\n", + m_target.data(),doctokenizerYYlineno); + } + } + else + { + printf("Error reference to empty target at line %d\n", + doctokenizerYYlineno); + } + DBG(("DocSecRefItem::parse() end\n")); DocNode *n = g_nodeStack.pop(); ASSERT(n==this); @@ -817,6 +1185,10 @@ void DocSecRefList::parse() goto endsecreflist; } } + else if (tok==TK_WHITESPACE) + { + // ignore whitespace + } else { printf("Error: Unexpected token %s inside section reference list at line %d\n", @@ -1094,9 +1466,47 @@ void DocDotFile::parse() } } } + 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 + { + printf("Error: Unknown option %s after image title at line %d\n", + g_token->name.data(),doctokenizerYYlineno); + } + 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) + { + printf("Error: included dot file name %s at line %d is ambigious.\n" + "Possible candidates:\n%s",m_name.data(),doctokenizerYYlineno, + showFileDefMatches(Doxygen::exampleNameDict,m_name).data() + ); + } + else + { + printf("Error: included dot file %s at line %d is not found " + "in any of the paths specified via DOTFILE_DIRS!",m_name.data(),doctokenizerYYlineno); + } + DBG(("DocDotFile::parse() end\n")); DocNode *n=g_nodeStack.pop(); ASSERT(n==this); @@ -1133,6 +1543,25 @@ void DocImage::parse() } } } + 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 + { + printf("Error: Unknown option %s after image title at line %d\n", + g_token->name.data(),doctokenizerYYlineno); + } + tok=doctokenizerYYlex(); + } + ASSERT(tok==0); doctokenizerYYsetStatePara(); handlePendingStyleCommands(this,m_children); @@ -1300,6 +1729,10 @@ int DocInternal::parse() m_children.append(par); lastPar=par; } + else + { + delete par; + } if (retval==TK_LISTITEM) { printf("Error: Invalid list item found at line %d!\n",doctokenizerYYlineno); @@ -1473,6 +1906,9 @@ int DocHtmlRow::parse() DBG(("DocHtmlRow::parse() start\n")); bool isHeading=FALSE; + bool isFirst=TRUE; + DocHtmlCell *cell=0; + // get next token int tok=doctokenizerYYlex(); // skip whitespace @@ -1511,12 +1947,15 @@ int DocHtmlRow::parse() // parse one or more cells do { - DocHtmlCell *td=new DocHtmlCell(this,isHeading); - m_children.append(td); - retval=td->parse(); + cell=new DocHtmlCell(this,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")); @@ -2089,6 +2528,7 @@ int DocParamSect::parse(const QCString &cmdName) //-------------------------------------------------------------------------- + int DocPara::handleSimpleSection(DocSimpleSect::Type t) { DocSimpleSect *ss=0; @@ -2168,8 +2608,30 @@ void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type tokToString(tok),cmdName.data(),doctokenizerYYlineno); return; } - DocIncOperator *op = new DocIncOperator(this,t,g_token->name); + DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context); + 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 QCString &cmdName) @@ -2365,8 +2827,9 @@ void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t) tokToString(tok),cmdName.data(),doctokenizerYYlineno); return; } - DocInclude *inc = new DocInclude(this,g_token->name,t); + DocInclude *inc = new DocInclude(this,g_token->name,g_context,t); m_children.append(inc); + inc->parse(); } @@ -2594,7 +3057,7 @@ int DocPara::handleCommand(const QCString &cmdName) tokToString(tok),cmdName.data(),doctokenizerYYlineno); break; } - DocAnchor *anchor = new DocAnchor(this,g_token->name); + DocAnchor *anchor = new DocAnchor(this,g_token->name,FALSE); m_children.append(anchor); } break; @@ -2632,6 +3095,7 @@ int DocPara::handleCommand(const QCString &cmdName) } DocCopy *cpy = new DocCopy(this,g_token->name); m_children.append(cpy); + cpy->parse(); } break; case CMD_INCLUDE: @@ -2830,7 +3294,7 @@ int DocPara::handleHtmlStartTag(const QCString &tagName,const QList<Option> &tag { if (!opt->value.isEmpty()) { - DocAnchor *anc = new DocAnchor(this,opt->value); + DocAnchor *anc = new DocAnchor(this,opt->value,TRUE); m_children.append(anc); break; // stop looking for other tag options } @@ -3294,6 +3758,19 @@ int DocSection::parse() 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; + } + } + // first parse any number of paragraphs bool isFirst=FALSE; DocPara *lastPar=0; @@ -3305,7 +3782,11 @@ int DocSection::parse() if (!par->isEmpty()) { m_children.append(par); - lastPar = par; + lastPar=par; + } + else + { + delete par; } if (retval==TK_LISTITEM) { @@ -3318,8 +3799,9 @@ int DocSection::parse() while (retval==RetVal_Section) // more sections follow { SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId]; + ASSERT(sec!=0); int secLev = sec->type==SectionInfo::Subsection ? 2 : 1; - if (secLev==level()) // new section at same level + if (secLev<=level()) // new section at same or lower level { break; } @@ -3364,7 +3846,11 @@ void DocRoot::parse() if (!par->isEmpty()) { m_children.append(par); - lastPar = par; + lastPar=par; + } + else + { + delete par; } if (retval==TK_LISTITEM) { @@ -3377,6 +3863,7 @@ void DocRoot::parse() while (retval==RetVal_Section) { SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId]; + ASSERT(sec!=0); int secLev = sec->type==SectionInfo::Subsection ? 2 : 1; if (secLev!=1) // wrong level { @@ -3417,6 +3904,9 @@ DocNode *validatingParseDoc(const char *fileName,int startLine, g_styleStack.clear(); g_inSeeBlock = FALSE; g_insideHtmlLink = FALSE; + g_includeFileText.resize(0); + g_includeFileOffset = 0; + g_includeFileLength = 0; doctokenizerYYlineno=startLine; doctokenizerYYinit(input); |