1 /******************************************************************************
6 * Copyright (C) 1997-2012 by Dimitri van Heesch.
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation under the terms of the GNU General Public License is hereby
10 * granted. No representations are made about the suitability of this software
11 * for any purpose. It is provided "as is" without express or implied warranty.
12 * See the GNU General Public License for more details.
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
23 #include <qfileinfo.h>
35 #include "docparser.h"
36 #include "doctokenizer.h"
37 #include "cmdmapper.h"
38 #include "printdocvisitor.h"
41 #include "searchindex.h"
45 #include "arguments.h"
48 #define DBG(x) do {} while(0)
51 //#define DBG(x) printf x
54 //#define myprintf(x...) fprintf(stderr,x)
55 //#define DBG(x) myprintf x
57 #define INTERNAL_ASSERT(x) do {} while(0)
58 //#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__));
60 //---------------------------------------------------------------------------
62 static const char *sectionLevelToName[] =
71 //---------------------------------------------------------------------------
73 // Parser state: global variables during a call to validatingParseDoc
74 static Definition * g_scope;
75 static QCString g_context;
76 static bool g_inSeeBlock;
77 static bool g_xmlComment;
78 static bool g_insideHtmlLink;
79 static QStack<DocNode> g_nodeStack;
80 static QStack<DocStyleChange> g_styleStack;
81 static QStack<DocStyleChange> g_initialStyleStack;
82 static QList<Definition> g_copyStack;
83 static QCString g_fileName;
84 static QCString g_relPath;
86 static bool g_hasParamCommand;
87 static bool g_hasReturnCommand;
88 static QDict<void> g_paramsFound;
89 static MemberDef * g_memberDef;
90 static bool g_isExample;
91 static QCString g_exampleName;
92 static SectionDict * g_sectionDict;
93 static QCString g_searchUrl;
95 static QCString g_includeFileText;
96 static uint g_includeFileOffset;
97 static uint g_includeFileLength;
100 /** Parser's context to store all global variables.
102 struct DocParserContext
109 QStack<DocNode> nodeStack;
110 QStack<DocStyleChange> styleStack;
111 QStack<DocStyleChange> initialStyleStack;
112 QList<Definition> copyStack;
116 bool hasParamCommand;
117 bool hasReturnCommand;
118 MemberDef * memberDef;
119 QDict<void> paramsFound;
121 QCString exampleName;
122 SectionDict *sectionDict;
125 QCString includeFileText;
126 uint includeFileOffset;
127 uint includeFileLength;
132 static QStack<DocParserContext> g_parserStack;
134 //---------------------------------------------------------------------------
136 static void docParserPushContext(bool saveParamInfo=TRUE)
139 //indent.fill(' ',g_parserStack.count()*2+2);
140 //printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count());
142 doctokenizerYYpushContext();
143 DocParserContext *ctx = new DocParserContext;
144 ctx->scope = g_scope;
145 ctx->context = g_context;
146 ctx->inSeeBlock = g_inSeeBlock;
147 ctx->xmlComment = g_xmlComment;
148 ctx->insideHtmlLink = g_insideHtmlLink;
149 ctx->nodeStack = g_nodeStack;
150 ctx->styleStack = g_styleStack;
151 ctx->initialStyleStack = g_initialStyleStack;
152 ctx->copyStack = g_copyStack;
153 ctx->fileName = g_fileName;
154 ctx->relPath = g_relPath;
158 ctx->hasParamCommand = g_hasParamCommand;
159 ctx->hasReturnCommand = g_hasReturnCommand;
160 ctx->paramsFound = g_paramsFound;
163 ctx->memberDef = g_memberDef;
164 ctx->isExample = g_isExample;
165 ctx->exampleName = g_exampleName;
166 ctx->sectionDict = g_sectionDict;
167 ctx->searchUrl = g_searchUrl;
169 ctx->includeFileText = g_includeFileText;
170 ctx->includeFileOffset = g_includeFileOffset;
171 ctx->includeFileLength = g_includeFileLength;
173 ctx->token = g_token;
174 g_token = new TokenInfo;
176 g_parserStack.push(ctx);
179 static void docParserPopContext(bool keepParamInfo=FALSE)
181 DocParserContext *ctx = g_parserStack.pop();
182 g_scope = ctx->scope;
183 g_context = ctx->context;
184 g_inSeeBlock = ctx->inSeeBlock;
185 g_xmlComment = ctx->xmlComment;
186 g_insideHtmlLink = ctx->insideHtmlLink;
187 g_nodeStack = ctx->nodeStack;
188 g_styleStack = ctx->styleStack;
189 g_initialStyleStack = ctx->initialStyleStack;
190 g_copyStack = ctx->copyStack;
191 g_fileName = ctx->fileName;
192 g_relPath = ctx->relPath;
196 g_hasParamCommand = ctx->hasParamCommand;
197 g_hasReturnCommand = ctx->hasReturnCommand;
198 g_paramsFound = ctx->paramsFound;
200 g_memberDef = ctx->memberDef;
201 g_isExample = ctx->isExample;
202 g_exampleName = ctx->exampleName;
203 g_sectionDict = ctx->sectionDict;
204 g_searchUrl = ctx->searchUrl;
206 g_includeFileText = ctx->includeFileText;
207 g_includeFileOffset = ctx->includeFileOffset;
208 g_includeFileLength = ctx->includeFileLength;
211 g_token = ctx->token;
214 doctokenizerYYpopContext();
217 //indent.fill(' ',g_parserStack.count()*2+2);
218 //printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count());
221 //---------------------------------------------------------------------------
223 /*! search for an image in the imageNameDict and if found
224 * copies the image to the output directory (which depends on the \a type
227 static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
232 //printf("Search for %s\n",fileName);
233 if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
235 QCString inputFile = fd->absFilePath();
236 QFile inImage(inputFile);
237 if (inImage.open(IO_ReadOnly))
241 if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1)
243 result = result.right(result.length()-i-1);
245 //printf("fileName=%s result=%s\n",fileName,result.data());
250 if (!Config_getBool("GENERATE_HTML")) return result;
251 outputDir = Config_getString("HTML_OUTPUT");
253 case DocImage::Latex:
254 if (!Config_getBool("GENERATE_LATEX")) return result;
255 outputDir = Config_getString("LATEX_OUTPUT");
258 if (!Config_getBool("GENERATE_RTF")) return result;
259 outputDir = Config_getString("RTF_OUTPUT");
262 QCString outputFile = outputDir+"/"+result;
263 if (outputFile!=inputFile) // prevent copying to ourself
265 QFile outImage(outputFile.data());
266 if (outImage.open(IO_WriteOnly)) // copy the image
268 char *buffer = new char[inImage.size()];
269 inImage.readBlock(buffer,inImage.size());
270 outImage.writeBlock(buffer,inImage.size());
273 if (type==DocImage::Html) Doxygen::indexList.addImageFile(result);
277 warn_doc_error(g_fileName,doctokenizerYYlineno,
278 "warning: could not write output image %s",qPrint(outputFile));
284 warn_doc_error(g_fileName,doctokenizerYYlineno,
285 "warning: could not open image %s",qPrint(fileName));
288 if (type==DocImage::Latex && Config_getBool("USE_PDFLATEX") &&
289 fd->name().right(4)==".eps"
291 { // we have an .eps image in pdflatex mode => convert it to a pdf.
292 QCString outputDir = Config_getString("LATEX_OUTPUT");
293 QCString baseName = fd->name().left(fd->name().length()-4);
294 QCString epstopdfArgs(4096);
295 epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"",
296 outputDir.data(), baseName.data(),
297 outputDir.data(), baseName.data());
298 portable_sysTimerStart();
299 if (portable_system("epstopdf",epstopdfArgs)!=0)
301 err("error: Problems running epstopdf. Check your TeX installation!\n");
303 portable_sysTimerStop();
310 text.sprintf("warning: image file name %s is ambiguous.\n",qPrint(fileName));
311 text+="Possible candidates:\n";
312 text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
313 warn_doc_error(g_fileName,doctokenizerYYlineno,text);
318 if (result.left(5)!="http:" && result.left(6)!="https:")
320 warn_doc_error(g_fileName,doctokenizerYYlineno,
321 "warning: image file %s is not found in IMAGE_PATH: "
322 "assuming external image.",qPrint(fileName)
329 /*! Collects the parameters found with \@param or \@retval commands
330 * in a global list g_paramsFound. If \a isParam is set to TRUE
331 * and the parameter is not an actual parameter of the current
332 * member g_memberDef, then a warning is raised (unless warnings
333 * are disabled altogether).
335 static void checkArgumentName(const QCString &name,bool isParam)
337 if (!Config_getBool("WARN_IF_DOC_ERROR")) return;
338 if (g_memberDef==0) return; // not a member
339 LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ?
340 g_memberDef->argumentList() :
341 g_memberDef->declArgumentList();
342 SrcLangExt lang = g_memberDef->getLanguage();
343 //printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition());
344 if (al==0) return; // no argument list
346 static QRegExp re("$?[a-zA-Z0-9_\\x80-\\xFF]+\\.*");
348 while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
350 QCString aName=name.mid(i,l);
351 if (lang==SrcLangExt_Fortran) aName=aName.lower();
352 //printf("aName=`%s'\n",aName.data());
353 ArgumentListIterator ali(*al);
356 for (ali.toFirst();(a=ali.current());++ali)
358 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
359 if (lang==SrcLangExt_Fortran) argName=argName.lower();
360 argName=argName.stripWhiteSpace();
361 //printf("argName=`%s' aName=%s\n",argName.data(),aName.data());
362 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
365 g_paramsFound.insert(aName,(void *)(0x8));
370 if (!found && isParam)
372 //printf("member type=%d\n",memberDef->memberType());
373 QCString scope=g_memberDef->getScopeString();
374 if (!scope.isEmpty()) scope+="::"; else scope="";
375 QCString inheritedFrom = "";
376 QCString docFile = g_memberDef->docFile();
377 int docLine = g_memberDef->docLine();
378 MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom();
379 if (inheritedMd) // documentation was inherited
381 inheritedFrom.sprintf(" inherited from member %s at line "
382 "%d in file %s",qPrint(inheritedMd->name()),
383 inheritedMd->docLine(),qPrint(inheritedMd->docFile()));
384 docFile = g_memberDef->getDefFileName();
385 docLine = g_memberDef->getDefLine();
388 QCString alStr = argListToString(al.pointer());
389 warn_doc_error(docFile,docLine,
390 "warning: argument '%s' of command @param "
391 "is not found in the argument list of %s%s%s%s",
392 qPrint(aName), qPrint(scope), qPrint(g_memberDef->name()),
393 qPrint(alStr), qPrint(inheritedFrom));
399 /*! Checks if the parameters that have been specified using \@param are
400 * indeed all parameters.
401 * Must be called after checkArgumentName() has been called for each
404 static void checkUndocumentedParams()
406 if (g_memberDef && g_hasParamCommand && Config_getBool("WARN_IF_DOC_ERROR"))
408 LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ?
409 g_memberDef->argumentList() :
410 g_memberDef->declArgumentList();
411 SrcLangExt lang = g_memberDef->getLanguage();
414 ArgumentListIterator ali(*al);
417 for (ali.toFirst();(a=ali.current());++ali)
419 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
420 if (lang==SrcLangExt_Fortran) argName = argName.lower();
421 argName=argName.stripWhiteSpace();
422 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
423 if (g_memberDef->getLanguage()==SrcLangExt_Python && argName=="self")
425 // allow undocumented self parameter for Python
427 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty())
437 "warning: The following parameters of "+
438 QCString(g_memberDef->qualifiedName()) +
439 QCString(argListToString(al.pointer())) +
440 " are not documented:\n";
441 for (ali.toFirst();(a=ali.current());++ali)
443 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
444 if (lang==SrcLangExt_Fortran) argName = argName.lower();
445 argName=argName.stripWhiteSpace();
446 if (g_memberDef->getLanguage()==SrcLangExt_Python && argName=="self")
448 // allow undocumented self parameter for Python
450 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0)
460 errMsg+=" parameter '"+argName+"'";
463 if (g_memberDef->inheritsDocsFrom())
465 warn_doc_error(g_memberDef->getDefFileName(),
466 g_memberDef->getDefLine(),
467 substitute(errMsg,"%","%%"));
471 warn_doc_error(g_memberDef->docFile(),
472 g_memberDef->docLine(),
473 substitute(errMsg,"%","%%"));
480 /*! Check if a member has documentation for its parameter and or return
481 * type, if applicable. If found this will be stored in the member, this
482 * is needed as a member can have brief and detailed documentation, while
483 * only one of these needs to document the parameters.
485 static void detectNoDocumentedParams()
487 if (g_memberDef && Config_getBool("WARN_NO_PARAMDOC"))
489 LockingPtr<ArgumentList> al = g_memberDef->argumentList();
490 LockingPtr<ArgumentList> declAl = g_memberDef->declArgumentList();
491 QCString returnType = g_memberDef->typeString();
492 bool isPython = g_memberDef->getLanguage()==SrcLangExt_Python;
494 if (!g_memberDef->hasDocumentedParams() &&
497 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
498 g_memberDef->setHasDocumentedParams(TRUE);
500 else if (!g_memberDef->hasDocumentedParams())
502 bool allDoc=TRUE; // no paramater => all parameters are documented
503 if ( // member has parameters
504 al!=0 && // but the member has a parameter list
505 al->count()>0 // with at least one parameter (that is not void)
508 ArgumentListIterator ali(*al);
511 // see if all parameters have documentation
512 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
514 if (!a->name.isEmpty() && a->type!="void" &&
515 !(isPython && a->name=="self")
518 allDoc = !a->docs.isEmpty();
520 //printf("a->type=%s a->name=%s doc=%s\n",
521 // a->type.data(),a->name.data(),a->docs.data());
523 if (!allDoc && declAl!=0) // try declaration arguments as well
526 ArgumentListIterator ali(*declAl);
528 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
530 if (!a->name.isEmpty() && a->type!="void" &&
531 !(isPython && a->name=="self")
534 allDoc = !a->docs.isEmpty();
536 //printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data());
542 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
543 g_memberDef->setHasDocumentedParams(TRUE);
546 //printf("Member %s hasReturnCommand=%d\n",g_memberDef->name().data(),g_hasReturnCommand);
547 if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found
550 g_memberDef->setHasDocumentedReturnType(TRUE);
552 else if ( // see if return needs to documented
553 g_memberDef->hasDocumentedReturnType() ||
554 returnType.isEmpty() || // empty return type
555 returnType.find("void")!=-1 || // void return type
556 returnType.find("subroutine")!=-1 || // fortran subroutine
557 g_memberDef->isConstructor() || // a constructor
558 g_memberDef->isDestructor() // or destructor
561 g_memberDef->setHasDocumentedReturnType(TRUE);
568 //---------------------------------------------------------------------------
570 /*! Strips known html and tex extensions from \a text. */
571 static QCString stripKnownExtensions(const char *text)
573 QCString result=text;
574 if (result.right(4)==".tex")
576 result=result.left(result.length()-4);
578 else if (result.right(Doxygen::htmlFileExtension.length())==
579 QCString(Doxygen::htmlFileExtension))
581 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
587 //---------------------------------------------------------------------------
589 /*! Returns TRUE iff node n is a child of a preformatted node */
590 static bool insidePRE(DocNode *n)
594 if (n->isPreformatted()) return TRUE;
600 //---------------------------------------------------------------------------
602 /*! Returns TRUE iff node n is a child of a html list item node */
603 static bool insideLI(DocNode *n)
607 if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE;
613 //---------------------------------------------------------------------------
615 /*! Returns TRUE iff node n is a child of a unordered html list node */
616 static bool insideUL(DocNode *n)
620 if (n->kind()==DocNode::Kind_HtmlList &&
621 ((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE;
627 //---------------------------------------------------------------------------
629 /*! Returns TRUE iff node n is a child of a ordered html list node */
630 static bool insideOL(DocNode *n)
634 if (n->kind()==DocNode::Kind_HtmlList &&
635 ((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE;
641 //---------------------------------------------------------------------------
643 static bool insideTable(DocNode *n)
647 if (n->kind()==DocNode::Kind_HtmlTable) return TRUE;
653 //---------------------------------------------------------------------------
655 /*! Looks for a documentation block with name commandName in the current
656 * context (g_context). The resulting documentation string is
657 * put in pDoc, the definition in which the documentation was found is
659 * @retval TRUE if name was found.
660 * @retval FALSE if name was not found.
662 static bool findDocsForMemberOrCompound(const char *commandName,
667 //printf("findDocsForMemberOrCompound(%s)\n",commandName);
671 QCString cmdArg=substitute(commandName,"#","::");
672 int l=cmdArg.length();
673 if (l==0) return FALSE;
675 int funcStart=cmdArg.find('(');
682 // Check for the case of operator() and the like.
683 // beware of scenarios like operator()((foo)bar)
684 int secondParen = cmdArg.find('(', funcStart+1);
685 int leftParen = cmdArg.find(')', funcStart+1);
686 if (leftParen!=-1 && secondParen!=-1)
688 if (leftParen<secondParen)
690 funcStart=secondParen;
695 QCString name=removeRedundantWhiteSpace(cmdArg.left(funcStart));
696 QCString args=cmdArg.right(l-funcStart);
698 // try if the link is to a member
705 bool found = getDefs(
706 g_context.find('.')==-1?g_context.data():"", // `find('.') is a hack to detect files
708 args.isEmpty()?0:args.data(),
709 md,cd,fd,nd,gd,FALSE,0,TRUE);
710 //printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data());
713 *pDoc=md->documentation();
714 *pBrief=md->briefDescription();
720 int scopeOffset=g_context.length();
723 QCString fullName=cmdArg;
726 fullName.prepend(g_context.left(scopeOffset)+"::");
728 //printf("Trying fullName=`%s'\n",fullName.data());
730 // try class, namespace, group, page, file reference
731 cd = Doxygen::classSDict->find(fullName);
734 *pDoc=cd->documentation();
735 *pBrief=cd->briefDescription();
739 nd = Doxygen::namespaceSDict->find(fullName);
742 *pDoc=nd->documentation();
743 *pBrief=nd->briefDescription();
747 gd = Doxygen::groupSDict->find(cmdArg);
750 *pDoc=gd->documentation();
751 *pBrief=gd->briefDescription();
755 pd = Doxygen::pageSDict->find(cmdArg);
758 *pDoc=pd->documentation();
759 *pBrief=pd->briefDescription();
764 fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig);
765 if (fd && !ambig) // file
767 *pDoc=fd->documentation();
768 *pBrief=fd->briefDescription();
779 scopeOffset = g_context.findRev("::",scopeOffset-1);
780 if (scopeOffset==-1) scopeOffset=0;
782 } while (scopeOffset>=0);
787 //---------------------------------------------------------------------------
789 // forward declaration
790 static bool defaultHandleToken(DocNode *parent,int tok,
791 QList<DocNode> &children,bool
795 static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
796 const QCString &cmdName)
798 DBG(("handleStyleArgument(%s)\n",qPrint(cmdName)));
799 QCString tokenName = g_token->name;
800 int tok=doctokenizerYYlex();
801 if (tok!=TK_WHITESPACE)
803 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
807 while ((tok=doctokenizerYYlex()) &&
808 tok!=TK_WHITESPACE &&
814 static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
815 if (tok==TK_WORD && g_token->name.length()==1 &&
816 g_token->name.find(specialChar)!=-1)
818 // special character that ends the markup command
821 if (!defaultHandleToken(parent,tok,children))
826 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command \\%s as the argument of a \\%s command",
827 qPrint(g_token->name),qPrint(cmdName));
830 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found while handling command %s",
831 qPrint(g_token->name),qPrint(cmdName));
834 if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
835 { // ignore </li> as the end of a style command
841 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s while handling command %s",
842 tokToString(tok),qPrint(cmdName));
848 DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(cmdName),tok));
849 return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
853 /*! Called when a style change starts. For instance a \<b\> command is
856 static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
857 DocStyleChange::Style s,const HtmlAttribList *attribs)
859 DBG(("HandleStyleEnter\n"));
860 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs);
862 g_styleStack.push(sc);
865 /*! Called when a style change ends. For instance a \</b\> command is
868 static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
869 DocStyleChange::Style s,const char *tagName)
871 DBG(("HandleStyleLeave\n"));
872 if (g_styleStack.isEmpty() || // no style change
873 g_styleStack.top()->style()!=s || // wrong style change
874 g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
877 if (g_styleStack.isEmpty())
879 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> tag without matching <%s>",
880 qPrint(tagName),qPrint(tagName));
882 else if (g_styleStack.top()->style()!=s)
884 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> tag while expecting </%s>",
885 qPrint(tagName),qPrint(g_styleStack.top()->styleString()));
889 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> at different nesting level (%d) than expected (%d)",
890 qPrint(tagName),g_nodeStack.count(),g_styleStack.top()->position());
893 else // end the section
895 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE);
901 /*! Called at the end of a paragraph to close all open style changes
902 * (e.g. a <b> without a </b>). The closed styles are pushed onto a stack
903 * and entered again at the start of a new paragraph.
905 static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
907 if (!g_styleStack.isEmpty())
909 DocStyleChange *sc = g_styleStack.top();
910 while (sc && sc->position()>=g_nodeStack.count())
911 { // there are unclosed style modifiers in the paragraph
912 children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
913 g_initialStyleStack.push(sc);
915 sc = g_styleStack.top();
920 static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
923 while ((sc=g_initialStyleStack.pop()))
925 handleStyleEnter(parent,children,sc->style(),&sc->attribs());
929 static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
931 HtmlAttribListIterator li(tagHtmlAttribs);
934 int retval = RetVal_OK;
935 for (li.toFirst();(opt=li.current());++li,++index)
937 if (opt->name=="name") // <a name=label> tag
939 if (!opt->value.isEmpty())
941 DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE);
942 children.append(anc);
943 break; // stop looking for other tag attribs
947 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <a> tag with name option but without value!");
950 else if (opt->name=="href") // <a href=url>..</a> tag
953 HtmlAttribList attrList = tagHtmlAttribs;
954 // and remove the href attribute
955 bool result = attrList.remove(index);
957 DocHRef *href = new DocHRef(parent,attrList,opt->value,g_relPath);
958 children.append(href);
959 g_insideHtmlLink=TRUE;
960 retval = href->parse();
961 g_insideHtmlLink=FALSE;
964 else // unsupported option for tag a
971 const char *DocStyleChange::styleString() const
975 case DocStyleChange::Bold: return "b";
976 case DocStyleChange::Italic: return "em";
977 case DocStyleChange::Code: return "code";
978 case DocStyleChange::Center: return "center";
979 case DocStyleChange::Small: return "small";
980 case DocStyleChange::Subscript: return "subscript";
981 case DocStyleChange::Superscript: return "superscript";
982 case DocStyleChange::Preformatted: return "pre";
983 case DocStyleChange::Div: return "div";
984 case DocStyleChange::Span: return "span";
989 static void handleUnclosedStyleCommands()
991 if (!g_initialStyleStack.isEmpty())
993 DocStyleChange *sc = g_initialStyleStack.top();
994 g_initialStyleStack.pop();
995 handleUnclosedStyleCommands();
996 warn_doc_error(g_fileName,doctokenizerYYlineno,
997 "warning: end of comment block while expecting "
998 "command </%s>",qPrint(sc->styleString()));
1002 static void handleLinkedWord(DocNode *parent,QList<DocNode> &children)
1004 QCString name = linkToText(SrcLangExt_Unknown,g_token->name,TRUE);
1005 static bool autolinkSupport = Config_getBool("AUTOLINK_SUPPORT");
1006 if (!autolinkSupport) // no autolinking -> add as normal word
1008 children.append(new DocWord(parent,name));
1012 // ------- try to turn the word 'name' into a link
1014 Definition *compound=0;
1015 MemberDef *member=0;
1016 int len = g_token->name.length();
1019 FileDef *fd = findFileDef(Doxygen::inputNameDict,g_fileName,ambig);
1020 //printf("handleLinkedWord(%s) g_context=%s\n",g_token->name.data(),g_context.data());
1021 if (!g_insideHtmlLink &&
1022 (resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member,TRUE,fd,TRUE)
1023 || (!g_context.isEmpty() && // also try with global scope
1024 resolveRef("",g_token->name,g_inSeeBlock,&compound,&member,FALSE,0,TRUE))
1028 //printf("resolveRef %s = %p (linkable?=%d)\n",qPrint(g_token->name),member,member ? member->isLinkable() : FALSE);
1029 if (member && member->isLinkable()) // member link
1031 if (member->isObjCMethod())
1033 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
1034 name = member->objCMethodName(localLink,g_inSeeBlock);
1037 DocLinkedWord(parent,name,
1038 member->getReference(),
1039 member->getOutputFileBase(),
1041 member->briefDescriptionAsTooltip()
1045 else if (compound->isLinkable()) // compound link
1047 QCString anchor = compound->anchor();
1048 if (compound->definitionType()==Definition::TypeFile)
1052 else if (compound->definitionType()==Definition::TypeGroup)
1054 name=((GroupDef*)compound)->groupTitle();
1057 DocLinkedWord(parent,name,
1058 compound->getReference(),
1059 compound->getOutputFileBase(),
1061 compound->briefDescriptionAsTooltip()
1065 else if (compound->definitionType()==Definition::TypeFile &&
1066 ((FileDef*)compound)->generateSourceFile()
1067 ) // undocumented file that has source code we can link to
1070 DocLinkedWord(parent,g_token->name,
1071 compound->getReference(),
1072 compound->getSourceFileBase(),
1074 compound->briefDescriptionAsTooltip()
1078 else // not linkable
1080 children.append(new DocWord(parent,name));
1083 else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':')
1085 // special case, where matching Foo: fails to be an Obj-C reference,
1086 // but Foo itself might be linkable.
1087 g_token->name=g_token->name.left(len-1);
1088 handleLinkedWord(parent,children);
1089 children.append(new DocWord(parent,":"));
1091 else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p")))
1093 // special case 2, where the token name is not a class, but could
1094 // be a Obj-C protocol
1096 DocLinkedWord(parent,name,
1098 cd->getOutputFileBase(),
1100 cd->briefDescriptionAsTooltip()
1103 // else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-g")))
1105 // // special case 3, where the token name is not a class, but could
1106 // // be a C# generic
1107 // children.append(new
1108 // DocLinkedWord(parent,name,
1109 // cd->getReference(),
1110 // cd->getOutputFileBase(),
1112 // cd->briefDescriptionAsTooltip()
1115 else // normal non-linkable word
1117 if (g_token->name.left(1)=="#" || g_token->name.left(2)=="::")
1119 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: explicit link request to '%s' could not be resolved",qPrint(name));
1120 children.append(new DocWord(parent,g_token->name));
1124 children.append(new DocWord(parent,name));
1129 static void handleParameterType(DocNode *parent,QList<DocNode> &children,const QCString ¶mTypes)
1131 QCString name = g_token->name;
1134 while ((i=paramTypes.find('|',p))!=-1)
1136 g_token->name = paramTypes.mid(p,i-p);
1137 handleLinkedWord(parent,children);
1140 g_token->name = paramTypes.mid(p);
1141 handleLinkedWord(parent,children);
1142 g_token->name = name;
1145 static DocInternalRef *handleInternalRef(DocNode *parent)
1147 //printf("CMD_INTERNALREF\n");
1148 int tok=doctokenizerYYlex();
1149 QCString tokenName = g_token->name;
1150 if (tok!=TK_WHITESPACE)
1152 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
1156 doctokenizerYYsetStateInternalRef();
1157 tok=doctokenizerYYlex(); // get the reference id
1158 if (tok!=TK_WORD && tok!=TK_LNKWORD)
1160 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
1161 tokToString(tok),qPrint(tokenName));
1164 return new DocInternalRef(parent,g_token->name);
1167 static DocAnchor *handleAnchor(DocNode *parent)
1169 int tok=doctokenizerYYlex();
1170 if (tok!=TK_WHITESPACE)
1172 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
1173 qPrint(g_token->name));
1176 doctokenizerYYsetStateAnchor();
1177 tok=doctokenizerYYlex();
1180 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
1181 "argument of command %s",qPrint(g_token->name));
1184 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
1186 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
1187 tokToString(tok),qPrint(g_token->name));
1190 doctokenizerYYsetStatePara();
1191 return new DocAnchor(parent,g_token->name,FALSE);
1195 /* Helper function that deals with the most common tokens allowed in
1196 * title like sections.
1197 * @param parent Parent node, owner of the children list passed as
1198 * the third argument.
1199 * @param tok The token to process.
1200 * @param children The list of child nodes to which the node representing
1201 * the token can be added.
1202 * @param handleWord Indicates if word token should be processed
1203 * @retval TRUE The token was handled.
1204 * @retval FALSE The token was not handled.
1206 static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool
1209 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
1210 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
1211 tok==TK_COMMAND || tok==TK_HTMLTAG
1214 DBG((" name=%s",qPrint(g_token->name)));
1218 QCString tokenName = g_token->name;
1222 switch (Mappers::cmdMapper->map(tokenName))
1225 children.append(new DocSymbol(parent,DocSymbol::BSlash));
1228 children.append(new DocSymbol(parent,DocSymbol::At));
1231 children.append(new DocSymbol(parent,DocSymbol::Less));
1234 children.append(new DocSymbol(parent,DocSymbol::Greater));
1237 children.append(new DocSymbol(parent,DocSymbol::Amp));
1240 children.append(new DocSymbol(parent,DocSymbol::Dollar));
1243 children.append(new DocSymbol(parent,DocSymbol::Hash));
1246 children.append(new DocSymbol(parent,DocSymbol::DoubleColon));
1249 children.append(new DocSymbol(parent,DocSymbol::Percent));
1252 children.append(new DocSymbol(parent,DocSymbol::Quot));
1256 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
1257 tok=handleStyleArgument(parent,children,tokenName);
1258 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
1259 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1260 if (tok==TK_NEWPARA) goto handlepara;
1261 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1263 DBG(("CMD_EMPHASIS: reparsing command %s\n",qPrint(g_token->name)));
1270 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
1271 tok=handleStyleArgument(parent,children,tokenName);
1272 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
1273 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1274 if (tok==TK_NEWPARA) goto handlepara;
1275 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1277 DBG(("CMD_BOLD: reparsing command %s\n",qPrint(g_token->name)));
1284 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE));
1285 tok=handleStyleArgument(parent,children,tokenName);
1286 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE));
1287 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1288 if (tok==TK_NEWPARA) goto handlepara;
1289 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1291 DBG(("CMD_CODE: reparsing command %s\n",qPrint(g_token->name)));
1298 doctokenizerYYsetStateHtmlOnly();
1299 tok = doctokenizerYYlex();
1300 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
1301 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: htmlonly section ended without end marker");
1302 doctokenizerYYsetStatePara();
1307 doctokenizerYYsetStateManOnly();
1308 tok = doctokenizerYYlex();
1309 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
1310 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: manonly section ended without end marker");
1311 doctokenizerYYsetStatePara();
1316 doctokenizerYYsetStateRtfOnly();
1317 tok = doctokenizerYYlex();
1318 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::RtfOnly,g_isExample,g_exampleName));
1319 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: rtfonly section ended without end marker");
1320 doctokenizerYYsetStatePara();
1325 doctokenizerYYsetStateLatexOnly();
1326 tok = doctokenizerYYlex();
1327 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
1328 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: latexonly section ended without end marker",doctokenizerYYlineno);
1329 doctokenizerYYsetStatePara();
1334 doctokenizerYYsetStateXmlOnly();
1335 tok = doctokenizerYYlex();
1336 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
1337 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: xmlonly section ended without end marker",doctokenizerYYlineno);
1338 doctokenizerYYsetStatePara();
1343 DocFormula *form=new DocFormula(parent,g_token->id);
1344 children.append(form);
1349 DocAnchor *anchor = handleAnchor(parent);
1352 children.append(anchor);
1356 case CMD_INTERNALREF:
1358 DocInternalRef *ref = handleInternalRef(parent);
1361 children.append(ref);
1364 doctokenizerYYsetStatePara();
1373 switch (Mappers::htmlTagMapper->map(tokenName))
1376 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <div> tag in heading\n");
1379 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <pre> tag in heading\n");
1382 if (!g_token->endTag)
1384 handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs);
1388 handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
1393 if (!g_token->endTag)
1395 handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs);
1399 handleStyleLeave(parent,children,DocStyleChange::Code,tokenName);
1403 if (!g_token->endTag)
1405 handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs);
1409 handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName);
1413 if (!g_token->endTag)
1415 handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs);
1419 handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName);
1423 if (!g_token->endTag)
1425 handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs);
1429 handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName);
1433 if (!g_token->endTag)
1435 handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs);
1439 handleStyleLeave(parent,children,DocStyleChange::Center,tokenName);
1443 if (!g_token->endTag)
1445 handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs);
1449 handleStyleLeave(parent,children,DocStyleChange::Small,tokenName);
1461 DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName,&letter);
1462 if (s!=DocSymbol::Unknown)
1464 children.append(new DocSymbol(parent,s,letter));
1475 if (insidePRE(parent) || !children.isEmpty())
1477 children.append(new DocWhiteSpace(parent,g_token->chars));
1483 handleLinkedWord(parent,children);
1491 children.append(new DocWord(parent,g_token->name));
1497 if (g_insideHtmlLink)
1499 children.append(new DocWord(parent,g_token->name));
1503 children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr));
1513 //---------------------------------------------------------------------------
1515 DocSymbol::SymType DocSymbol::decodeSymbol(const QCString &symName,char *letter)
1517 int l=symName.length();
1518 DBG(("decodeSymbol(%s) l=%d\n",qPrint(symName),l));
1519 if (symName=="©") return DocSymbol::Copy;
1520 else if (symName=="™") return DocSymbol::Tm;
1521 else if (symName=="&tm;") return DocSymbol::Tm; // alias for ™
1522 else if (symName=="®") return DocSymbol::Reg;
1523 else if (symName=="<") return DocSymbol::Less;
1524 else if (symName==">") return DocSymbol::Greater;
1525 else if (symName=="&") return DocSymbol::Amp;
1526 else if (symName=="'") return DocSymbol::Apos;
1527 else if (symName==""") return DocSymbol::Quot;
1528 else if (symName=="‘") return DocSymbol::Lsquo;
1529 else if (symName=="’") return DocSymbol::Rsquo;
1530 else if (symName=="“") return DocSymbol::Ldquo;
1531 else if (symName=="”") return DocSymbol::Rdquo;
1532 else if (symName=="–") return DocSymbol::Ndash;
1533 else if (symName=="—") return DocSymbol::Mdash;
1534 else if (symName=="ß") return DocSymbol::Szlig;
1535 else if (symName==" ") return DocSymbol::Nbsp;
1536 else if (symName=="Æ") return DocSymbol::AElig;
1537 else if (symName=="æ") return DocSymbol::Aelig;
1538 else if (symName=="Γ") return DocSymbol::GrkGamma;
1539 else if (symName=="Δ") return DocSymbol::GrkDelta;
1540 else if (symName=="Θ") return DocSymbol::GrkTheta;
1541 else if (symName=="Λ") return DocSymbol::GrkLambda;
1542 else if (symName=="Ξ") return DocSymbol::GrkXi;
1543 else if (symName=="Π") return DocSymbol::GrkPi;
1544 else if (symName=="Σ") return DocSymbol::GrkSigma;
1545 else if (symName=="Υ") return DocSymbol::GrkUpsilon;
1546 else if (symName=="Φ") return DocSymbol::GrkPhi;
1547 else if (symName=="Ψ") return DocSymbol::GrkPsi;
1548 else if (symName=="Ω") return DocSymbol::GrkOmega;
1549 else if (symName=="α") return DocSymbol::Grkalpha;
1550 else if (symName=="β") return DocSymbol::Grkbeta;
1551 else if (symName=="γ") return DocSymbol::Grkgamma;
1552 else if (symName=="δ") return DocSymbol::Grkdelta;
1553 else if (symName=="ε") return DocSymbol::Grkepsilon;
1554 else if (symName=="ζ") return DocSymbol::Grkzeta;
1555 else if (symName=="η") return DocSymbol::Grketa;
1556 else if (symName=="θ") return DocSymbol::Grktheta;
1557 else if (symName=="ι") return DocSymbol::Grkiota;
1558 else if (symName=="κ") return DocSymbol::Grkkappa;
1559 else if (symName=="λ") return DocSymbol::Grklambda;
1560 else if (symName=="μ") return DocSymbol::Grkmu;
1561 else if (symName=="ν") return DocSymbol::Grknu;
1562 else if (symName=="ξ") return DocSymbol::Grkxi;
1563 else if (symName=="π") return DocSymbol::Grkpi;
1564 else if (symName=="ρ") return DocSymbol::Grkrho;
1565 else if (symName=="σ") return DocSymbol::Grksigma;
1566 else if (symName=="τ") return DocSymbol::Grktau;
1567 else if (symName=="υ") return DocSymbol::Grkupsilon;
1568 else if (symName=="φ") return DocSymbol::Grkphi;
1569 else if (symName=="χ") return DocSymbol::Grkchi;
1570 else if (symName=="ψ") return DocSymbol::Grkpsi;
1571 else if (symName=="ω") return DocSymbol::Grkomega;
1572 else if (symName=="ς") return DocSymbol::Grkvarsigma;
1573 else if (symName=="§") return DocSymbol::Section;
1574 else if (symName=="°") return DocSymbol::Degree;
1575 else if (symName=="′") return DocSymbol::Prime;
1576 else if (symName=="″") return DocSymbol::DoublePrime;
1577 else if (symName=="∞") return DocSymbol::Infinity;
1578 else if (symName=="∅") return DocSymbol::EmptySet;
1579 else if (symName=="±") return DocSymbol::PlusMinus;
1580 else if (symName=="×") return DocSymbol::Times;
1581 else if (symName=="−") return DocSymbol::Minus;
1582 else if (symName=="⋅") return DocSymbol::CenterDot;
1583 else if (symName=="∂") return DocSymbol::Partial;
1584 else if (symName=="∇") return DocSymbol::Nabla;
1585 else if (symName=="√") return DocSymbol::SquareRoot;
1586 else if (symName=="⊥") return DocSymbol::Perpendicular;
1587 else if (symName=="∑") return DocSymbol::Sum;
1588 else if (symName=="∫") return DocSymbol::Integral;
1589 else if (symName=="∏") return DocSymbol::Product;
1590 else if (symName=="∼") return DocSymbol::Similar;
1591 else if (symName=="≈") return DocSymbol::Approx;
1592 else if (symName=="≠") return DocSymbol::NotEqual;
1593 else if (symName=="≡") return DocSymbol::Equivalent;
1594 else if (symName=="∝") return DocSymbol::Proportional;
1595 else if (symName=="≤") return DocSymbol::LessEqual;
1596 else if (symName=="≥") return DocSymbol::GreaterEqual;
1597 else if (symName=="←") return DocSymbol::LeftArrow;
1598 else if (symName=="→") return DocSymbol::RightArrow;
1599 else if (symName=="∈") return DocSymbol::SetIn;
1600 else if (symName=="∉") return DocSymbol::SetNotIn;
1601 else if (symName=="⌈") return DocSymbol::LeftCeil;
1602 else if (symName=="⌉") return DocSymbol::RightCeil;
1603 else if (symName=="⌊") return DocSymbol::LeftFloor;
1604 else if (symName=="⌋") return DocSymbol::RightFloor;
1605 else if (l==6 && symName.right(4)=="uml;")
1607 *letter=symName.at(1);
1608 return DocSymbol::Uml;
1610 else if (l==8 && symName.right(6)=="acute;")
1612 *letter=symName.at(1);
1613 return DocSymbol::Acute;
1615 else if (l==8 && symName.right(6)=="grave;")
1617 *letter=symName.at(1);
1618 return DocSymbol::Grave;
1620 else if (l==7 && symName.right(5)=="circ;")
1622 *letter=symName.at(1);
1623 return DocSymbol::Circ;
1625 else if (l==8 && symName.right(6)=="tilde;")
1627 *letter=symName.at(1);
1628 return DocSymbol::Tilde;
1630 else if (l==8 && symName.right(6)=="cedil;")
1632 *letter=symName.at(1);
1633 return DocSymbol::Cedil;
1635 else if (l==7 && symName.right(5)=="ring;")
1637 *letter=symName.at(1);
1638 return DocSymbol::Ring;
1640 else if (l==8 && symName.right(6)=="slash;")
1642 *letter=symName.at(1);
1643 return DocSymbol::Slash;
1645 return DocSymbol::Unknown;
1648 //---------------------------------------------------------------------------
1650 static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
1651 const QCString &doc)
1653 int retval = RetVal_OK;
1655 if (doc.isEmpty()) return retval;
1657 doctokenizerYYinit(doc,g_fileName);
1659 // first parse any number of paragraphs
1662 if (!children.isEmpty() && children.last()->kind()==DocNode::Kind_Para)
1663 { // last child item was a paragraph
1664 lastPar = (DocPara*)children.last();
1669 DocPara *par = new DocPara(parent);
1670 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1671 retval=par->parse();
1672 if (!par->isEmpty())
1674 children.append(par);
1675 if (lastPar) lastPar->markLast(FALSE);
1682 } while (retval==TK_NEWPARA);
1683 if (lastPar) lastPar->markLast();
1685 //printf("internalValidateParsingDoc: %p: isFirst=%d isLast=%d\n",
1686 // lastPar,lastPar?lastPar->isFirst():-1,lastPar?lastPar->isLast():-1);
1691 //---------------------------------------------------------------------------
1693 static void readTextFileByName(const QCString &file,QCString &text)
1695 QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
1696 char *s=examplePathList.first();
1699 QCString absFileName = QCString(s)+portable_pathSeparator()+file;
1700 QFileInfo fi(absFileName);
1703 text = fileToString(absFileName,Config_getBool("FILTER_SOURCE_FILES"));
1706 s=examplePathList.next();
1709 // as a fallback we also look in the exampleNameDict
1712 if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
1714 text = fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES"));
1718 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included file name %s is ambiguous"
1719 "Possible candidates:\n%s",qPrint(file),
1720 qPrint(showFileDefMatches(Doxygen::exampleNameDict,file))
1725 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included file %s is not found. "
1726 "Check your EXAMPLE_PATH",qPrint(file));
1730 //---------------------------------------------------------------------------
1732 DocWord::DocWord(DocNode *parent,const QCString &word) :
1736 //printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
1737 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1739 Doxygen::searchIndex->addWord(word,FALSE);
1743 //---------------------------------------------------------------------------
1745 DocLinkedWord::DocLinkedWord(DocNode *parent,const QCString &word,
1746 const QCString &ref,const QCString &file,
1747 const QCString &anchor,const QCString &tooltip) :
1748 m_word(word), m_ref(ref),
1749 m_file(file), m_relPath(g_relPath), m_anchor(anchor),
1753 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
1754 // word.data(),g_searchUrl.data(),tooltip.data());
1755 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1757 Doxygen::searchIndex->addWord(word,FALSE);
1761 //---------------------------------------------------------------------------
1763 DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
1768 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Empty anchor label");
1770 if (newAnchor) // found <a name="label">
1774 else if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix)
1776 CiteInfo *cite = Doxygen::citeDict->find(id.mid(CiteConsts::anchorPrefix.length()));
1779 m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE);
1784 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid cite anchor id `%s'",qPrint(id));
1785 m_anchor = "invalid";
1789 else // found \anchor label
1791 SectionInfo *sec = Doxygen::sectionDict[id];
1794 //printf("Found anchor %s\n",id.data());
1795 m_file = sec->fileName;
1796 m_anchor = sec->label;
1797 if (g_sectionDict && g_sectionDict->find(id)==0)
1799 //printf("Inserting in dictionary!\n");
1800 g_sectionDict->append(id,sec);
1805 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid anchor id `%s'",qPrint(id));
1806 m_anchor = "invalid";
1812 //---------------------------------------------------------------------------
1814 DocVerbatim::DocVerbatim(DocNode *parent,const QCString &context,
1815 const QCString &text, Type t,bool isExample,
1816 const QCString &exampleFile,const QCString &lang)
1817 : m_context(context), m_text(text), m_type(t),
1818 m_isExample(isExample), m_exampleFile(exampleFile),
1819 m_relPath(g_relPath), m_lang(lang)
1825 //---------------------------------------------------------------------------
1827 void DocInclude::parse()
1829 DBG(("DocInclude::parse(file=%s,text=%s)\n",qPrint(m_file),qPrint(m_text)));
1837 readTextFileByName(m_file,m_text);
1838 g_includeFileText = m_text;
1839 g_includeFileOffset = 0;
1840 g_includeFileLength = m_text.length();
1841 //printf("g_includeFile=<<%s>>\n",g_includeFileText.data());
1846 readTextFileByName(m_file,m_text);
1849 readTextFileByName(m_file,m_text);
1850 // check here for the existence of the blockId inside the file, so we
1851 // only generate the warning once.
1853 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
1855 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: block marked with %s for \\snippet should appear twice in file %s, found it %d times\n",
1856 m_blockId.data(),m_file.data(),count);
1862 //---------------------------------------------------------------------------
1864 void DocIncOperator::parse()
1866 const char *p = g_includeFileText;
1867 uint l = g_includeFileLength;
1868 uint o = g_includeFileOffset;
1869 DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",qPrint(p),o,l));
1871 bool nonEmpty = FALSE;
1880 if (nonEmpty) break; // we have a pattern to match
1881 so=o+1; // no pattern, skip empty line
1883 else if (!isspace((uchar)c)) // no white space char
1889 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1891 m_text = g_includeFileText.mid(so,o-so);
1892 DBG(("DocIncOperator::parse() Line: %s\n",qPrint(m_text)));
1894 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1905 if (nonEmpty) break; // we have a pattern to match
1906 so=o+1; // no pattern, skip empty line
1908 else if (!isspace((uchar)c)) // no white space char
1914 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1916 m_text = g_includeFileText.mid(so,o-so);
1917 DBG(("DocIncOperator::parse() SkipLine: %s\n",qPrint(m_text)));
1920 o++; // skip new line
1922 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1933 if (nonEmpty) break; // we have a pattern to match
1934 so=o+1; // no pattern, skip empty line
1936 else if (!isspace((uchar)c)) // no white space char
1942 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1946 o++; // skip new line
1948 g_includeFileOffset = so; // set pointer to start of new line
1960 if (nonEmpty) break; // we have a pattern to match
1961 so=o+1; // no pattern, skip empty line
1963 else if (!isspace((uchar)c)) // no white space char
1969 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1971 m_text = g_includeFileText.mid(bo,o-bo);
1972 DBG(("DocIncOperator::parse() Until: %s\n",qPrint(m_text)));
1975 o++; // skip new line
1977 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1982 //---------------------------------------------------------------------------
1984 void DocCopy::parse(QList<DocNode> &children)
1988 if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
1990 if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
1992 bool hasParamCommand = g_hasParamCommand;
1993 bool hasReturnCommand = g_hasReturnCommand;
1994 QDict<void> paramsFound = g_paramsFound;
1995 //printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
1996 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
1998 docParserPushContext(FALSE);
2000 if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
2002 if (def->getOuterScope()!=Doxygen::globalScope)
2004 g_context=def->getOuterScope()->name();
2007 else if (def!=Doxygen::globalScope)
2009 g_context=def->name();
2011 g_styleStack.clear();
2012 g_nodeStack.clear();
2013 g_paramsFound.clear();
2014 g_copyStack.append(def);
2015 // make sure the descriptions end with a newline, so the parser will correctly
2016 // handle them in all cases.
2017 //printf("doc='%s'\n",doc.data());
2018 //printf("brief='%s'\n",brief.data());
2022 internalValidatingParseDoc(m_parent,children,brief);
2024 //printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2025 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2026 hasParamCommand = hasParamCommand || g_hasParamCommand;
2027 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
2028 QDictIterator<void> it(g_paramsFound);
2030 for (;(item=it.current());++it)
2032 paramsFound.insert(it.currentKey(),it.current());
2038 internalValidatingParseDoc(m_parent,children,doc);
2040 //printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2041 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2042 hasParamCommand = hasParamCommand || g_hasParamCommand;
2043 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
2044 QDictIterator<void> it(g_paramsFound);
2046 for (;(item=it.current());++it)
2048 paramsFound.insert(it.currentKey(),it.current());
2051 g_copyStack.remove(def);
2052 ASSERT(g_styleStack.isEmpty());
2053 ASSERT(g_nodeStack.isEmpty());
2054 docParserPopContext(TRUE);
2056 g_hasParamCommand = hasParamCommand;
2057 g_hasReturnCommand = hasReturnCommand;
2058 g_paramsFound = paramsFound;
2060 //printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2061 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2063 else // oops, recursion
2065 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: recursive call chain of \\copydoc commands detected at %d\n",
2066 doctokenizerYYlineno);
2071 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: target %s of \\copydoc command not found",
2076 //---------------------------------------------------------------------------
2078 DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) :
2079 m_id(id), m_key(key), m_relPath(g_relPath)
2084 bool DocXRefItem::parse()
2087 RefList *refList = Doxygen::xrefLists->find(m_key);
2090 // either not a built-in list or the list is enabled
2091 (m_key!="todo" || Config_getBool("GENERATE_TODOLIST")) &&
2092 (m_key!="test" || Config_getBool("GENERATE_TESTLIST")) &&
2093 (m_key!="bug" || Config_getBool("GENERATE_BUGLIST")) &&
2094 (m_key!="deprecated" || Config_getBool("GENERATE_DEPRECATEDLIST"))
2098 RefItem *item = refList->getRefItem(m_id);
2102 if (g_memberDef && g_memberDef->name().at(0)=='@')
2104 m_file = "@"; // can't cross reference anonymous enum
2109 m_file = convertNameToFile(refList->listName(),FALSE,TRUE);
2110 m_anchor = item->listAnchor;
2112 m_title = refList->sectionTitle();
2113 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
2114 // m_file.data(),m_anchor.data(),m_title.data());
2116 if (!item->text.isEmpty())
2118 docParserPushContext();
2119 internalValidatingParseDoc(this,m_children,item->text);
2120 docParserPopContext();
2128 //---------------------------------------------------------------------------
2130 DocFormula::DocFormula(DocNode *parent,int id) :
2131 m_relPath(g_relPath)
2135 formCmd.sprintf("\\form#%d",id);
2136 Formula *formula=Doxygen::formulaNameDict[formCmd];
2139 m_id = formula->getId();
2140 m_name.sprintf("form_%d",m_id);
2141 m_text = formula->getFormulaText();
2145 //---------------------------------------------------------------------------
2147 //int DocLanguage::parse()
2150 // DBG(("DocLanguage::parse() start\n"));
2151 // g_nodeStack.push(this);
2153 // // parse one or more paragraphs
2154 // bool isFirst=TRUE;
2158 // par = new DocPara(this);
2159 // if (isFirst) { par->markFirst(); isFirst=FALSE; }
2160 // m_children.append(par);
2161 // retval=par->parse();
2163 // while (retval==TK_NEWPARA);
2164 // if (par) par->markLast();
2166 // DBG(("DocLanguage::parse() end\n"));
2167 // DocNode *n = g_nodeStack.pop();
2172 //---------------------------------------------------------------------------
2174 void DocSecRefItem::parse()
2176 DBG(("DocSecRefItem::parse() start\n"));
2177 g_nodeStack.push(this);
2179 doctokenizerYYsetStateTitle();
2181 while ((tok=doctokenizerYYlex()))
2183 if (!defaultHandleToken(this,tok,m_children))
2188 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\refitem",
2189 qPrint(g_token->name));
2192 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2193 qPrint(g_token->name));
2196 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2202 doctokenizerYYsetStatePara();
2203 handlePendingStyleCommands(this,m_children);
2206 if (!m_target.isEmpty())
2208 sec=Doxygen::sectionDict[m_target];
2211 m_file = sec->fileName;
2212 m_anchor = sec->label;
2213 if (g_sectionDict && g_sectionDict->find(m_target)==0)
2215 g_sectionDict->append(m_target,sec);
2220 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: reference to unknown section %s",
2226 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: reference to empty target");
2229 DBG(("DocSecRefItem::parse() end\n"));
2230 DocNode *n = g_nodeStack.pop();
2234 //---------------------------------------------------------------------------
2236 void DocSecRefList::parse()
2238 DBG(("DocSecRefList::parse() start\n"));
2239 g_nodeStack.push(this);
2241 int tok=doctokenizerYYlex();
2243 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
2247 if (tok==TK_COMMAND)
2249 switch (Mappers::cmdMapper->map(g_token->name))
2251 case CMD_SECREFITEM:
2253 int tok=doctokenizerYYlex();
2254 if (tok!=TK_WHITESPACE)
2256 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after \\refitem command");
2259 tok=doctokenizerYYlex();
2260 if (tok!=TK_WORD && tok!=TK_LNKWORD)
2262 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of \\refitem",
2267 DocSecRefItem *item = new DocSecRefItem(this,g_token->name);
2268 m_children.append(item);
2272 case CMD_ENDSECREFLIST:
2275 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\secreflist",
2276 qPrint(g_token->name));
2280 else if (tok==TK_WHITESPACE)
2282 // ignore whitespace
2286 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s inside section reference list",
2290 tok=doctokenizerYYlex();
2294 DBG(("DocSecRefList::parse() end\n"));
2295 DocNode *n = g_nodeStack.pop();
2299 //---------------------------------------------------------------------------
2301 DocInternalRef::DocInternalRef(DocNode *parent,const QCString &ref)
2302 : m_relPath(g_relPath)
2305 int i=ref.find('#');
2308 m_anchor = ref.right(ref.length()-i-1);
2309 m_file = ref.left(i);
2317 void DocInternalRef::parse()
2319 g_nodeStack.push(this);
2320 DBG(("DocInternalRef::parse() start\n"));
2323 while ((tok=doctokenizerYYlex()))
2325 if (!defaultHandleToken(this,tok,m_children))
2330 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\ref",
2331 qPrint(g_token->name));
2334 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2335 qPrint(g_token->name));
2338 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2345 handlePendingStyleCommands(this,m_children);
2346 DBG(("DocInternalRef::parse() end\n"));
2347 DocNode *n=g_nodeStack.pop();
2351 //---------------------------------------------------------------------------
2353 DocRef::DocRef(DocNode *parent,const QCString &target,const QCString &context) :
2354 m_refToSection(FALSE), m_refToAnchor(FALSE), m_isSubPage(FALSE)
2357 Definition *compound = 0;
2359 //printf("DocRef::DocRef(target=%s,context=%s)\n",target.data(),context.data());
2360 ASSERT(!target.isEmpty());
2361 m_relPath = g_relPath;
2362 SectionInfo *sec = Doxygen::sectionDict[target];
2363 if (sec) // ref to section or anchor
2366 if (sec->type==SectionInfo::Page)
2368 pd = Doxygen::pageSDict->find(target);
2370 m_text = sec->title;
2371 if (m_text.isEmpty()) m_text = sec->label;
2374 m_file = stripKnownExtensions(sec->fileName);
2375 m_refToAnchor = sec->type==SectionInfo::Anchor;
2376 m_refToSection = sec->type!=SectionInfo::Anchor;
2377 m_isSubPage = pd && pd->hasParentPage();
2378 if (sec->type!=SectionInfo::Page || m_isSubPage) m_anchor = sec->label;
2379 //printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d type=%d\n",
2380 // m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor,sec->type);
2383 else if (resolveLink(context,target,TRUE,&compound,anchor))
2385 bool isFile = compound ?
2386 (compound->definitionType()==Definition::TypeFile ||
2387 compound->definitionType()==Definition::TypePage ? TRUE : FALSE) :
2389 m_text = linkToText(compound?compound->getLanguage():SrcLangExt_Unknown,target,isFile);
2391 if (compound && compound->isLinkable()) // ref to compound
2393 if (anchor.isEmpty() && /* compound link */
2394 compound->definitionType()==Definition::TypeGroup && /* is group */
2395 ((GroupDef *)compound)->groupTitle() /* with title */
2398 m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link
2400 else if (compound->definitionType()==Definition::TypeMember &&
2401 ((MemberDef*)compound)->isObjCMethod())
2403 // Objective C Method
2404 MemberDef *member = (MemberDef*)compound;
2405 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
2406 m_text = member->objCMethodName(localLink,g_inSeeBlock);
2409 m_file = compound->getOutputFileBase();
2410 m_ref = compound->getReference();
2411 //printf("isFile=%d compound=%s (%d)\n",isFile,compound->name().data(),
2412 // compound->definitionType());
2415 else if (compound->definitionType()==Definition::TypeFile &&
2416 ((FileDef*)compound)->generateSourceFile()
2417 ) // undocumented file that has source code we can link to
2419 m_file = compound->getSourceFileBase();
2420 m_ref = compound->getReference();
2425 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve reference to `%s' for \\ref command",
2429 static void flattenParagraphs(DocNode *root,QList<DocNode> &children)
2431 QListIterator<DocNode> li(children);
2432 QList<DocNode> newChildren;
2434 for (li.toFirst();(dn=li.current());++li)
2436 if (dn->kind()==DocNode::Kind_Para)
2438 DocPara *para = (DocPara*)dn;
2439 QList<DocNode> ¶Children = para->children();
2440 paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node
2441 QListIterator<DocNode> li2(paraChildren);
2443 for (li2.toFirst();(dn2=li2.current());++li2)
2445 newChildren.append(dn2); // add them to new node
2450 QListIterator<DocNode> li3(newChildren);
2451 for (li3.toFirst();(dn=li3.current());++li3)
2453 children.append(dn);
2454 dn->setParent(root);
2458 void DocRef::parse()
2460 g_nodeStack.push(this);
2461 DBG(("DocRef::parse() start\n"));
2464 while ((tok=doctokenizerYYlex()))
2466 if (!defaultHandleToken(this,tok,m_children))
2471 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\ref",
2472 qPrint(g_token->name));
2475 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2476 qPrint(g_token->name));
2481 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2488 if (m_children.isEmpty() && !m_text.isEmpty())
2490 g_insideHtmlLink=TRUE;
2491 docParserPushContext();
2492 internalValidatingParseDoc(this,m_children,m_text);
2493 docParserPopContext();
2494 g_insideHtmlLink=FALSE;
2495 flattenParagraphs(this,m_children);
2498 handlePendingStyleCommands(this,m_children);
2500 DocNode *n=g_nodeStack.pop();
2504 //---------------------------------------------------------------------------
2506 DocCite::DocCite(DocNode *parent,const QCString &target,const QCString &) //context)
2508 static uint numBibFiles = Config_getList("CITE_BIB_FILES").count();
2511 //printf("DocCite::DocCite(target=%s)\n",target.data());
2512 ASSERT(!target.isEmpty());
2513 m_relPath = g_relPath;
2514 CiteInfo *cite = Doxygen::citeDict->find(target);
2515 if (numBibFiles>0 && cite) // ref to citation
2517 m_text = cite->text;
2518 if (m_text.isEmpty()) m_text = cite->label;
2520 m_anchor = CiteConsts::anchorPrefix+cite->label;
2521 m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE);
2522 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
2523 // m_text.data(),m_ref.data(),m_file.data(),m_anchor.data());
2526 m_text = linkToText(SrcLangExt_Unknown,target,FALSE);
2527 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve reference to `%s' for \\cite command",
2531 //---------------------------------------------------------------------------
2533 DocLink::DocLink(DocNode *parent,const QCString &target)
2536 Definition *compound;
2540 m_relPath = g_relPath;
2541 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
2543 m_refText = m_refText.right(m_refText.length()-1);
2545 if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock,
2549 if (compound && compound->isLinkable())
2551 m_file = compound->getOutputFileBase();
2552 m_ref = compound->getReference();
2554 else if (compound->definitionType()==Definition::TypeFile &&
2555 ((FileDef*)compound)->generateSourceFile()
2556 ) // undocumented file that has source code we can link to
2558 m_file = compound->getSourceFileBase();
2559 m_ref = compound->getReference();
2564 // bogus link target
2565 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve link to `%s' for \\link command",
2570 QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
2573 g_nodeStack.push(this);
2574 DBG(("DocLink::parse() start\n"));
2577 while ((tok=doctokenizerYYlex()))
2579 if (!defaultHandleToken(this,tok,m_children,FALSE))
2584 switch (Mappers::cmdMapper->map(g_token->name))
2589 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: {@link.. ended with @endlink command");
2593 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\link",
2594 qPrint(g_token->name));
2599 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2600 qPrint(g_token->name));
2603 if (g_token->name!="see" || !isXmlLink)
2605 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected xml/html command %s found",
2606 qPrint(g_token->name));
2611 if (isJavaLink) // special case to detect closing }
2613 QCString w = g_token->name;
2619 else if ((p=w.find('}'))!=-1)
2622 m_children.append(new DocWord(this,w.left(p)));
2623 if ((uint)p<l-1) // something left after the } (for instance a .)
2625 result=w.right(l-p-1);
2630 m_children.append(new DocWord(this,g_token->name));
2633 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2641 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
2646 if (m_children.isEmpty()) // no link text
2648 m_children.append(new DocWord(this,m_refText));
2651 handlePendingStyleCommands(this,m_children);
2652 DBG(("DocLink::parse() end\n"));
2653 DocNode *n=g_nodeStack.pop();
2659 //---------------------------------------------------------------------------
2661 DocDotFile::DocDotFile(DocNode *parent,const QCString &name,const QCString &context) :
2662 m_name(name), m_relPath(g_relPath), m_context(context)
2667 void DocDotFile::parse()
2669 g_nodeStack.push(this);
2670 DBG(("DocDotFile::parse() start\n"));
2672 doctokenizerYYsetStateTitle();
2674 while ((tok=doctokenizerYYlex()))
2676 if (!defaultHandleToken(this,tok,m_children))
2681 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\dotfile",
2682 qPrint(g_token->name));
2685 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2686 qPrint(g_token->name));
2689 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2695 tok=doctokenizerYYlex();
2696 while (tok==TK_WORD) // there are values following the title
2698 if (g_token->name=="width")
2700 m_width=g_token->chars;
2702 else if (g_token->name=="height")
2704 m_height=g_token->chars;
2708 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title",
2709 qPrint(g_token->name));
2711 tok=doctokenizerYYlex();
2714 doctokenizerYYsetStatePara();
2715 handlePendingStyleCommands(this,m_children);
2718 FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig);
2719 if (fd==0 && m_name.right(4)!=".dot") // try with .dot extension as well
2721 fd = findFileDef(Doxygen::dotFileNameDict,m_name+".dot",ambig);
2725 m_file = fd->absFilePath();
2729 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included dot file name %s is ambiguous.\n"
2730 "Possible candidates:\n%s",qPrint(m_name),
2731 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2736 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included dot file %s is not found "
2737 "in any of the paths specified via DOTFILE_DIRS!",qPrint(m_name));
2740 DBG(("DocDotFile::parse() end\n"));
2741 DocNode *n=g_nodeStack.pop();
2745 DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &context) :
2746 m_name(name), m_relPath(g_relPath), m_context(context)
2751 void DocMscFile::parse()
2753 g_nodeStack.push(this);
2754 DBG(("DocMscFile::parse() start\n"));
2756 doctokenizerYYsetStateTitle();
2758 while ((tok=doctokenizerYYlex()))
2760 if (!defaultHandleToken(this,tok,m_children))
2765 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\mscfile",
2766 qPrint(g_token->name));
2769 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2770 qPrint(g_token->name));
2773 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2779 tok=doctokenizerYYlex();
2780 while (tok==TK_WORD) // there are values following the title
2782 if (g_token->name=="width")
2784 m_width=g_token->chars;
2786 else if (g_token->name=="height")
2788 m_height=g_token->chars;
2792 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title",
2793 qPrint(g_token->name));
2795 tok=doctokenizerYYlex();
2798 doctokenizerYYsetStatePara();
2799 handlePendingStyleCommands(this,m_children);
2802 FileDef *fd = findFileDef(Doxygen::mscFileNameDict,m_name,ambig);
2803 if (fd==0 && m_name.right(4)!=".msc") // try with .msc extension as well
2805 fd = findFileDef(Doxygen::mscFileNameDict,m_name+".msc",ambig);
2809 m_file = fd->absFilePath();
2813 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included msc file name %s is ambiguous.\n"
2814 "Possible candidates:\n%s",qPrint(m_name),
2815 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2820 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included msc file %s is not found "
2821 "in any of the paths specified via MSCFILE_DIRS!",qPrint(m_name));
2824 DBG(("DocMscFile::parse() end\n"));
2825 DocNode *n=g_nodeStack.pop();
2831 //---------------------------------------------------------------------------
2833 DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QCString &name,
2834 Type t,const QCString &url) :
2835 m_attribs(attribs), m_name(name),
2836 m_type(t), m_relPath(g_relPath),
2842 void DocImage::parse()
2844 g_nodeStack.push(this);
2845 DBG(("DocImage::parse() start\n"));
2848 doctokenizerYYsetStateTitle();
2850 while ((tok=doctokenizerYYlex()))
2852 if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height="))
2854 // special case: no title, but we do have a size indicator
2855 doctokenizerYYsetStateTitleAttrValue();
2857 g_token->name=g_token->name.left(g_token->name.length()-1);
2860 if (!defaultHandleToken(this,tok,m_children))
2865 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\image",
2866 qPrint(g_token->name));
2869 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2870 qPrint(g_token->name));
2873 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2879 // parse size attributes
2880 tok=doctokenizerYYlex();
2881 while (tok==TK_WORD) // there are values following the title
2883 if (g_token->name=="width")
2885 m_width=g_token->chars;
2887 else if (g_token->name=="height")
2889 m_height=g_token->chars;
2893 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title",
2894 qPrint(g_token->name));
2896 tok=doctokenizerYYlex();
2898 doctokenizerYYsetStatePara();
2900 handlePendingStyleCommands(this,m_children);
2901 DBG(("DocImage::parse() end\n"));
2902 DocNode *n=g_nodeStack.pop();
2907 //---------------------------------------------------------------------------
2909 int DocHtmlHeader::parse()
2911 int retval=RetVal_OK;
2912 g_nodeStack.push(this);
2913 DBG(("DocHtmlHeader::parse() start\n"));
2916 while ((tok=doctokenizerYYlex()))
2918 if (!defaultHandleToken(this,tok,m_children))
2923 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <h%d> tag",
2924 qPrint(g_token->name),m_level);
2928 int tagId=Mappers::htmlTagMapper->map(g_token->name);
2929 if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
2933 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h1>",
2938 else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag
2942 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h2>",
2947 else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag
2951 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h3>",
2956 else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag
2960 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h4>",
2965 else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag
2969 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h5>",
2974 else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag
2978 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h6>",
2983 else if (tagId==HTML_A)
2985 if (!g_token->endTag)
2987 handleAHref(this,m_children,g_token->attribs);
2990 else if (tagId==HTML_BR)
2992 DocLineBreak *lb = new DocLineBreak(this);
2993 m_children.append(lb);
2997 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <h%d> context",
2998 g_token->endTag?"/":"",qPrint(g_token->name),m_level);
3004 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3005 qPrint(g_token->name));
3008 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3016 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
3017 " <h%d> tag\n",m_level);
3020 handlePendingStyleCommands(this,m_children);
3021 DBG(("DocHtmlHeader::parse() end\n"));
3022 DocNode *n=g_nodeStack.pop();
3027 //---------------------------------------------------------------------------
3029 int DocHRef::parse()
3031 int retval=RetVal_OK;
3032 g_nodeStack.push(this);
3033 DBG(("DocHRef::parse() start\n"));
3036 while ((tok=doctokenizerYYlex()))
3038 if (!defaultHandleToken(this,tok,m_children))
3043 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <a>..</a> block",
3044 qPrint(g_token->name));
3047 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3048 qPrint(g_token->name));
3052 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3053 if (tagId==HTML_A && g_token->endTag) // found </a> tag
3059 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <a href=...> context",
3060 g_token->endTag?"/":"",qPrint(g_token->name),doctokenizerYYlineno);
3065 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3066 tokToString(tok),doctokenizerYYlineno);
3073 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
3074 " <a href=...> tag",doctokenizerYYlineno);
3077 handlePendingStyleCommands(this,m_children);
3078 DBG(("DocHRef::parse() end\n"));
3079 DocNode *n=g_nodeStack.pop();
3084 //---------------------------------------------------------------------------
3086 int DocInternal::parse(int level)
3088 int retval=RetVal_OK;
3089 g_nodeStack.push(this);
3090 DBG(("DocInternal::parse() start\n"));
3092 // first parse any number of paragraphs
3097 DocPara *par = new DocPara(this);
3098 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3099 retval=par->parse();
3100 if (!par->isEmpty())
3102 m_children.append(par);
3109 if (retval==TK_LISTITEM)
3111 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found",doctokenizerYYlineno);
3113 } while (retval!=0 &&
3114 retval!=RetVal_Section &&
3115 retval!=RetVal_Subsection &&
3116 retval!=RetVal_Subsubsection &&
3117 retval!=RetVal_Paragraph
3119 if (lastPar) lastPar->markLast();
3121 // then parse any number of level-n sections
3122 while ((level==1 && retval==RetVal_Section) ||
3123 (level==2 && retval==RetVal_Subsection) ||
3124 (level==3 && retval==RetVal_Subsubsection) ||
3125 (level==4 && retval==RetVal_Paragraph)
3128 DocSection *s=new DocSection(this,
3129 QMIN(level+Doxygen::subpageNestingLevel,5),g_token->sectionId);
3130 m_children.append(s);
3131 retval = s->parse();
3134 if (retval==RetVal_Internal)
3136 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: \\internal command found inside internal section");
3139 DBG(("DocInternal::parse() end\n"));
3140 DocNode *n=g_nodeStack.pop();
3145 //---------------------------------------------------------------------------
3147 int DocIndexEntry::parse()
3149 int retval=RetVal_OK;
3150 g_nodeStack.push(this);
3151 DBG(("DocIndexEntry::parse() start\n"));
3152 int tok=doctokenizerYYlex();
3153 if (tok!=TK_WHITESPACE)
3155 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after \\addindex command");
3158 doctokenizerYYsetStateTitle();
3160 while ((tok=doctokenizerYYlex()))
3169 m_entry+=g_token->name;
3174 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
3177 case DocSymbol::BSlash: m_entry+='\\'; break;
3178 case DocSymbol::At: m_entry+='@'; break;
3179 case DocSymbol::Less: m_entry+='<'; break;
3180 case DocSymbol::Greater: m_entry+='>'; break;
3181 case DocSymbol::Amp: m_entry+='&'; break;
3182 case DocSymbol::Dollar: m_entry+='$'; break;
3183 case DocSymbol::Hash: m_entry+='#'; break;
3184 case DocSymbol::Percent: m_entry+='%'; break;
3185 case DocSymbol::Apos: m_entry+='\''; break;
3186 case DocSymbol::Quot: m_entry+='"'; break;
3187 case DocSymbol::Lsquo: m_entry+='`'; break;
3188 case DocSymbol::Rsquo: m_entry+='\''; break;
3189 case DocSymbol::Ldquo: m_entry+="``"; break;
3190 case DocSymbol::Rdquo: m_entry+="''"; break;
3191 case DocSymbol::Ndash: m_entry+="--"; break;
3192 case DocSymbol::Mdash: m_entry+="---"; break;
3194 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected symbol found as argument of \\addindex");
3200 switch (Mappers::cmdMapper->map(g_token->name))
3202 case CMD_BSLASH: m_entry+='\\'; break;
3203 case CMD_AT: m_entry+='@'; break;
3204 case CMD_LESS: m_entry+='<'; break;
3205 case CMD_GREATER: m_entry+='>'; break;
3206 case CMD_AMP: m_entry+='&'; break;
3207 case CMD_DOLLAR: m_entry+='$'; break;
3208 case CMD_HASH: m_entry+='#'; break;
3209 case CMD_DCOLON: m_entry+="::"; break;
3210 case CMD_PERCENT: m_entry+='%'; break;
3211 case CMD_QUOTE: m_entry+='"'; break;
3213 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected command %s found as argument of \\addindex",
3214 qPrint(g_token->name));
3219 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3224 if (tok!=0) retval=tok;
3225 doctokenizerYYsetStatePara();
3226 m_entry = m_entry.stripWhiteSpace();
3228 DBG(("DocIndexEntry::parse() end retval=%x\n",retval));
3229 DocNode *n=g_nodeStack.pop();
3234 //---------------------------------------------------------------------------
3236 int DocHtmlCaption::parse()
3239 g_nodeStack.push(this);
3240 DBG(("DocHtmlCaption::parse() start\n"));
3242 while ((tok=doctokenizerYYlex()))
3244 if (!defaultHandleToken(this,tok,m_children))
3249 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <caption> tag",
3250 qPrint(g_token->name));
3253 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3254 qPrint(g_token->name));
3258 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3259 if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
3266 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <caption> context",
3267 g_token->endTag?"/":"",qPrint(g_token->name));
3272 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3280 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
3281 " <caption> tag",doctokenizerYYlineno);
3284 handlePendingStyleCommands(this,m_children);
3285 DBG(("DocHtmlCaption::parse() end\n"));
3286 DocNode *n=g_nodeStack.pop();
3291 //---------------------------------------------------------------------------
3293 int DocHtmlCell::parse()
3295 int retval=RetVal_OK;
3296 g_nodeStack.push(this);
3297 DBG(("DocHtmlCell::parse() start\n"));
3299 // parse one or more paragraphs
3304 par = new DocPara(this);
3305 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3306 m_children.append(par);
3307 retval=par->parse();
3308 if (retval==TK_HTMLTAG)
3310 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3311 if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
3313 retval=TK_NEWPARA; // ignore the tag
3315 else if (tagId==HTML_TH && g_token->endTag) // found </th> tag
3317 retval=TK_NEWPARA; // ignore the tag
3321 while (retval==TK_NEWPARA);
3322 if (par) par->markLast();
3324 DBG(("DocHtmlCell::parse() end\n"));
3325 DocNode *n=g_nodeStack.pop();
3330 int DocHtmlCell::parseXml()
3332 int retval=RetVal_OK;
3333 g_nodeStack.push(this);
3334 DBG(("DocHtmlCell::parseXml() start\n"));
3336 // parse one or more paragraphs
3341 par = new DocPara(this);
3342 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3343 m_children.append(par);
3344 retval=par->parse();
3345 if (retval==TK_HTMLTAG)
3347 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3348 if (tagId==XML_ITEM && g_token->endTag) // found </item> tag
3350 retval=TK_NEWPARA; // ignore the tag
3352 else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag
3354 retval=TK_NEWPARA; // ignore the tag
3358 while (retval==TK_NEWPARA);
3359 if (par) par->markLast();
3361 DBG(("DocHtmlCell::parseXml() end\n"));
3362 DocNode *n=g_nodeStack.pop();
3367 int DocHtmlCell::rowSpan() const
3370 HtmlAttribList attrs = attribs();
3372 for (i=0; i<attrs.count(); ++i)
3374 if (attrs.at(i)->name.lower()=="rowspan")
3376 retval = attrs.at(i)->value.toInt();
3383 int DocHtmlCell::colSpan() const
3386 HtmlAttribList attrs = attribs();
3388 for (i=0; i<attrs.count(); ++i)
3390 if (attrs.at(i)->name.lower()=="colspan")
3392 retval = QMAX(1,attrs.at(i)->value.toInt());
3399 DocHtmlCell::Alignment DocHtmlCell::alignment() const
3401 HtmlAttribList attrs = attribs();
3403 for (i=0; i<attrs.count(); ++i)
3405 if (attrs.at(i)->name.lower()=="align")
3407 if (attrs.at(i)->value.lower()=="center")
3409 else if (attrs.at(i)->value.lower()=="right")
3418 //---------------------------------------------------------------------------
3420 int DocHtmlRow::parse()
3422 int retval=RetVal_OK;
3423 g_nodeStack.push(this);
3424 DBG(("DocHtmlRow::parse() start\n"));
3426 bool isHeading=FALSE;
3428 DocHtmlCell *cell=0;
3431 int tok=doctokenizerYYlex();
3433 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3434 // should find a html tag now
3435 if (tok==TK_HTMLTAG)
3437 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3438 if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
3441 else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag
3445 else // found some other tag
3447 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but "
3448 "found <%s> instead!",qPrint(g_token->name));
3449 doctokenizerYYpushBackHtmlTag(g_token->name);
3453 else if (tok==0) // premature end of comment
3455 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3456 " for a html description title");
3459 else // token other than html token
3461 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but found %s token instead!",
3466 // parse one or more cells
3469 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3470 cell->markFirst(isFirst);
3472 m_children.append(cell);
3473 retval=cell->parse();
3474 isHeading = retval==RetVal_TableHCell;
3476 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3477 if (cell) cell->markLast(TRUE);
3480 DBG(("DocHtmlRow::parse() end\n"));
3481 DocNode *n=g_nodeStack.pop();
3486 int DocHtmlRow::parseXml(bool isHeading)
3488 int retval=RetVal_OK;
3489 g_nodeStack.push(this);
3490 DBG(("DocHtmlRow::parseXml() start\n"));
3493 DocHtmlCell *cell=0;
3496 int tok=doctokenizerYYlex();
3498 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3499 // should find a html tag now
3500 if (tok==TK_HTMLTAG)
3502 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3503 if (tagId==XML_TERM && !g_token->endTag) // found <term> tag
3506 else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag
3509 else // found some other tag
3511 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <term> or <description> tag but "
3512 "found <%s> instead!",qPrint(g_token->name));
3513 doctokenizerYYpushBackHtmlTag(g_token->name);
3517 else if (tok==0) // premature end of comment
3519 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3520 " for a html description title");
3523 else // token other than html token
3525 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but found %s token instead!",
3532 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3533 cell->markFirst(isFirst);
3535 m_children.append(cell);
3536 retval=cell->parseXml();
3538 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3539 if (cell) cell->markLast(TRUE);
3542 DBG(("DocHtmlRow::parseXml() end\n"));
3543 DocNode *n=g_nodeStack.pop();
3548 //---------------------------------------------------------------------------
3550 int DocHtmlTable::parse()
3552 int retval=RetVal_OK;
3553 g_nodeStack.push(this);
3554 DBG(("DocHtmlTable::parse() start\n"));
3558 int tok=doctokenizerYYlex();
3560 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3561 // should find a html tag now
3562 if (tok==TK_HTMLTAG)
3564 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3565 if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
3567 // no caption, just rows
3568 retval=RetVal_TableRow;
3570 else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag
3574 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: table already has a caption, found another one");
3578 m_caption = new DocHtmlCaption(this,g_token->attribs);
3579 retval=m_caption->parse();
3581 if (retval==RetVal_OK) // caption was parsed ok
3587 else // found wrong token
3589 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <tr> or <caption> tag but "
3590 "found <%s%s> instead!", g_token->endTag ? "/" : "", qPrint(g_token->name));
3593 else if (tok==0) // premature end of comment
3595 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3596 " for a <tr> or <caption> tag");
3598 else // token other than html token
3600 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <tr> tag but found %s token instead!",
3604 // parse one or more rows
3605 while (retval==RetVal_TableRow)
3607 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3608 m_children.append(tr);
3614 DBG(("DocHtmlTable::parse() end\n"));
3615 DocNode *n=g_nodeStack.pop();
3617 return retval==RetVal_EndTable ? RetVal_OK : retval;
3620 int DocHtmlTable::parseXml()
3622 int retval=RetVal_OK;
3623 g_nodeStack.push(this);
3624 DBG(("DocHtmlTable::parseXml() start\n"));
3627 int tok=doctokenizerYYlex();
3629 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3630 // should find a html tag now
3632 bool isHeader=FALSE;
3633 if (tok==TK_HTMLTAG)
3635 tagId=Mappers::htmlTagMapper->map(g_token->name);
3636 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
3638 retval=RetVal_TableRow;
3640 if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag
3642 retval=RetVal_TableRow;
3647 // parse one or more rows
3648 while (retval==RetVal_TableRow)
3650 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3651 m_children.append(tr);
3652 retval=tr->parseXml(isHeader);
3658 DBG(("DocHtmlTable::parseXml() end\n"));
3659 DocNode *n=g_nodeStack.pop();
3661 return retval==RetVal_EndTable ? RetVal_OK : retval;
3664 /** Helper class to compute the grid for an HTML style table */
3665 struct ActiveRowSpan
3667 ActiveRowSpan(int rows,int col) : rowsLeft(rows), column(col) {}
3672 /** List of ActiveRowSpan classes. */
3673 typedef QList<ActiveRowSpan> RowSpanList;
3675 /** determines the location of all cells in a grid, resolving row and
3676 column spans. For each the total number of visible cells is computed,
3677 and the total number of visible columns over all rows is stored.
3679 void DocHtmlTable::computeTableGrid()
3681 //printf("computeTableGrid()\n");
3682 RowSpanList rowSpans;
3683 rowSpans.setAutoDelete(TRUE);
3686 QListIterator<DocNode> li(children());
3688 for (li.toFirst();(rowNode=li.current());++li)
3692 if (rowNode->kind()==DocNode::Kind_HtmlRow)
3695 DocHtmlRow *row = (DocHtmlRow*)rowNode;
3696 QListIterator<DocNode> rli(row->children());
3698 for (rli.toFirst();(cellNode=rli.current());++rli)
3700 if (cellNode->kind()==DocNode::Kind_HtmlCell)
3702 DocHtmlCell *cell = (DocHtmlCell*)cellNode;
3703 int rs = cell->rowSpan();
3704 int cs = cell->colSpan();
3706 for (i=0;i<rowSpans.count();i++)
3708 if (rowSpans.at(i)->rowsLeft>0 &&
3709 rowSpans.at(i)->column==colIdx)
3711 colIdx=rowSpans.at(i)->column+1;
3715 if (rs>0) rowSpans.append(new ActiveRowSpan(rs,colIdx));
3716 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
3717 cell->setRowIndex(rowIdx);
3718 cell->setColumnIndex(colIdx);
3723 for (i=0;i<rowSpans.count();i++)
3725 if (rowSpans.at(i)->rowsLeft>0) rowSpans.at(i)->rowsLeft--;
3727 row->setVisibleCells(cells);
3728 row->setRowIndex(rowIdx);
3731 if (colIdx-1>maxCols) maxCols=colIdx-1;
3733 m_numCols = maxCols;
3736 void DocHtmlTable::accept(DocVisitor *v)
3739 // for HTML output we put the caption first
3740 if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v);
3741 QListIterator<DocNode> cli(m_children);
3743 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
3744 // for other output formats we put the caption last
3745 if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v);
3749 //---------------------------------------------------------------------------
3751 int DocHtmlDescTitle::parse()
3754 g_nodeStack.push(this);
3755 DBG(("DocHtmlDescTitle::parse() start\n"));
3758 while ((tok=doctokenizerYYlex()))
3760 if (!defaultHandleToken(this,tok,m_children))
3766 QCString cmdName=g_token->name;
3767 bool isJavaLink=FALSE;
3768 switch (Mappers::cmdMapper->map(cmdName))
3772 int tok=doctokenizerYYlex();
3773 if (tok!=TK_WHITESPACE)
3775 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
3776 qPrint(g_token->name));
3780 doctokenizerYYsetStateRef();
3781 tok=doctokenizerYYlex(); // get the reference id
3784 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
3785 tokToString(tok),qPrint(cmdName));
3789 DocRef *ref = new DocRef(this,g_token->name,g_context);
3790 m_children.append(ref);
3793 doctokenizerYYsetStatePara();
3802 int tok=doctokenizerYYlex();
3803 if (tok!=TK_WHITESPACE)
3805 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
3810 doctokenizerYYsetStateLink();
3811 tok=doctokenizerYYlex();
3814 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
3815 tokToString(tok),qPrint(cmdName));
3819 doctokenizerYYsetStatePara();
3820 DocLink *lnk = new DocLink(this,g_token->name);
3821 m_children.append(lnk);
3822 QCString leftOver = lnk->parse(isJavaLink);
3823 if (!leftOver.isEmpty())
3825 m_children.append(new DocWord(this,leftOver));
3833 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <dt> tag",
3834 qPrint(g_token->name));
3839 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3840 qPrint(g_token->name));
3844 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3845 if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
3847 retval = RetVal_DescData;
3850 else if (tagId==HTML_DT && g_token->endTag)
3852 // ignore </dt> tag.
3854 else if (tagId==HTML_DT)
3856 // missing <dt> tag.
3857 retval = RetVal_DescTitle;
3860 else if (tagId==HTML_DL && g_token->endTag)
3862 retval=RetVal_EndDesc;
3865 else if (tagId==HTML_A)
3867 if (!g_token->endTag)
3869 handleAHref(this,m_children,g_token->attribs);
3874 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <dt> context",
3875 g_token->endTag?"/":"",qPrint(g_token->name));
3880 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3888 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
3892 handlePendingStyleCommands(this,m_children);
3893 DBG(("DocHtmlDescTitle::parse() end\n"));
3894 DocNode *n=g_nodeStack.pop();
3899 //---------------------------------------------------------------------------
3901 int DocHtmlDescData::parse()
3903 m_attribs = g_token->attribs;
3905 g_nodeStack.push(this);
3906 DBG(("DocHtmlDescData::parse() start\n"));
3912 par = new DocPara(this);
3913 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3914 m_children.append(par);
3915 retval=par->parse();
3917 while (retval==TK_NEWPARA);
3918 if (par) par->markLast();
3920 DBG(("DocHtmlDescData::parse() end\n"));
3921 DocNode *n=g_nodeStack.pop();
3926 //---------------------------------------------------------------------------
3928 int DocHtmlDescList::parse()
3930 int retval=RetVal_OK;
3931 g_nodeStack.push(this);
3932 DBG(("DocHtmlDescList::parse() start\n"));
3935 int tok=doctokenizerYYlex();
3937 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3938 // should find a html tag now
3939 if (tok==TK_HTMLTAG)
3941 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3942 if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
3946 else // found some other tag
3948 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <dt> tag but "
3949 "found <%s> instead!",qPrint(g_token->name));
3950 doctokenizerYYpushBackHtmlTag(g_token->name);
3954 else if (tok==0) // premature end of comment
3956 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3957 " for a html description title");
3960 else // token other than html token
3962 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <dt> tag but found %s token instead!",
3969 DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs);
3970 m_children.append(dt);
3971 DocHtmlDescData *dd=new DocHtmlDescData(this);
3972 m_children.append(dd);
3974 if (retval==RetVal_DescData)
3978 else if (retval!=RetVal_DescTitle)
3983 } while (retval==RetVal_DescTitle);
3987 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <dl> block");
3992 DocNode *n=g_nodeStack.pop();
3994 DBG(("DocHtmlDescList::parse() end\n"));
3995 return retval==RetVal_EndDesc ? RetVal_OK : retval;
3998 //---------------------------------------------------------------------------
4000 int DocHtmlListItem::parse()
4002 DBG(("DocHtmlListItem::parse() start\n"));
4004 g_nodeStack.push(this);
4006 // parse one or more paragraphs
4011 par = new DocPara(this);
4012 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4013 m_children.append(par);
4014 retval=par->parse();
4016 while (retval==TK_NEWPARA);
4017 if (par) par->markLast();
4019 DocNode *n=g_nodeStack.pop();
4021 DBG(("DocHtmlListItem::parse() end retval=%x\n",retval));
4025 int DocHtmlListItem::parseXml()
4027 DBG(("DocHtmlListItem::parseXml() start\n"));
4029 g_nodeStack.push(this);
4031 // parse one or more paragraphs
4036 par = new DocPara(this);
4037 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4038 m_children.append(par);
4039 retval=par->parse();
4040 if (retval==0) break;
4042 //printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
4043 // retval,qPrint(g_token->name),g_token->endTag);
4044 if (retval==RetVal_ListItem)
4049 while (retval!=RetVal_CloseXml);
4051 if (par) par->markLast();
4053 DocNode *n=g_nodeStack.pop();
4055 DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
4059 //---------------------------------------------------------------------------
4061 int DocHtmlList::parse()
4063 DBG(("DocHtmlList::parse() start\n"));
4064 int retval=RetVal_OK;
4066 g_nodeStack.push(this);
4069 int tok=doctokenizerYYlex();
4070 // skip whitespace and paragraph breaks
4071 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4072 // should find a html tag now
4073 if (tok==TK_HTMLTAG)
4075 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4076 if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
4078 // ok, we can go on.
4080 else if (((m_type==Unordered && tagId==HTML_UL) ||
4081 (m_type==Ordered && tagId==HTML_OL)
4082 ) && g_token->endTag
4083 ) // found empty list
4085 // add dummy item to obtain valid HTML
4086 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4087 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: empty list!");
4088 retval = RetVal_EndList;
4091 else // found some other tag
4093 // add dummy item to obtain valid HTML
4094 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4095 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <li> tag but "
4096 "found <%s%s> instead!",g_token->endTag?"/":"",qPrint(g_token->name));
4097 doctokenizerYYpushBackHtmlTag(g_token->name);
4101 else if (tok==0) // premature end of comment
4103 // add dummy item to obtain valid HTML
4104 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4105 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
4106 " for a html list item");
4109 else // token other than html token
4111 // add dummy item to obtain valid HTML
4112 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4113 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <li> tag but found %s token instead!",
4120 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
4121 m_children.append(li);
4123 } while (retval==RetVal_ListItem);
4127 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <%cl> block",
4128 m_type==Unordered ? 'u' : 'o');
4132 DBG(("DocHtmlList::parse() end retval=%x\n",retval));
4133 DocNode *n=g_nodeStack.pop();
4135 return retval==RetVal_EndList ? RetVal_OK : retval;
4138 int DocHtmlList::parseXml()
4140 DBG(("DocHtmlList::parseXml() start\n"));
4141 int retval=RetVal_OK;
4143 g_nodeStack.push(this);
4146 int tok=doctokenizerYYlex();
4147 // skip whitespace and paragraph breaks
4148 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4149 // should find a html tag now
4150 if (tok==TK_HTMLTAG)
4152 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4153 //printf("g_token->name=%s g_token->endTag=%d\n",qPrint(g_token->name),g_token->endTag);
4154 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
4156 // ok, we can go on.
4158 else // found some other tag
4160 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <item> tag but "
4161 "found <%s> instead!",qPrint(g_token->name));
4162 doctokenizerYYpushBackHtmlTag(g_token->name);
4166 else if (tok==0) // premature end of comment
4168 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
4169 " for a html list item");
4172 else // token other than html token
4174 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <item> tag but found %s token instead!",
4181 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
4182 m_children.append(li);
4183 retval=li->parseXml();
4184 if (retval==0) break;
4185 //printf("retval=%x g_token->name=%s\n",retval,qPrint(g_token->name));
4186 } while (retval==RetVal_ListItem);
4190 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <list type=\"%s\"> block",
4191 m_type==Unordered ? "bullet" : "number");
4195 DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
4196 DocNode *n=g_nodeStack.pop();
4198 return retval==RetVal_EndList ||
4199 (retval==RetVal_CloseXml || g_token->name=="list") ?
4203 //--------------------------------------------------------------------------
4205 int DocHtmlBlockQuote::parse()
4207 DBG(("DocHtmlBlockQuote::parse() start\n"));
4209 g_nodeStack.push(this);
4211 // parse one or more paragraphs
4216 par = new DocPara(this);
4217 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4218 m_children.append(par);
4219 retval=par->parse();
4221 while (retval==TK_NEWPARA);
4222 if (par) par->markLast();
4224 DocNode *n=g_nodeStack.pop();
4226 DBG(("DocHtmlBlockQuote::parse() end retval=%x\n",retval));
4227 return (retval==RetVal_EndBlockQuote) ? RetVal_OK : retval;
4230 //---------------------------------------------------------------------------
4232 int DocSimpleListItem::parse()
4234 g_nodeStack.push(this);
4235 int rv=m_paragraph->parse();
4236 m_paragraph->markFirst();
4237 m_paragraph->markLast();
4238 DocNode *n=g_nodeStack.pop();
4243 //--------------------------------------------------------------------------
4245 int DocSimpleList::parse()
4247 g_nodeStack.push(this);
4251 DocSimpleListItem *li=new DocSimpleListItem(this);
4252 m_children.append(li);
4254 } while (rv==RetVal_ListItem);
4255 DocNode *n=g_nodeStack.pop();
4257 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4260 //--------------------------------------------------------------------------
4262 DocAutoListItem::DocAutoListItem(DocNode *parent,int indent,int num)
4263 : m_indent(indent), m_itemNum(num)
4268 int DocAutoListItem::parse()
4270 int retval = RetVal_OK;
4271 g_nodeStack.push(this);
4273 //retval=m_paragraph->parse();
4274 //m_paragraph->markFirst();
4275 //m_paragraph->markLast();
4277 // first parse any number of paragraphs
4282 DocPara *par = new DocPara(this);
4283 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4284 retval=par->parse();
4285 if (!par->isEmpty())
4287 m_children.append(par);
4288 if (lastPar) lastPar->markLast(FALSE);
4295 // next paragraph should be more indented than the - marker to belong
4297 } while (retval==TK_NEWPARA && g_token->indent>m_indent);
4298 if (lastPar) lastPar->markLast();
4300 DocNode *n=g_nodeStack.pop();
4302 //printf("DocAutoListItem: retval=%d indent=%d\n",retval,g_token->indent);
4306 //--------------------------------------------------------------------------
4308 DocAutoList::DocAutoList(DocNode *parent,int indent,bool isEnumList,
4310 m_indent(indent), m_isEnumList(isEnumList),
4316 int DocAutoList::parse()
4318 int retval = RetVal_OK;
4320 g_nodeStack.push(this);
4321 // first item or sub list => create new list
4324 if (g_token->id!=-1) // explicitly numbered list
4326 num=g_token->id; // override num with real number given
4328 DocAutoListItem *li = new DocAutoListItem(this,m_indent,num++);
4329 m_children.append(li);
4331 //printf("DocAutoList::parse(): retval=0x%x g_token->indent=%d m_indent=%d "
4332 // "m_isEnumList=%d g_token->isEnumList=%d g_token->name=%s\n",
4333 // retval,g_token->indent,m_indent,m_isEnumList,g_token->isEnumList,
4334 // g_token->name.data());
4335 //printf("num=%d g_token->id=%d\n",num,g_token->id);
4337 while (retval==TK_LISTITEM && // new list item
4338 m_indent==g_token->indent && // at same indent level
4339 m_isEnumList==g_token->isEnumList && // of the same kind
4340 (g_token->id==-1 || g_token->id>=num) // increasing number (or no number)
4343 DocNode *n=g_nodeStack.pop();
4348 //--------------------------------------------------------------------------
4350 void DocTitle::parse()
4352 DBG(("DocTitle::parse() start\n"));
4353 g_nodeStack.push(this);
4354 doctokenizerYYsetStateTitle();
4356 while ((tok=doctokenizerYYlex()))
4358 if (!defaultHandleToken(this,tok,m_children))
4363 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a title section",
4364 qPrint(g_token->name));
4367 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
4368 qPrint(g_token->name));
4371 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
4377 doctokenizerYYsetStatePara();
4378 handlePendingStyleCommands(this,m_children);
4379 DBG(("DocTitle::parse() end\n"));
4380 DocNode *n = g_nodeStack.pop();
4384 void DocTitle::parseFromString(const QCString &text)
4386 m_children.append(new DocWord(this,text));
4389 //--------------------------------------------------------------------------
4391 DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) :
4398 DocSimpleSect::~DocSimpleSect()
4403 void DocSimpleSect::accept(DocVisitor *v)
4406 if (m_title) m_title->accept(v);
4407 QListIterator<DocNode> cli(m_children);
4409 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
4413 int DocSimpleSect::parse(bool userTitle,bool needsSeparator)
4415 DBG(("DocSimpleSect::parse() start\n"));
4416 g_nodeStack.push(this);
4418 // handle case for user defined title
4421 m_title = new DocTitle(this);
4425 // add new paragraph as child
4426 DocPara *par = new DocPara(this);
4427 if (m_children.isEmpty())
4433 ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
4434 ((DocPara *)m_children.last())->markLast(FALSE);
4437 if (needsSeparator) m_children.append(new DocSimpleSectSep(this));
4438 m_children.append(par);
4440 // parse the contents of the paragraph
4441 int retval = par->parse();
4443 DBG(("DocSimpleSect::parse() end retval=%d\n",retval));
4444 DocNode *n=g_nodeStack.pop();
4446 return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec
4449 int DocSimpleSect::parseRcs()
4451 DBG(("DocSimpleSect::parseRcs() start\n"));
4452 g_nodeStack.push(this);
4454 m_title = new DocTitle(this);
4455 m_title->parseFromString(g_token->name);
4457 QCString text = g_token->text;
4458 docParserPushContext(); // this will create a new g_token
4459 internalValidatingParseDoc(this,m_children,text);
4460 docParserPopContext(); // this will restore the old g_token
4462 DBG(("DocSimpleSect::parseRcs()\n"));
4463 DocNode *n=g_nodeStack.pop();
4468 int DocSimpleSect::parseXml()
4470 DBG(("DocSimpleSect::parse() start\n"));
4471 g_nodeStack.push(this);
4473 int retval = RetVal_OK;
4476 // add new paragraph as child
4477 DocPara *par = new DocPara(this);
4478 if (m_children.isEmpty())
4484 ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
4485 ((DocPara *)m_children.last())->markLast(FALSE);
4488 m_children.append(par);
4490 // parse the contents of the paragraph
4491 retval = par->parse();
4492 if (retval == 0) break;
4493 if (retval == RetVal_CloseXml)
4500 DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
4501 DocNode *n=g_nodeStack.pop();
4506 void DocSimpleSect::appendLinkWord(const QCString &word)
4509 if (m_children.isEmpty() || m_children.last()->kind()!=DocNode::Kind_Para)
4511 p = new DocPara(this);
4512 m_children.append(p);
4516 p = (DocPara *)m_children.last();
4518 // Comma-seperate <seealso> links.
4519 p->injectToken(TK_WORD,",");
4520 p->injectToken(TK_WHITESPACE," ");
4524 p->injectToken(TK_LNKWORD,word);
4528 QCString DocSimpleSect::typeString() const
4532 case Unknown: break;
4533 case See: return "see";
4534 case Return: return "return";
4535 case Author: // fall through
4536 case Authors: return "author";
4537 case Version: return "version";
4538 case Since: return "since";
4539 case Date: return "date";
4540 case Note: return "note";
4541 case Warning: return "warning";
4542 case Pre: return "pre";
4543 case Post: return "post";
4544 case Copyright: return "copyright";
4545 case Invar: return "invariant";
4546 case Remark: return "remark";
4547 case Attention: return "attention";
4548 case User: return "user";
4549 case Rcs: return "rcs";
4554 //--------------------------------------------------------------------------
4556 int DocParamList::parse(const QCString &cmdName)
4558 int retval=RetVal_OK;
4559 DBG(("DocParamList::parse() start\n"));
4560 g_nodeStack.push(this);
4563 int tok=doctokenizerYYlex();
4564 if (tok!=TK_WHITESPACE)
4566 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4569 doctokenizerYYsetStateParam();
4570 tok=doctokenizerYYlex();
4571 while (tok==TK_WORD) /* there is a parameter name */
4573 if (m_type==DocParamSect::Param)
4575 int typeSeparator = g_token->name.find('#'); // explicit type position
4576 if (typeSeparator!=-1)
4578 handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator));
4579 g_token->name = g_token->name.mid(typeSeparator+1);
4580 g_hasParamCommand=TRUE;
4581 checkArgumentName(g_token->name,TRUE);
4582 ((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE;
4586 g_hasParamCommand=TRUE;
4587 checkArgumentName(g_token->name,TRUE);
4590 else if (m_type==DocParamSect::RetVal)
4592 g_hasReturnCommand=TRUE;
4593 checkArgumentName(g_token->name,FALSE);
4595 //m_params.append(g_token->name);
4596 handleLinkedWord(this,m_params);
4597 tok=doctokenizerYYlex();
4599 doctokenizerYYsetStatePara();
4600 if (tok==0) /* premature end of comment block */
4602 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4603 "argument of command %s",qPrint(cmdName));
4607 ASSERT(tok==TK_WHITESPACE);
4609 par = new DocPara(this);
4610 m_paragraphs.append(par);
4611 retval = par->parse();
4616 DBG(("DocParamList::parse() end retval=%d\n",retval));
4617 DocNode *n=g_nodeStack.pop();
4622 int DocParamList::parseXml(const QCString ¶mName)
4624 int retval=RetVal_OK;
4625 DBG(("DocParamList::parseXml() start\n"));
4626 g_nodeStack.push(this);
4628 g_token->name = paramName;
4629 if (m_type==DocParamSect::Param)
4631 g_hasParamCommand=TRUE;
4632 checkArgumentName(g_token->name,TRUE);
4634 else if (m_type==DocParamSect::RetVal)
4636 g_hasReturnCommand=TRUE;
4637 checkArgumentName(g_token->name,FALSE);
4640 handleLinkedWord(this,m_params);
4644 DocPara *par = new DocPara(this);
4645 retval = par->parse();
4646 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
4647 // after </para> and before </param>
4652 else // append the paragraph to the list
4654 if (m_paragraphs.isEmpty())
4660 m_paragraphs.last()->markLast(FALSE);
4663 m_paragraphs.append(par);
4666 if (retval == 0) break;
4668 } while (retval==RetVal_CloseXml &&
4669 Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
4670 Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM &&
4671 Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
4674 if (retval==0) /* premature end of comment block */
4676 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unterminated param or exception tag");
4684 DBG(("DocParamList::parse() end retval=%d\n",retval));
4685 DocNode *n=g_nodeStack.pop();
4690 //--------------------------------------------------------------------------
4692 int DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
4694 int retval=RetVal_OK;
4695 DBG(("DocParamSect::parse() start\n"));
4696 g_nodeStack.push(this);
4700 m_hasInOutSpecifier=TRUE;
4703 DocParamList *pl = new DocParamList(this,m_type,d);
4704 if (m_children.isEmpty())
4711 ASSERT(m_children.last()->kind()==DocNode::Kind_ParamList);
4712 ((DocParamList *)m_children.last())->markLast(FALSE);
4715 m_children.append(pl);
4718 retval = pl->parseXml(cmdName);
4722 retval = pl->parse(cmdName);
4725 DBG(("DocParamSect::parse() end retval=%d\n",retval));
4726 DocNode *n=g_nodeStack.pop();
4731 //--------------------------------------------------------------------------
4733 int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
4735 DocSimpleSect *ss=0;
4736 bool needsSeparator = FALSE;
4737 if (!m_children.isEmpty() && // previous element
4738 m_children.last()->kind()==Kind_SimpleSect && // was a simple sect
4739 ((DocSimpleSect *)m_children.last())->type()==t && // of same type
4740 t!=DocSimpleSect::User) // but not user defined
4742 // append to previous section
4743 ss=(DocSimpleSect *)m_children.last();
4744 needsSeparator = TRUE;
4746 else // start new section
4748 ss=new DocSimpleSect(this,t);
4749 m_children.append(ss);
4754 return ss->parseXml();
4758 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
4760 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4763 int DocPara::handleParamSection(const QCString &cmdName,
4764 DocParamSect::Type t,
4765 bool xmlContext=FALSE,
4766 int direction=DocParamSect::Unspecified)
4769 if (!m_children.isEmpty() && // previous element
4770 m_children.last()->kind()==Kind_ParamSect && // was a param sect
4771 ((DocParamSect *)m_children.last())->type()==t) // of same type
4773 // append to previous section
4774 ps=(DocParamSect *)m_children.last();
4776 else // start new section
4778 ps=new DocParamSect(this,t);
4779 m_children.append(ps);
4781 int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
4782 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4785 void DocPara::handleCite()
4787 // get the argument of the cite command.
4788 int tok=doctokenizerYYlex();
4789 if (tok!=TK_WHITESPACE)
4791 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4795 doctokenizerYYsetStateCite();
4796 tok=doctokenizerYYlex();
4799 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4800 "argument of command %s\n", qPrint("cite"));
4803 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
4805 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4806 tokToString(tok),qPrint("cite"));
4809 g_token->sectionId = g_token->name;
4810 DocCite *cite = new DocCite(this,g_token->name,g_context);
4811 m_children.append(cite);
4814 doctokenizerYYsetStatePara();
4817 int DocPara::handleXRefItem()
4819 int retval=doctokenizerYYlex();
4820 ASSERT(retval==TK_WHITESPACE);
4821 doctokenizerYYsetStateXRefItem();
4822 retval=doctokenizerYYlex();
4823 if (retval==RetVal_OK)
4825 DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name);
4828 m_children.append(ref);
4835 doctokenizerYYsetStatePara();
4839 void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t)
4841 DBG(("handleIncludeOperator(%s)\n",qPrint(cmdName)));
4842 int tok=doctokenizerYYlex();
4843 if (tok!=TK_WHITESPACE)
4845 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4849 doctokenizerYYsetStatePattern();
4850 tok=doctokenizerYYlex();
4851 doctokenizerYYsetStatePara();
4854 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4855 "argument of command %s", qPrint(cmdName));
4858 else if (tok!=TK_WORD)
4860 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4861 tokToString(tok),qPrint(cmdName));
4864 DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
4865 DocNode *n1 = m_children.last();
4866 DocNode *n2 = n1!=0 ? m_children.prev() : 0;
4867 bool isFirst = n1==0 || // no last node
4868 (n1->kind()!=DocNode::Kind_IncOperator &&
4869 n1->kind()!=DocNode::Kind_WhiteSpace
4870 ) || // last node is not operator or whitespace
4871 (n1->kind()==DocNode::Kind_WhiteSpace &&
4872 n2!=0 && n2->kind()!=DocNode::Kind_IncOperator
4873 ); // previous not is not operator
4874 op->markFirst(isFirst);
4876 if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator)
4878 ((DocIncOperator *)n1)->markLast(FALSE);
4880 else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace &&
4881 n2!=0 && n2->kind()==DocNode::Kind_IncOperator
4884 ((DocIncOperator *)n2)->markLast(FALSE);
4886 m_children.append(op);
4890 void DocPara::handleImage(const QCString &cmdName)
4892 int tok=doctokenizerYYlex();
4893 if (tok!=TK_WHITESPACE)
4895 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4899 tok=doctokenizerYYlex();
4900 if (tok!=TK_WORD && tok!=TK_LNKWORD)
4902 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4903 tokToString(tok),qPrint(cmdName));
4906 tok=doctokenizerYYlex();
4907 if (tok!=TK_WHITESPACE)
4909 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4914 QCString imgType = g_token->name.lower();
4915 if (imgType=="html") t=DocImage::Html;
4916 else if (imgType=="latex") t=DocImage::Latex;
4917 else if (imgType=="rtf") t=DocImage::Rtf;
4920 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: image type %s specified as the first argument of "
4922 qPrint(imgType),qPrint(cmdName));
4925 doctokenizerYYsetStateFile();
4926 tok=doctokenizerYYlex();
4927 doctokenizerYYsetStatePara();
4930 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4931 tokToString(tok),qPrint(cmdName));
4934 HtmlAttribList attrList;
4935 DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t);
4936 m_children.append(img);
4940 void DocPara::handleDotFile(const QCString &cmdName)
4942 int tok=doctokenizerYYlex();
4943 if (tok!=TK_WHITESPACE)
4945 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4949 doctokenizerYYsetStateFile();
4950 tok=doctokenizerYYlex();
4951 doctokenizerYYsetStatePara();
4954 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4955 tokToString(tok),qPrint(cmdName));
4958 QCString name = g_token->name;
4959 DocDotFile *df = new DocDotFile(this,name,g_context);
4960 m_children.append(df);
4964 void DocPara::handleMscFile(const QCString &cmdName)
4966 int tok=doctokenizerYYlex();
4967 if (tok!=TK_WHITESPACE)
4969 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4973 doctokenizerYYsetStateFile();
4974 tok=doctokenizerYYlex();
4975 doctokenizerYYsetStatePara();
4978 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4979 tokToString(tok),qPrint(cmdName));
4982 QCString name = g_token->name;
4983 DocMscFile *df = new DocMscFile(this,name,g_context);
4984 m_children.append(df);
4988 void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
4990 int tok=doctokenizerYYlex();
4991 if (tok!=TK_WHITESPACE)
4993 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4997 doctokenizerYYsetStateLink();
4998 tok=doctokenizerYYlex();
5001 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5002 tokToString(tok),qPrint(cmdName));
5005 doctokenizerYYsetStatePara();
5006 DocLink *lnk = new DocLink(this,g_token->name);
5007 m_children.append(lnk);
5008 QCString leftOver = lnk->parse(isJavaLink);
5009 if (!leftOver.isEmpty())
5011 m_children.append(new DocWord(this,leftOver));
5015 void DocPara::handleRef(const QCString &cmdName)
5017 DBG(("handleRef(%s)\n",qPrint(cmdName)));
5018 int tok=doctokenizerYYlex();
5019 if (tok!=TK_WHITESPACE)
5021 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
5025 doctokenizerYYsetStateRef();
5026 tok=doctokenizerYYlex(); // get the reference id
5030 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5031 tokToString(tok),qPrint(cmdName));
5034 ref = new DocRef(this,g_token->name,g_context);
5035 m_children.append(ref);
5038 doctokenizerYYsetStatePara();
5042 void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
5044 DBG(("handleInclude(%s)\n",qPrint(cmdName)));
5045 int tok=doctokenizerYYlex();
5046 if (tok!=TK_WHITESPACE)
5048 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
5052 doctokenizerYYsetStateFile();
5053 tok=doctokenizerYYlex();
5054 doctokenizerYYsetStatePara();
5057 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
5058 "argument of command %s",qPrint(cmdName));
5061 else if (tok!=TK_WORD)
5063 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5064 tokToString(tok),qPrint(cmdName));
5067 QCString fileName = g_token->name;
5069 if (t==DocInclude::Snippet)
5071 doctokenizerYYsetStateSnippet();
5072 tok=doctokenizerYYlex();
5073 doctokenizerYYsetStatePara();
5076 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected block identifier, but found token %s instead while parsing the %s command",
5077 tokToString(tok),qPrint(cmdName));
5080 blockId = "["+g_token->name+"]";
5082 DocInclude *inc = new DocInclude(this,fileName,g_context,t,g_isExample,g_exampleName,blockId);
5083 m_children.append(inc);
5087 void DocPara::handleSection(const QCString &cmdName)
5089 // get the argument of the section command.
5090 int tok=doctokenizerYYlex();
5091 if (tok!=TK_WHITESPACE)
5093 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
5097 tok=doctokenizerYYlex();
5100 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
5101 "argument of command %s\n", qPrint(cmdName));
5104 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
5106 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5107 tokToString(tok),qPrint(cmdName));
5110 g_token->sectionId = g_token->name;
5111 doctokenizerYYsetStateSkipTitle();
5112 doctokenizerYYlex();
5113 doctokenizerYYsetStatePara();
5116 int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
5118 DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level);
5119 m_children.append(header);
5120 int retval = header->parse();
5121 return (retval==RetVal_OK) ? TK_NEWPARA : retval;
5124 // For XML tags whose content is stored in attributes rather than
5125 // contained within the element, we need a way to inject the attribute
5126 // text into the current paragraph.
5127 bool DocPara::injectToken(int tok,const QCString &tokText)
5129 g_token->name = tokText;
5130 return defaultHandleToken(this,tok,m_children);
5133 int DocPara::handleStartCode()
5135 int retval = doctokenizerYYlex();
5136 QCString lang = g_token->name;
5137 if (!lang.isEmpty() && lang.at(0)!='.')
5141 // search for the first non-whitespace line, index is stored in li
5142 int i=0,li=0,l=g_token->verb.length();
5143 while (i<l && (g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n'))
5145 if (g_token->verb.at(i)=='\n') li=i+1;
5148 m_children.append(new DocVerbatim(this,g_context,stripIndentation(g_token->verb.mid(li)),DocVerbatim::Code,g_isExample,g_exampleName,lang));
5149 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: code section ended without end marker");
5150 doctokenizerYYsetStatePara();
5154 void DocPara::handleInheritDoc()
5156 if (g_memberDef) // inheriting docs from a member
5158 MemberDef *reMd = g_memberDef->reimplements();
5159 if (reMd) // member from which was inherited.
5161 MemberDef *thisMd = g_memberDef;
5162 //printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data());
5163 docParserPushContext();
5164 g_scope=reMd->getOuterScope();
5165 if (g_scope!=Doxygen::globalScope)
5167 g_context=g_scope->name();
5170 g_styleStack.clear();
5171 g_nodeStack.clear();
5172 g_copyStack.append(reMd);
5173 internalValidatingParseDoc(this,m_children,reMd->briefDescription());
5174 internalValidatingParseDoc(this,m_children,reMd->documentation());
5175 g_copyStack.remove(reMd);
5176 docParserPopContext(TRUE);
5177 g_memberDef = thisMd;
5183 int DocPara::handleCommand(const QCString &cmdName)
5185 DBG(("handleCommand(%s)\n",qPrint(cmdName)));
5186 int retval = RetVal_OK;
5187 int cmdId = Mappers::cmdMapper->map(cmdName);
5191 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Found unknown command `\\%s'",qPrint(cmdName));
5194 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
5195 retval=handleStyleArgument(this,m_children,cmdName);
5196 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
5197 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5200 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
5201 retval=handleStyleArgument(this,m_children,cmdName);
5202 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
5203 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5206 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
5207 retval=handleStyleArgument(this,m_children,cmdName);
5208 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
5209 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5212 m_children.append(new DocSymbol(this,DocSymbol::BSlash));
5215 m_children.append(new DocSymbol(this,DocSymbol::At));
5218 m_children.append(new DocSymbol(this,DocSymbol::Less));
5221 m_children.append(new DocSymbol(this,DocSymbol::Greater));
5224 m_children.append(new DocSymbol(this,DocSymbol::Amp));
5227 m_children.append(new DocSymbol(this,DocSymbol::Dollar));
5230 m_children.append(new DocSymbol(this,DocSymbol::Hash));
5233 m_children.append(new DocSymbol(this,DocSymbol::Pipe));
5236 m_children.append(new DocSymbol(this,DocSymbol::DoubleColon));
5239 m_children.append(new DocSymbol(this,DocSymbol::Percent));
5242 m_children.append(new DocSymbol(this,DocSymbol::Quot));
5246 retval = handleSimpleSection(DocSimpleSect::See);
5250 retval = handleSimpleSection(DocSimpleSect::Return);
5251 g_hasReturnCommand=TRUE;
5254 retval = handleSimpleSection(DocSimpleSect::Author);
5257 retval = handleSimpleSection(DocSimpleSect::Authors);
5260 retval = handleSimpleSection(DocSimpleSect::Version);
5263 retval = handleSimpleSection(DocSimpleSect::Since);
5266 retval = handleSimpleSection(DocSimpleSect::Date);
5269 retval = handleSimpleSection(DocSimpleSect::Note);
5272 retval = handleSimpleSection(DocSimpleSect::Warning);
5275 retval = handleSimpleSection(DocSimpleSect::Pre);
5278 retval = handleSimpleSection(DocSimpleSect::Post);
5281 retval = handleSimpleSection(DocSimpleSect::Copyright);
5284 retval = handleSimpleSection(DocSimpleSect::Invar);
5287 retval = handleSimpleSection(DocSimpleSect::Remark);
5290 retval = handleSimpleSection(DocSimpleSect::Attention);
5293 retval = handleSimpleSection(DocSimpleSect::User);
5297 DocSimpleList *sl=new DocSimpleList(this);
5298 m_children.append(sl);
5299 retval = sl->parse();
5304 handleSection(cmdName);
5305 retval = RetVal_Section;
5308 case CMD_SUBSECTION:
5310 handleSection(cmdName);
5311 retval = RetVal_Subsection;
5314 case CMD_SUBSUBSECTION:
5316 handleSection(cmdName);
5317 retval = RetVal_Subsubsection;
5322 handleSection(cmdName);
5323 retval = RetVal_Paragraph;
5328 doctokenizerYYsetStateCode();
5329 retval = handleStartCode();
5334 doctokenizerYYsetStateHtmlOnly();
5335 retval = doctokenizerYYlex();
5336 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
5337 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: htmlonly section ended without end marker");
5338 doctokenizerYYsetStatePara();
5343 doctokenizerYYsetStateManOnly();
5344 retval = doctokenizerYYlex();
5345 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
5346 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: manonly section ended without end marker");
5347 doctokenizerYYsetStatePara();
5352 doctokenizerYYsetStateRtfOnly();
5353 retval = doctokenizerYYlex();
5354 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::RtfOnly,g_isExample,g_exampleName));
5355 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: rtfonly section ended without end marker");
5356 doctokenizerYYsetStatePara();
5361 doctokenizerYYsetStateLatexOnly();
5362 retval = doctokenizerYYlex();
5363 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
5364 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: latexonly section ended without end marker");
5365 doctokenizerYYsetStatePara();
5370 doctokenizerYYsetStateXmlOnly();
5371 retval = doctokenizerYYlex();
5372 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
5373 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: xmlonly section ended without end marker");
5374 doctokenizerYYsetStatePara();
5379 doctokenizerYYsetStateVerbatim();
5380 retval = doctokenizerYYlex();
5381 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName));
5382 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: verbatim section ended without end marker");
5383 doctokenizerYYsetStatePara();
5388 doctokenizerYYsetStateDot();
5389 retval = doctokenizerYYlex();
5390 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName));
5391 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: dot section ended without end marker");
5392 doctokenizerYYsetStatePara();
5397 doctokenizerYYsetStateMsc();
5398 retval = doctokenizerYYlex();
5399 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName));
5400 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: msc section ended without end marker");
5401 doctokenizerYYsetStatePara();
5405 case CMD_ENDHTMLONLY:
5406 case CMD_ENDMANONLY:
5407 case CMD_ENDRTFONLY:
5408 case CMD_ENDLATEXONLY:
5409 case CMD_ENDXMLONLY:
5411 case CMD_ENDVERBATIM:
5413 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5416 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5419 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
5422 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir);
5425 retval = handleParamSection(cmdName,DocParamSect::RetVal);
5428 retval = handleParamSection(cmdName,DocParamSect::Exception);
5431 retval = handleXRefItem();
5435 DocLineBreak *lb = new DocLineBreak(this);
5436 m_children.append(lb);
5441 DocAnchor *anchor = handleAnchor(this);
5444 m_children.append(anchor);
5450 DocIndexEntry *ie = new DocIndexEntry(this,
5451 g_scope!=Doxygen::globalScope?g_scope:0,
5453 m_children.append(ie);
5454 retval = ie->parse();
5458 retval = RetVal_Internal;
5460 case CMD_COPYDOC: // fall through
5461 case CMD_COPYBRIEF: // fall through
5462 case CMD_COPYDETAILS:
5464 int tok=doctokenizerYYlex();
5465 if (tok!=TK_WHITESPACE)
5467 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
5471 tok=doctokenizerYYlex();
5474 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
5475 "argument of command %s\n", qPrint(cmdName));
5478 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
5480 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5481 tokToString(tok),qPrint(cmdName));
5484 DocCopy *cpy = new DocCopy(this,g_token->name,
5485 cmdId==CMD_COPYDOC || cmdId==CMD_COPYBRIEF,
5486 cmdId==CMD_COPYDOC || cmdId==CMD_COPYDETAILS);
5487 //m_children.append(cpy);
5488 cpy->parse(m_children);
5493 handleInclude(cmdName,DocInclude::Include);
5495 case CMD_INCWITHLINES:
5496 handleInclude(cmdName,DocInclude::IncWithLines);
5498 case CMD_DONTINCLUDE:
5499 handleInclude(cmdName,DocInclude::DontInclude);
5501 case CMD_HTMLINCLUDE:
5502 handleInclude(cmdName,DocInclude::HtmlInclude);
5504 case CMD_VERBINCLUDE:
5505 handleInclude(cmdName,DocInclude::VerbInclude);
5508 handleInclude(cmdName,DocInclude::Snippet);
5511 handleIncludeOperator(cmdName,DocIncOperator::Skip);
5514 handleIncludeOperator(cmdName,DocIncOperator::Until);
5517 handleIncludeOperator(cmdName,DocIncOperator::SkipLine);
5520 handleIncludeOperator(cmdName,DocIncOperator::Line);
5523 handleImage(cmdName);
5526 handleDotFile(cmdName);
5529 handleMscFile(cmdName);
5532 handleLink(cmdName,FALSE);
5535 handleLink(cmdName,TRUE);
5540 case CMD_REF: // fall through
5544 case CMD_SECREFLIST:
5546 DocSecRefList *list = new DocSecRefList(this);
5547 m_children.append(list);
5551 case CMD_SECREFITEM:
5552 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5554 case CMD_ENDSECREFLIST:
5555 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5559 DocFormula *form=new DocFormula(this,g_token->id);
5560 m_children.append(form);
5563 //case CMD_LANGSWITCH:
5564 // retval = handleLanguageSwitch();
5566 case CMD_INTERNALREF:
5567 //warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5569 DocInternalRef *ref = handleInternalRef(this);
5572 m_children.append(ref);
5575 doctokenizerYYsetStatePara();
5578 case CMD_INHERITDOC:
5582 // we should not get here!
5586 INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec ||
5587 retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA ||
5588 retval==RetVal_Section || retval==RetVal_EndList ||
5589 retval==RetVal_Internal || retval==RetVal_SwitchLang
5591 DBG(("handleCommand(%s) end retval=%x\n",qPrint(cmdName),retval));
5595 static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
5596 const char *attrName,
5600 HtmlAttribListIterator li(tagHtmlAttribs);
5602 for (li.toFirst();(opt=li.current());++li)
5604 if (opt->name==attrName)
5606 *result = opt->value;
5613 int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
5615 DBG(("handleHtmlStartTag(%s,%d)\n",qPrint(tagName),tagHtmlAttribs.count()));
5616 int retval=RetVal_OK;
5617 int tagId = Mappers::htmlTagMapper->map(tagName);
5618 if (g_token->emptyTag && !(tagId&XML_CmdMask) &&
5619 tagId!=HTML_UNKNOWN && tagId!=HTML_IMG && tagId!=HTML_BR)
5621 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: HTML tags may not use the 'empty tag' XHTML syntax.");
5627 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered);
5628 m_children.append(list);
5629 retval=list->parse();
5634 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered);
5635 m_children.append(list);
5636 retval=list->parse();
5640 if (!insideUL(this) && !insideOL(this))
5642 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: lonely <li> tag found");
5646 retval=RetVal_ListItem;
5650 handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
5653 if (/*getLanguageFromFileName(g_fileName)==SrcLangExt_CSharp ||*/ g_xmlComment)
5654 // for C# source or inside a <summary> or <remark> section we
5655 // treat <code> as an XML tag (so similar to @code)
5657 doctokenizerYYsetStateXmlCode();
5658 retval = handleStartCode();
5660 else // normal HTML markup
5662 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
5666 handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
5669 handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs);
5672 handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs);
5675 handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs);
5678 handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs);
5681 handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs);
5684 handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs);
5687 handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
5688 setInsidePreformatted(TRUE);
5689 doctokenizerYYsetInsidePre(TRUE);
5696 DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs);
5697 m_children.append(list);
5698 retval=list->parse();
5702 retval = RetVal_DescTitle;
5705 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag <dd> found");
5709 DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
5710 m_children.append(table);
5711 retval=table->parse();
5715 retval = RetVal_TableRow;
5718 retval = RetVal_TableCell;
5721 retval = RetVal_TableHCell;
5724 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag <caption> found");
5728 DocLineBreak *lb = new DocLineBreak(this);
5729 m_children.append(lb);
5734 DocHorRuler *hr = new DocHorRuler(this);
5735 m_children.append(hr);
5739 retval=handleAHref(this,m_children,tagHtmlAttribs);
5742 retval=handleHtmlHeader(tagHtmlAttribs,1);
5745 retval=handleHtmlHeader(tagHtmlAttribs,2);
5748 retval=handleHtmlHeader(tagHtmlAttribs,3);
5751 retval=handleHtmlHeader(tagHtmlAttribs,4);
5754 retval=handleHtmlHeader(tagHtmlAttribs,5);
5757 retval=handleHtmlHeader(tagHtmlAttribs,6);
5761 HtmlAttribListIterator li(tagHtmlAttribs);
5765 for (li.toFirst();(opt=li.current());++li,++index)
5767 //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
5768 if (opt->name=="src" && !opt->value.isEmpty())
5771 HtmlAttribList attrList = tagHtmlAttribs;
5772 // and remove the src attribute
5773 bool result = attrList.remove(index);
5775 DocImage *img = new DocImage(this,attrList,opt->value,DocImage::Html,opt->value);
5776 m_children.append(img);
5782 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: IMG tag does not have a SRC attribute!\n");
5786 case HTML_BLOCKQUOTE:
5788 DocHtmlBlockQuote *block = new DocHtmlBlockQuote(this,tagHtmlAttribs);
5789 m_children.append(block);
5790 retval = block->parse();
5800 if (!m_children.isEmpty())
5802 retval = TK_NEWPARA;
5806 case XML_DESCRIPTION:
5807 if (insideTable(this))
5809 retval=RetVal_TableCell;
5813 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
5819 if (findAttribute(tagHtmlAttribs,"name",¶mName))
5821 if (paramName.isEmpty())
5823 if (Config_getBool("WARN_NO_PARAMDOC"))
5825 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: empty 'name' attribute for <param> tag.");
5830 retval = handleParamSection(paramName,
5831 tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam,
5837 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <param> tag.");
5842 case XML_TYPEPARAMREF:
5845 if (findAttribute(tagHtmlAttribs,"name",¶mName))
5847 //printf("paramName=%s\n",paramName.data());
5848 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
5849 m_children.append(new DocWord(this,paramName));
5850 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
5851 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5855 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type");
5861 QCString exceptName;
5862 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5864 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5868 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <exception> tag.");
5873 case XML_LISTHEADER:
5874 if (insideTable(this))
5876 retval=RetVal_TableRow;
5878 else if (insideUL(this) || insideOL(this))
5880 retval=RetVal_ListItem;
5884 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: lonely <item> tag found");
5888 retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
5889 g_hasReturnCommand=TRUE;
5892 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
5893 if (insideTable(this))
5895 retval=RetVal_TableCell;
5899 // I'm not sure if <see> is the same as <seealso> or if it
5900 // should you link a member without producing a section. The
5901 // C# specification is extremely vague about this (but what else
5902 // can we expect from Microsoft...)
5905 //printf("XML_SEE: empty tag=%d\n",g_token->emptyTag);
5906 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5908 if (g_token->emptyTag) // <see cref="..."/> style
5910 bool inSeeBlock = g_inSeeBlock;
5911 g_token->name = cref;
5912 g_inSeeBlock = TRUE;
5913 handleLinkedWord(this,m_children);
5914 g_inSeeBlock = inSeeBlock;
5916 else // <see cref="...">...</see> style
5918 //DocRef *ref = new DocRef(this,cref);
5919 //m_children.append(ref);
5921 doctokenizerYYsetStatePara();
5922 DocLink *lnk = new DocLink(this,cref);
5923 m_children.append(lnk);
5924 QCString leftOver = lnk->parse(FALSE,TRUE);
5925 if (!leftOver.isEmpty())
5927 m_children.append(new DocWord(this,leftOver));
5933 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'cref' attribute from <see> tag.");
5940 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5942 // Look for an existing "see" section
5943 DocSimpleSect *ss=0;
5944 QListIterator<DocNode> cli(m_children);
5946 for (cli.toFirst();(n=cli.current());++cli)
5948 if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
5950 ss = (DocSimpleSect *)n;
5954 if (!ss) // start new section
5956 ss=new DocSimpleSect(this,DocSimpleSect::See);
5957 m_children.append(ss);
5960 ss->appendLinkWord(cref);
5965 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'cref' attribute from <seealso> tag.");
5972 findAttribute(tagHtmlAttribs,"type",&type);
5973 DocHtmlList::Type listType = DocHtmlList::Unordered;
5974 HtmlAttribList emptyList;
5977 listType=DocHtmlList::Ordered;
5981 DocHtmlTable *table = new DocHtmlTable(this,emptyList);
5982 m_children.append(table);
5983 retval=table->parseXml();
5987 DocHtmlList *list = new DocHtmlList(this,emptyList,listType);
5988 m_children.append(list);
5989 retval=list->parseXml();
5994 case XML_PERMISSION:
5995 // These tags are defined in .Net but are currently unsupported
5998 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported xml/html tag <%s> found", qPrint(tagName));
5999 m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
6001 case XML_INHERITDOC:
6006 // we should not get here!
6013 int DocPara::handleHtmlEndTag(const QCString &tagName)
6015 DBG(("handleHtmlEndTag(%s)\n",qPrint(tagName)));
6016 int tagId = Mappers::htmlTagMapper->map(tagName);
6017 int retval=RetVal_OK;
6021 if (!insideUL(this))
6023 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </ul> tag without matching <ul>");
6027 retval=RetVal_EndList;
6031 if (!insideOL(this))
6033 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </ol> tag without matching <ol>");
6037 retval=RetVal_EndList;
6041 if (!insideLI(this))
6043 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </li> tag without matching <li>");
6047 // ignore </li> tags
6050 case HTML_BLOCKQUOTE:
6051 retval=RetVal_EndBlockQuote;
6054 // if (!insidePRE(this))
6056 // warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </pre> tag without matching <pre>");
6060 // retval=RetVal_EndPre;
6064 handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
6067 handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
6070 handleStyleLeave(this,m_children,DocStyleChange::Italic,"em");
6073 handleStyleLeave(this,m_children,DocStyleChange::Div,"div");
6076 handleStyleLeave(this,m_children,DocStyleChange::Span,"span");
6079 handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub");
6082 handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup");
6085 handleStyleLeave(this,m_children,DocStyleChange::Center,"center");
6088 handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
6091 handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
6092 setInsidePreformatted(FALSE);
6093 doctokenizerYYsetInsidePre(FALSE);
6099 retval=RetVal_EndDesc;
6108 retval=RetVal_EndTable;
6120 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </caption> found");
6123 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal </br> tag found\n");
6126 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h1> found");
6129 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h2> found");
6132 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h3> found");
6135 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </img> found");
6138 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </hr> found");
6141 //warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </a> found");
6142 // ignore </a> tag (can be part of <a name=...></a>
6146 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
6160 case XML_INHERITDOC:
6161 retval = RetVal_CloseXml;
6164 handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
6167 case XML_LISTHEADER:
6169 case XML_PERMISSION:
6170 case XML_DESCRIPTION:
6172 case XML_TYPEPARAMREF:
6173 // These tags are defined in .Net but are currently unsupported
6176 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported xml/html tag </%s> found", qPrint(tagName));
6177 m_children.append(new DocWord(this,"</"+tagName+">"));
6180 // we should not get here!
6181 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",qPrint(tagName));
6188 int DocPara::parse()
6190 DBG(("DocPara::parse() start\n"));
6191 g_nodeStack.push(this);
6192 // handle style commands "inherited" from the previous paragraph
6193 handleInitialStyleCommands(this,m_children);
6196 while ((tok=doctokenizerYYlex())) // get the next token
6199 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
6200 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
6201 tok==TK_COMMAND || tok==TK_HTMLTAG
6204 DBG((" name=%s",qPrint(g_token->name)));
6210 m_children.append(new DocWord(this,g_token->name));
6213 handleLinkedWord(this,m_children);
6216 m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr));
6220 // prevent leading whitespace and collapse multiple whitespace areas
6222 if (insidePRE(this) || // all whitespace is relevant
6224 // remove leading whitespace
6225 !m_children.isEmpty() &&
6226 // and whitespace after certain constructs
6227 (k=m_children.last()->kind())!=DocNode::Kind_HtmlDescList &&
6228 k!=DocNode::Kind_HtmlTable &&
6229 k!=DocNode::Kind_HtmlList &&
6230 k!=DocNode::Kind_SimpleSect &&
6231 k!=DocNode::Kind_AutoList &&
6232 k!=DocNode::Kind_SimpleList &&
6233 /*k!=DocNode::Kind_Verbatim &&*/
6234 k!=DocNode::Kind_HtmlHeader &&
6235 k!=DocNode::Kind_HtmlBlockQuote &&
6236 k!=DocNode::Kind_ParamSect &&
6237 k!=DocNode::Kind_XRefItem
6241 m_children.append(new DocWhiteSpace(this,g_token->chars));
6247 DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind()));
6248 DocNode *n=parent();
6249 while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent();
6250 if (n) // we found an auto list up in the hierarchy
6252 DocAutoList *al = (DocAutoList *)n;
6253 DBG(("previous list item at %d\n",al->indent()));
6254 if (al->indent()>=g_token->indent)
6255 // new item at the same or lower indent level
6262 // determine list depth
6267 if (n->kind() == DocNode::Kind_AutoList &&
6268 ((DocAutoList*)n)->isEnumList()) depth++;
6272 // first item or sub list => create new list
6276 al = new DocAutoList(this,g_token->indent,
6277 g_token->isEnumList,depth);
6278 m_children.append(al);
6279 retval = al->parse();
6280 } while (retval==TK_LISTITEM && // new list
6281 al->indent()==g_token->indent // at same indent level
6284 // check the return value
6285 if (retval==RetVal_SimpleSec) // auto list ended due to simple section command
6287 // Reparse the token that ended the section at this level,
6288 // so a new simple section will be started at this level.
6289 // This is the same as unputting the last read token and continuing.
6290 g_token->name = g_token->simpleSectName;
6291 if (g_token->name.left(4)=="rcs:") // RCS section
6293 g_token->name = g_token->name.mid(4);
6294 g_token->text = g_token->simpleSectText;
6297 else // other section
6301 DBG(("reparsing command %s\n",qPrint(g_token->name)));
6304 else if (retval==TK_ENDLIST)
6306 if (al->indent()>g_token->indent) // end list
6310 else // continue with current paragraph
6314 else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF
6321 DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno));
6322 if (parent()->kind()==DocNode::Kind_AutoListItem)
6324 ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList);
6325 DocAutoList *al = (DocAutoList *)parent()->parent();
6326 if (al->indent()>=g_token->indent)
6328 // end of list marker ends this paragraph
6334 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: End of list marker found "
6335 "has invalid indent level");
6340 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: End of list marker found without any preceding "
6346 // see if we have to start a simple section
6347 int cmd = Mappers::cmdMapper->map(g_token->name);
6348 DocNode *n=parent();
6350 n->kind()!=DocNode::Kind_SimpleSect &&
6351 n->kind()!=DocNode::Kind_ParamSect
6356 if (cmd&SIMPLESECT_BIT)
6358 if (n) // already in a simple section
6360 // simple section cannot start in this paragraph, need
6361 // to unwind the stack and remember the command.
6362 g_token->simpleSectName = g_token->name.copy();
6363 retval=RetVal_SimpleSec;
6367 // see if we are in a simple list
6369 while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent();
6374 retval=RetVal_ListItem;
6379 // handle the command
6380 retval=handleCommand(g_token->name.copy());
6381 DBG(("handleCommand returns %x\n",retval));
6383 // check the return value
6384 if (retval==RetVal_SimpleSec)
6386 // Reparse the token that ended the section at this level,
6387 // so a new simple section will be started at this level.
6388 // This is the same as unputting the last read token and continuing.
6389 g_token->name = g_token->simpleSectName;
6390 if (g_token->name.left(4)=="rcs:") // RCS section
6392 g_token->name = g_token->name.mid(4);
6393 g_token->text = g_token->simpleSectText;
6396 else // other section
6400 DBG(("reparsing command %s\n",qPrint(g_token->name)));
6403 else if (retval==RetVal_OK)
6405 // the command ended normally, keep scanning for new tokens.
6408 else if (retval>0 && retval<RetVal_OK)
6410 // the command ended with a new command, reparse this token
6414 else // end of file, end of paragraph, start or end of section
6415 // or some auto list marker
6423 if (!g_token->endTag) // found a start tag
6425 retval = handleHtmlStartTag(g_token->name,g_token->attribs);
6427 else // found an end tag
6429 retval = handleHtmlEndTag(g_token->name);
6431 if (retval==RetVal_OK)
6433 // the command ended normally, keep scanner for new tokens.
6445 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
6446 if (s!=DocSymbol::Unknown)
6448 m_children.append(new DocSymbol(this,s,letter));
6452 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
6453 qPrint(g_token->name));
6462 DocNode *n=parent();
6464 n->kind()!=DocNode::Kind_SimpleSect &&
6465 n->kind()!=DocNode::Kind_ParamSect
6470 if (n) // already in a simple section
6472 // simple section cannot start in this paragraph, need
6473 // to unwind the stack and remember the command.
6474 g_token->simpleSectName = "rcs:"+g_token->name;
6475 g_token->simpleSectText = g_token->text;
6476 retval=RetVal_SimpleSec;
6480 // see if we are in a simple list
6481 DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs);
6482 m_children.append(ss);
6487 warn_doc_error(g_fileName,doctokenizerYYlineno,
6488 "warning: Found unexpected token (id=%x)\n",tok);
6494 handlePendingStyleCommands(this,m_children);
6495 DocNode *n = g_nodeStack.pop();
6497 DBG(("DocPara::parse() end retval=%x\n",retval));
6498 INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM ||
6499 retval==TK_ENDLIST || retval>RetVal_OK
6505 //--------------------------------------------------------------------------
6507 int DocSection::parse()
6509 DBG(("DocSection::parse() start %s level=%d\n",qPrint(g_token->sectionId),m_level));
6510 int retval=RetVal_OK;
6511 g_nodeStack.push(this);
6514 if (!m_id.isEmpty())
6516 sec=Doxygen::sectionDict[m_id];
6519 m_file = sec->fileName;
6520 m_anchor = sec->label;
6521 m_title = sec->title;
6522 if (m_title.isEmpty()) m_title = sec->label;
6523 if (g_sectionDict && g_sectionDict->find(m_id)==0)
6525 g_sectionDict->append(m_id,sec);
6530 // first parse any number of paragraphs
6535 DocPara *par = new DocPara(this);
6536 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6537 retval=par->parse();
6538 if (!par->isEmpty())
6540 m_children.append(par);
6547 if (retval==TK_LISTITEM)
6549 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found");
6551 } while (retval!=0 &&
6552 retval!=RetVal_Internal &&
6553 retval!=RetVal_Section &&
6554 retval!=RetVal_Subsection &&
6555 retval!=RetVal_Subsubsection &&
6556 retval!=RetVal_Paragraph
6559 if (lastPar) lastPar->markLast();
6561 //printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel);
6563 if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1)
6565 // then parse any number of nested sections
6566 while (retval==RetVal_Subsection) // more sections follow
6568 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6569 DocSection *s=new DocSection(this,
6570 QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6571 m_children.append(s);
6572 retval = s->parse();
6575 else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2)
6577 // then parse any number of nested sections
6578 while (retval==RetVal_Subsubsection) // more sections follow
6580 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6581 DocSection *s=new DocSection(this,
6582 QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6583 m_children.append(s);
6584 retval = s->parse();
6587 else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3))
6589 // then parse any number of nested sections
6590 while (retval==RetVal_Paragraph) // more sections follow
6592 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6593 DocSection *s=new DocSection(this,
6594 QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6595 m_children.append(s);
6596 retval = s->parse();
6599 else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) ||
6600 (m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph)
6604 if (retval==RetVal_Subsection) level=2;
6605 else if (retval==RetVal_Subsubsection) level=3;
6607 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected %s "
6608 "command found inside %s!",
6609 sectionLevelToName[level],sectionLevelToName[m_level]);
6610 retval=0; // stop parsing
6613 else if (retval==RetVal_Internal)
6615 DocInternal *in = new DocInternal(this);
6616 m_children.append(in);
6617 retval = in->parse(m_level+1);
6623 INTERNAL_ASSERT(retval==0 ||
6624 retval==RetVal_Section ||
6625 retval==RetVal_Subsection ||
6626 retval==RetVal_Subsubsection ||
6627 retval==RetVal_Paragraph ||
6628 retval==RetVal_Internal
6631 DBG(("DocSection::parse() end\n"));
6632 DocNode *n = g_nodeStack.pop();
6637 //--------------------------------------------------------------------------
6639 void DocText::parse()
6641 DBG(("DocText::parse() start\n"));
6642 g_nodeStack.push(this);
6643 doctokenizerYYsetStateText();
6646 while ((tok=doctokenizerYYlex())) // get the next token
6651 m_children.append(new DocWord(this,g_token->name));
6654 m_children.append(new DocWhiteSpace(this,g_token->chars));
6659 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
6660 if (s!=DocSymbol::Unknown)
6662 m_children.append(new DocSymbol(this,s,letter));
6666 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
6667 qPrint(g_token->name));
6672 switch (Mappers::cmdMapper->map(g_token->name))
6675 m_children.append(new DocSymbol(this,DocSymbol::BSlash));
6678 m_children.append(new DocSymbol(this,DocSymbol::At));
6681 m_children.append(new DocSymbol(this,DocSymbol::Less));
6684 m_children.append(new DocSymbol(this,DocSymbol::Greater));
6687 m_children.append(new DocSymbol(this,DocSymbol::Amp));
6690 m_children.append(new DocSymbol(this,DocSymbol::Dollar));
6693 m_children.append(new DocSymbol(this,DocSymbol::Hash));
6696 m_children.append(new DocSymbol(this,DocSymbol::DoubleColon));
6699 m_children.append(new DocSymbol(this,DocSymbol::Percent));
6702 m_children.append(new DocSymbol(this,DocSymbol::Quot));
6705 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected command `%s' found",
6706 qPrint(g_token->name));
6711 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
6717 handleUnclosedStyleCommands();
6719 DocNode *n = g_nodeStack.pop();
6721 DBG(("DocText::parse() end\n"));
6725 //--------------------------------------------------------------------------
6727 void DocRoot::parse()
6729 DBG(("DocRoot::parse() start\n"));
6730 g_nodeStack.push(this);
6731 doctokenizerYYsetStatePara();
6734 // first parse any number of paragraphs
6739 DocPara *par = new DocPara(this);
6740 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6741 retval=par->parse();
6742 if (!par->isEmpty())
6744 m_children.append(par);
6751 if (retval==TK_LISTITEM)
6753 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found");
6755 else if (retval==RetVal_Subsection)
6757 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found subsection command outside of section context!");
6759 else if (retval==RetVal_Subsubsection)
6761 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found subsubsection command outside of subsection context!");
6763 else if (retval==RetVal_Paragraph)
6765 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found paragraph command outside of subsubsection context!");
6767 } while (retval!=0 && retval!=RetVal_Section && retval!=RetVal_Internal);
6768 if (lastPar) lastPar->markLast();
6770 //printf("DocRoot::parse() retval=%d %d\n",retval,RetVal_Section);
6771 // then parse any number of level1 sections
6772 while (retval==RetVal_Section)
6774 SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6777 DocSection *s=new DocSection(this,
6778 QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6779 m_children.append(s);
6780 retval = s->parse();
6784 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid section id `%s'; ignoring section",qPrint(g_token->sectionId));
6789 if (retval==RetVal_Internal)
6791 DocInternal *in = new DocInternal(this);
6792 m_children.append(in);
6793 retval = in->parse(1);
6797 handleUnclosedStyleCommands();
6799 DocNode *n = g_nodeStack.pop();
6801 DBG(("DocRoot::parse() end\n"));
6804 //--------------------------------------------------------------------------
6806 DocNode *validatingParseDoc(const char *fileName,int startLine,
6807 Definition *ctx,MemberDef *md,
6808 const char *input,bool indexWords,
6809 bool isExample, const char *exampleName,
6810 bool singleLine, bool linkFromIndex)
6812 //printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>",
6813 // md?md->name().data():"<none>",
6815 //printf("========== validating %s at line %d\n",fileName,startLine);
6816 //printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input);
6817 //g_token = new TokenInfo;
6819 // store parser state so we can re-enter this function if needed
6820 //bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
6821 docParserPushContext();
6823 if (ctx && ctx!=Doxygen::globalScope &&
6824 (ctx->definitionType()==Definition::TypeClass ||
6825 ctx->definitionType()==Definition::TypeNamespace
6829 g_context = ctx->name();
6831 else if (ctx && ctx->definitionType()==Definition::TypePage)
6833 Definition *scope = ((PageDef*)ctx)->getPageScope();
6834 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
6836 else if (ctx && ctx->definitionType()==Definition::TypeGroup)
6838 Definition *scope = ((GroupDef*)ctx)->getGroupScope();
6839 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
6847 if (indexWords && Doxygen::searchIndex)
6851 g_searchUrl=md->getOutputFileBase();
6852 Doxygen::searchIndex->setCurrentDoc(md,md->anchor(),FALSE);
6856 g_searchUrl=ctx->getOutputFileBase();
6857 Doxygen::searchIndex->setCurrentDoc(ctx,ctx->anchor(),FALSE);
6861 if (indexWords && md && Doxygen::searchIndex)
6863 g_searchUrl=md->getOutputFileBase();
6864 Doxygen::searchIndex->setCurrentDoc(
6865 (md->getLanguage()==SrcLangExt_Fortran ?
6866 theTranslator->trSubprogram(TRUE,TRUE):
6867 theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(),
6871 else if (indexWords && ctx && Doxygen::searchIndex)
6873 g_searchUrl=ctx->getOutputFileBase();
6874 QCString name = ctx->qualifiedName();
6876 SrcLangExt lang = ctx->getLanguage();
6877 QCString sep = getLanguageSpecificSeparator(lang);
6880 name = substitute(name,"::",sep);
6883 switch (ctx->definitionType())
6885 case Definition::TypePage:
6887 PageDef *pd = (PageDef *)ctx;
6888 if (!pd->title().isEmpty())
6890 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title();
6894 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name();
6898 case Definition::TypeClass:
6900 ClassDef *cd = (ClassDef *)ctx;
6901 name.prepend(cd->compoundTypeString()+" ");
6904 case Definition::TypeNamespace:
6906 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
6908 name = theTranslator->trPackage(name);
6910 else if (lang==SrcLangExt_Fortran)
6912 name.prepend(theTranslator->trModule(TRUE,TRUE)+" ");
6916 name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" ");
6920 case Definition::TypeGroup:
6922 GroupDef *gd = (GroupDef *)ctx;
6923 if (gd->groupTitle())
6925 name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle();
6929 name.prepend(theTranslator->trGroup(TRUE,TRUE)+" ");
6936 Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl);
6944 g_fileName = fileName;
6945 g_relPath = (!linkFromIndex && ctx) ?
6946 QCString(relativePathToRoot(ctx->getOutputFileBase())) :
6948 //printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data());
6950 g_nodeStack.clear();
6951 g_styleStack.clear();
6952 g_initialStyleStack.clear();
6953 g_inSeeBlock = FALSE;
6954 g_xmlComment = FALSE;
6955 g_insideHtmlLink = FALSE;
6956 g_includeFileText = "";
6957 g_includeFileOffset = 0;
6958 g_includeFileLength = 0;
6959 g_isExample = isExample;
6960 g_exampleName = exampleName;
6961 g_hasParamCommand = FALSE;
6962 g_hasReturnCommand = FALSE;
6963 g_paramsFound.setAutoDelete(FALSE);
6964 g_paramsFound.clear();
6965 g_sectionDict = 0; //sections;
6967 //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
6968 doctokenizerYYlineno=startLine;
6969 doctokenizerYYinit(input,g_fileName);
6972 // build abstract syntax tree
6973 DocRoot *root = new DocRoot(md!=0,singleLine);
6977 if (Debug::isFlagSet(Debug::PrintTree))
6979 // pretty print the result
6980 PrintDocVisitor *v = new PrintDocVisitor;
6985 checkUndocumentedParams();
6986 detectNoDocumentedParams();
6988 // TODO: These should be called at the end of the program.
6989 //doctokenizerYYcleanup();
6990 //Mappers::cmdMapper->freeInstance();
6991 //Mappers::htmlTagMapper->freeInstance();
6993 // restore original parser state
6994 docParserPopContext();
6996 //printf(">>>>>> end validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>",
6997 // md?md->name().data():"<none>");
7002 DocNode *validatingParseText(const char *input)
7004 // store parser state so we can re-enter this function if needed
7005 docParserPushContext();
7007 //printf("------------ input ---------\n%s\n"
7008 // "------------ end input -----\n",input);
7009 //g_token = new TokenInfo;
7011 g_fileName = "<parseText>";
7014 g_nodeStack.clear();
7015 g_styleStack.clear();
7016 g_initialStyleStack.clear();
7017 g_inSeeBlock = FALSE;
7018 g_xmlComment = FALSE;
7019 g_insideHtmlLink = FALSE;
7020 g_includeFileText = "";
7021 g_includeFileOffset = 0;
7022 g_includeFileLength = 0;
7023 g_isExample = FALSE;
7025 g_hasParamCommand = FALSE;
7026 g_hasReturnCommand = FALSE;
7027 g_paramsFound.setAutoDelete(FALSE);
7028 g_paramsFound.clear();
7031 DocText *txt = new DocText;
7035 doctokenizerYYlineno=1;
7036 doctokenizerYYinit(input,g_fileName);
7038 // build abstract syntax tree
7041 if (Debug::isFlagSet(Debug::PrintTree))
7043 // pretty print the result
7044 PrintDocVisitor *v = new PrintDocVisitor;
7050 // restore original parser state
7051 docParserPopContext();
7055 void docFindSections(const char *input,
7058 const char *fileName)
7060 doctokenizerYYFindSections(input,d,mg,fileName);