1 /******************************************************************************
6 * Copyright (C) 1997-2015 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>
29 #include <qcstringlist.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"
46 #include "vhdldocgen.h"
48 #include "classlist.h"
50 #include "memberdef.h"
51 #include "namespacedef.h"
57 #include "htmlentity.h"
60 #define TK_COMMAND_CHAR(token) ((token)==TK_COMMAND_AT ? '@' : '\\')
63 #define DBG(x) do {} while(0)
66 //#define DBG(x) printf x
69 //#define myprintf(x...) fprintf(stderr,x)
70 //#define DBG(x) myprintf x
72 #define INTERNAL_ASSERT(x) do {} while(0)
73 //#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__));
75 //---------------------------------------------------------------------------
77 static const char *sectionLevelToName[] =
87 //---------------------------------------------------------------------------
89 // Parser state: global variables during a call to validatingParseDoc
90 static Definition * g_scope;
91 static QCString g_context;
92 static bool g_inSeeBlock;
93 static bool g_xmlComment;
94 static bool g_insideHtmlLink;
95 static QStack<DocNode> g_nodeStack;
96 static QStack<DocStyleChange> g_styleStack;
97 static QStack<DocStyleChange> g_initialStyleStack;
98 static QList<Definition> g_copyStack;
99 static QCString g_fileName;
100 static QCString g_relPath;
102 static bool g_hasParamCommand;
103 static bool g_hasReturnCommand;
104 static QDict<void> g_paramsFound;
105 static MemberDef * g_memberDef;
106 static bool g_isExample;
107 static QCString g_exampleName;
108 static SectionDict * g_sectionDict;
109 static QCString g_searchUrl;
111 static QCString g_includeFileName;
112 static QCString g_includeFileText;
113 static uint g_includeFileOffset;
114 static uint g_includeFileLength;
117 /** Parser's context to store all global variables.
119 struct DocParserContext
126 QStack<DocNode> nodeStack;
127 QStack<DocStyleChange> styleStack;
128 QStack<DocStyleChange> initialStyleStack;
129 QList<Definition> copyStack;
134 bool hasParamCommand;
135 bool hasReturnCommand;
136 MemberDef * memberDef;
137 QDict<void> paramsFound;
139 QCString exampleName;
140 SectionDict *sectionDict;
143 QCString includeFileText;
144 uint includeFileOffset;
145 uint includeFileLength;
150 static QStack<DocParserContext> g_parserStack;
152 //---------------------------------------------------------------------------
153 static void handleImg(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs);
155 //---------------------------------------------------------------------------
156 static void docParserPushContext(bool saveParamInfo=TRUE)
159 //indent.fill(' ',g_parserStack.count()*2+2);
160 //printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count());
162 doctokenizerYYpushContext();
163 DocParserContext *ctx = new DocParserContext;
164 ctx->scope = g_scope;
165 ctx->context = g_context;
166 ctx->inSeeBlock = g_inSeeBlock;
167 ctx->xmlComment = g_xmlComment;
168 ctx->insideHtmlLink = g_insideHtmlLink;
169 ctx->nodeStack = g_nodeStack;
170 ctx->styleStack = g_styleStack;
171 ctx->initialStyleStack = g_initialStyleStack;
172 ctx->copyStack = g_copyStack;
173 ctx->fileName = g_fileName;
174 ctx->lineNo = doctokenizerYYlineno;
175 ctx->relPath = g_relPath;
179 ctx->hasParamCommand = g_hasParamCommand;
180 ctx->hasReturnCommand = g_hasReturnCommand;
181 ctx->paramsFound = g_paramsFound;
184 ctx->memberDef = g_memberDef;
185 ctx->isExample = g_isExample;
186 ctx->exampleName = g_exampleName;
187 ctx->sectionDict = g_sectionDict;
188 ctx->searchUrl = g_searchUrl;
190 ctx->includeFileText = g_includeFileText;
191 ctx->includeFileOffset = g_includeFileOffset;
192 ctx->includeFileLength = g_includeFileLength;
194 ctx->token = g_token;
195 g_token = new TokenInfo;
197 g_parserStack.push(ctx);
200 static void docParserPopContext(bool keepParamInfo=FALSE)
202 DocParserContext *ctx = g_parserStack.pop();
203 g_scope = ctx->scope;
204 g_context = ctx->context;
205 g_inSeeBlock = ctx->inSeeBlock;
206 g_xmlComment = ctx->xmlComment;
207 g_insideHtmlLink = ctx->insideHtmlLink;
208 g_nodeStack = ctx->nodeStack;
209 g_styleStack = ctx->styleStack;
210 g_initialStyleStack = ctx->initialStyleStack;
211 g_copyStack = ctx->copyStack;
212 g_fileName = ctx->fileName;
213 doctokenizerYYlineno = ctx->lineNo;
214 g_relPath = ctx->relPath;
218 g_hasParamCommand = ctx->hasParamCommand;
219 g_hasReturnCommand = ctx->hasReturnCommand;
220 g_paramsFound = ctx->paramsFound;
222 g_memberDef = ctx->memberDef;
223 g_isExample = ctx->isExample;
224 g_exampleName = ctx->exampleName;
225 g_sectionDict = ctx->sectionDict;
226 g_searchUrl = ctx->searchUrl;
228 g_includeFileText = ctx->includeFileText;
229 g_includeFileOffset = ctx->includeFileOffset;
230 g_includeFileLength = ctx->includeFileLength;
233 g_token = ctx->token;
236 doctokenizerYYpopContext();
239 //indent.fill(' ',g_parserStack.count()*2+2);
240 //printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count());
243 //---------------------------------------------------------------------------
245 // replaces { with < and } with > and also
246 // replaces > with < and > with > within string s
247 static void unescapeCRef(QCString &s)
250 char *p = tmp.rawData();
256 if (c=='{') c='<'; else if (c=='}') c='>';
261 tmp=substitute(tmp,"<","<");
262 tmp=substitute(tmp,">",">");
266 //---------------------------------------------------------------------------
268 /*! search for an image in the imageNameDict and if found
269 * copies the image to the output directory (which depends on the \a type
272 static QCString findAndCopyImage(const char *fileName,DocImage::Type type, bool dowarn = true)
277 //printf("Search for %s\n",fileName);
278 if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
280 QCString inputFile = fd->absFilePath();
281 QFile inImage(inputFile);
282 if (inImage.open(IO_ReadOnly))
286 if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1)
288 result = result.right(result.length()-i-1);
290 //printf("fileName=%s result=%s\n",fileName,result.data());
295 if (!Config_getBool(GENERATE_HTML)) return result;
296 outputDir = Config_getString(HTML_OUTPUT);
298 case DocImage::Latex:
299 if (!Config_getBool(GENERATE_LATEX)) return result;
300 outputDir = Config_getString(LATEX_OUTPUT);
302 case DocImage::DocBook:
303 if (!Config_getBool(GENERATE_DOCBOOK)) return result;
304 outputDir = Config_getString(DOCBOOK_OUTPUT);
307 if (!Config_getBool(GENERATE_RTF)) return result;
308 outputDir = Config_getString(RTF_OUTPUT);
311 QCString outputFile = outputDir+"/"+result;
312 QFileInfo outfi(outputFile);
313 if (outfi.isSymLink())
315 QFile::remove(outputFile);
316 warn_doc_error(g_fileName,doctokenizerYYlineno,
317 "destination of image %s is a symlink, replacing with image",
320 if (outputFile!=inputFile) // prevent copying to ourself
322 QFile outImage(outputFile.data());
323 if (outImage.open(IO_WriteOnly)) // copy the image
325 char *buffer = new char[inImage.size()];
326 inImage.readBlock(buffer,inImage.size());
327 outImage.writeBlock(buffer,inImage.size());
330 if (type==DocImage::Html) Doxygen::indexList->addImageFile(result);
334 warn_doc_error(g_fileName,doctokenizerYYlineno,
335 "could not write output image %s",qPrint(outputFile));
340 warn(g_fileName,doctokenizerYYlineno,
341 "Prevented to copy file %s onto itself!\n",qPrint(inputFile));
346 warn_doc_error(g_fileName,doctokenizerYYlineno,
347 "could not open image %s",qPrint(fileName));
350 if (type==DocImage::Latex && Config_getBool(USE_PDFLATEX) &&
351 fd->name().right(4)==".eps"
353 { // we have an .eps image in pdflatex mode => convert it to a pdf.
354 QCString outputDir = Config_getString(LATEX_OUTPUT);
355 QCString baseName = fd->name().left(fd->name().length()-4);
356 QCString epstopdfArgs(4096);
357 epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"",
358 outputDir.data(), baseName.data(),
359 outputDir.data(), baseName.data());
360 portable_sysTimerStart();
361 if (portable_system("epstopdf",epstopdfArgs)!=0)
363 err("Problems running epstopdf. Check your TeX installation!\n");
365 portable_sysTimerStop();
369 else if (ambig && dowarn)
372 text.sprintf("image file name %s is ambiguous.\n",qPrint(fileName));
373 text+="Possible candidates:\n";
374 text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
375 warn_doc_error(g_fileName,doctokenizerYYlineno,text);
380 if (result.left(5)!="http:" && result.left(6)!="https:" && dowarn)
382 warn_doc_error(g_fileName,doctokenizerYYlineno,
383 "image file %s is not found in IMAGE_PATH: "
384 "assuming external image.",qPrint(fileName)
391 /*! Collects the parameters found with \@param or \@retval commands
392 * in a global list g_paramsFound. If \a isParam is set to TRUE
393 * and the parameter is not an actual parameter of the current
394 * member g_memberDef, then a warning is raised (unless warnings
395 * are disabled altogether).
397 static void checkArgumentName(const QCString &name,bool isParam)
399 if (!Config_getBool(WARN_IF_DOC_ERROR)) return;
400 if (g_memberDef==0) return; // not a member
401 ArgumentList *al=g_memberDef->isDocsForDefinition() ?
402 g_memberDef->argumentList() :
403 g_memberDef->declArgumentList();
404 SrcLangExt lang = g_memberDef->getLanguage();
405 //printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition());
406 if (al==0) return; // no argument list
408 static QRegExp re("$?[a-zA-Z0-9_\\x80-\\xFF]+\\.*");
410 while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
412 QCString aName=name.mid(i,l);
413 if (lang==SrcLangExt_Fortran) aName=aName.lower();
414 //printf("aName=`%s'\n",aName.data());
415 ArgumentListIterator ali(*al);
418 for (ali.toFirst();(a=ali.current());++ali)
420 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
421 if (lang==SrcLangExt_Fortran) argName=argName.lower();
422 argName=argName.stripWhiteSpace();
423 //printf("argName=`%s' aName=%s\n",argName.data(),aName.data());
424 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
427 g_paramsFound.insert(aName,(void *)(0x8));
432 if (!found && isParam)
434 //printf("member type=%d\n",g_memberDef->memberType());
435 QCString scope=g_memberDef->getScopeString();
436 if (!scope.isEmpty()) scope+="::"; else scope="";
437 QCString inheritedFrom = "";
438 QCString docFile = g_memberDef->docFile();
439 int docLine = g_memberDef->docLine();
440 MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom();
441 if (inheritedMd) // documentation was inherited
443 inheritedFrom.sprintf(" inherited from member %s at line "
444 "%d in file %s",qPrint(inheritedMd->name()),
445 inheritedMd->docLine(),qPrint(inheritedMd->docFile()));
446 docFile = g_memberDef->getDefFileName();
447 docLine = g_memberDef->getDefLine();
450 QCString alStr = argListToString(al);
451 warn_doc_error(docFile,docLine,
452 "argument '%s' of command @param "
453 "is not found in the argument list of %s%s%s%s",
454 qPrint(aName), qPrint(scope), qPrint(g_memberDef->name()),
455 qPrint(alStr), qPrint(inheritedFrom));
461 /*! Checks if the parameters that have been specified using \@param are
462 * indeed all parameters and that a parameter does not have multiple
464 * Must be called after checkArgumentName() has been called for each
467 static void checkUnOrMultipleDocumentedParams()
469 if (g_memberDef && g_hasParamCommand && Config_getBool(WARN_IF_DOC_ERROR))
471 ArgumentList *al=g_memberDef->isDocsForDefinition() ?
472 g_memberDef->argumentList() :
473 g_memberDef->declArgumentList();
474 SrcLangExt lang = g_memberDef->getLanguage();
477 ArgumentListIterator ali(*al);
480 for (ali.toFirst();(a=ali.current());++ali)
483 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
484 if (lang==SrcLangExt_Fortran) argName = argName.lower();
485 argName=argName.stripWhiteSpace();
486 QCString aName = argName;
487 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
488 if (lang==SrcLangExt_Python && (argName=="self" || argName=="cls"))
490 // allow undocumented self / cls parameter for Python
492 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty())
498 QDictIterator<void> it1(g_paramsFound);
500 for (;(item1=it1.current());++it1)
502 if (argName == it1.currentKey()) count++;
507 warn_doc_error(g_memberDef->getDefFileName(),
508 g_memberDef->getDefLine(),
509 "argument '" + aName +
510 "' from the argument list of " +
511 QCString(g_memberDef->qualifiedName()) +
512 " has muliple @param documentation sections");
519 "The following parameters of "+
520 QCString(g_memberDef->qualifiedName()) +
521 QCString(argListToString(al)) +
522 " are not documented:\n";
523 for (ali.toFirst();(a=ali.current());++ali)
525 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
526 if (lang==SrcLangExt_Fortran) argName = argName.lower();
527 argName=argName.stripWhiteSpace();
528 if (lang==SrcLangExt_Python && (argName=="self" || argName=="cls"))
530 // allow undocumented self / cls parameter for Python
532 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0)
542 errMsg+=" parameter '"+argName+"'";
545 warn_doc_error(g_memberDef->getDefFileName(),
546 g_memberDef->getDefLine(),
547 substitute(errMsg,"%","%%"));
553 /*! Check if a member has documentation for its parameter and or return
554 * type, if applicable. If found this will be stored in the member, this
555 * is needed as a member can have brief and detailed documentation, while
556 * only one of these needs to document the parameters.
558 static void detectNoDocumentedParams()
560 if (g_memberDef && Config_getBool(WARN_NO_PARAMDOC))
562 ArgumentList *al = g_memberDef->argumentList();
563 ArgumentList *declAl = g_memberDef->declArgumentList();
564 QCString returnType = g_memberDef->typeString();
565 bool isPython = g_memberDef->getLanguage()==SrcLangExt_Python;
567 if (!g_memberDef->hasDocumentedParams() &&
570 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
571 g_memberDef->setHasDocumentedParams(TRUE);
573 else if (!g_memberDef->hasDocumentedParams())
575 bool allDoc=TRUE; // no parameter => all parameters are documented
576 if ( // member has parameters
577 al!=0 && // but the member has a parameter list
578 al->count()>0 // with at least one parameter (that is not void)
581 ArgumentListIterator ali(*al);
584 // see if all parameters have documentation
585 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
587 if (!a->name.isEmpty() && a->type!="void" &&
588 !(isPython && (a->name=="self" || a->name=="cls"))
591 allDoc = !a->docs.isEmpty();
593 //printf("a->type=%s a->name=%s doc=%s\n",
594 // a->type.data(),a->name.data(),a->docs.data());
596 if (!allDoc && declAl!=0) // try declaration arguments as well
599 ArgumentListIterator ali(*declAl);
601 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
603 if (!a->name.isEmpty() && a->type!="void" &&
604 !(isPython && (a->name=="self" || a->name=="cls"))
607 allDoc = !a->docs.isEmpty();
609 //printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data());
615 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
616 g_memberDef->setHasDocumentedParams(TRUE);
619 //printf("Member %s hadDocumentedReturnType()=%d hasReturnCommand=%d\n",
620 // g_memberDef->name().data(),g_memberDef->hasDocumentedReturnType(),g_hasReturnCommand);
621 if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found
624 g_memberDef->setHasDocumentedReturnType(TRUE);
626 else if ( // see if return needs to documented
627 g_memberDef->hasDocumentedReturnType() ||
628 returnType.isEmpty() || // empty return type
629 returnType.find("void")!=-1 || // void return type
630 returnType.find("subroutine")!=-1 || // fortran subroutine
631 g_memberDef->isConstructor() || // a constructor
632 g_memberDef->isDestructor() // or destructor
635 g_memberDef->setHasDocumentedReturnType(TRUE);
637 else if ( // see if return type is documented in a function w/o return type
638 g_memberDef->hasDocumentedReturnType() &&
639 (returnType.isEmpty() || // empty return type
640 returnType.find("void")!=-1 || // void return type
641 returnType.find("subroutine")!=-1 || // fortran subroutine
642 g_memberDef->isConstructor() || // a constructor
643 g_memberDef->isDestructor() // or destructor
647 warn_doc_error(g_fileName,doctokenizerYYlineno,"documented empty return type");
653 //---------------------------------------------------------------------------
655 /*! Strips known html and tex extensions from \a text. */
656 static QCString stripKnownExtensions(const char *text)
658 QCString result=text;
659 if (result.right(4)==".tex")
661 result=result.left(result.length()-4);
663 else if (result.right(Doxygen::htmlFileExtension.length())==
664 QCString(Doxygen::htmlFileExtension))
666 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
672 //---------------------------------------------------------------------------
674 /*! Returns TRUE iff node n is a child of a preformatted node */
675 static bool insidePRE(DocNode *n)
679 if (n->isPreformatted()) return TRUE;
685 //---------------------------------------------------------------------------
687 /*! Returns TRUE iff node n is a child of a html list item node */
688 static bool insideLI(DocNode *n)
692 if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE;
698 //---------------------------------------------------------------------------
700 /*! Returns TRUE iff node n is a child of a unordered html list node */
701 static bool insideUL(DocNode *n)
705 if (n->kind()==DocNode::Kind_HtmlList &&
706 ((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE;
712 //---------------------------------------------------------------------------
714 /*! Returns TRUE iff node n is a child of a ordered html list node */
715 static bool insideOL(DocNode *n)
719 if (n->kind()==DocNode::Kind_HtmlList &&
720 ((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE;
726 //---------------------------------------------------------------------------
728 static bool insideTable(DocNode *n)
732 if (n->kind()==DocNode::Kind_HtmlTable) return TRUE;
738 //---------------------------------------------------------------------------
740 /*! Looks for a documentation block with name commandName in the current
741 * context (g_context). The resulting documentation string is
742 * put in pDoc, the definition in which the documentation was found is
744 * @retval TRUE if name was found.
745 * @retval FALSE if name was not found.
747 static bool findDocsForMemberOrCompound(const char *commandName,
752 //printf("findDocsForMemberOrCompound(%s)\n",commandName);
756 QCString cmdArg=substitute(commandName,"#","::");
757 int l=cmdArg.length();
758 if (l==0) return FALSE;
760 int funcStart=cmdArg.find('(');
767 // Check for the case of operator() and the like.
768 // beware of scenarios like operator()((foo)bar)
769 int secondParen = cmdArg.find('(', funcStart+1);
770 int leftParen = cmdArg.find(')', funcStart+1);
771 if (leftParen!=-1 && secondParen!=-1)
773 if (leftParen<secondParen)
775 funcStart=secondParen;
780 QCString name=removeRedundantWhiteSpace(cmdArg.left(funcStart));
781 QCString args=cmdArg.right(l-funcStart);
783 // try if the link is to a member
790 bool found = getDefs(
791 g_context.find('.')==-1?g_context.data():"", // `find('.') is a hack to detect files
793 args.isEmpty()?0:args.data(),
794 md,cd,fd,nd,gd,FALSE,0,TRUE);
795 //printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data());
798 *pDoc=md->documentation();
799 *pBrief=md->briefDescription();
805 int scopeOffset=g_context.length();
808 QCString fullName=cmdArg;
811 fullName.prepend(g_context.left(scopeOffset)+"::");
813 //printf("Trying fullName=`%s'\n",fullName.data());
815 // try class, namespace, group, page, file reference
816 cd = Doxygen::classSDict->find(fullName);
819 *pDoc=cd->documentation();
820 *pBrief=cd->briefDescription();
824 nd = Doxygen::namespaceSDict->find(fullName);
827 *pDoc=nd->documentation();
828 *pBrief=nd->briefDescription();
832 gd = Doxygen::groupSDict->find(cmdArg);
835 *pDoc=gd->documentation();
836 *pBrief=gd->briefDescription();
840 pd = Doxygen::pageSDict->find(cmdArg);
843 *pDoc=pd->documentation();
844 *pBrief=pd->briefDescription();
849 fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig);
850 if (fd && !ambig) // file
852 *pDoc=fd->documentation();
853 *pBrief=fd->briefDescription();
864 scopeOffset = g_context.findRev("::",scopeOffset-1);
865 if (scopeOffset==-1) scopeOffset=0;
867 } while (scopeOffset>=0);
872 //---------------------------------------------------------------------------
873 inline void errorHandleDefaultToken(DocNode *parent,int tok,
874 QList<DocNode> &children,const char *txt)
881 children.append(new DocWord(parent,TK_COMMAND_CHAR(tok) + g_token->name));
882 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a %s",
883 qPrint(TK_COMMAND_CHAR(tok) + g_token->name), txt);
886 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found found as part of a %s",
887 qPrint(g_token->name), txt);
890 children.append(new DocWord(parent,g_token->name));
891 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s found as part of a %s",
892 tokToString(tok), txt);
897 //---------------------------------------------------------------------------
898 // forward declaration
899 static bool defaultHandleToken(DocNode *parent,int tok,
900 QList<DocNode> &children,bool
903 static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
904 const QCString &cmdName)
906 DBG(("handleStyleArgument(%s)\n",qPrint(cmdName)));
907 QCString saveCmdName = cmdName;
908 int tok=doctokenizerYYlex();
909 if (tok!=TK_WHITESPACE)
911 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
915 while ((tok=doctokenizerYYlex()) &&
916 tok!=TK_WHITESPACE &&
922 static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
923 if (tok==TK_WORD && g_token->name.length()==1 &&
924 g_token->name.find(specialChar)!=-1)
926 // special character that ends the markup command
929 if (!defaultHandleToken(parent,tok,children))
934 if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
935 { // ignore </li> as the end of a style command
941 errorHandleDefaultToken(parent,tok,children,"\\" + saveCmdName + " command");
947 DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(cmdName),tok));
948 return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
952 /*! Called when a style change starts. For instance a \<b\> command is
955 static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
956 DocStyleChange::Style s,const HtmlAttribList *attribs)
958 DBG(("HandleStyleEnter\n"));
959 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs);
961 g_styleStack.push(sc);
964 /*! Called when a style change ends. For instance a \</b\> command is
967 static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
968 DocStyleChange::Style s,const char *tagName)
970 DBG(("HandleStyleLeave\n"));
971 if (g_styleStack.isEmpty() || // no style change
972 g_styleStack.top()->style()!=s || // wrong style change
973 g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
976 if (g_styleStack.isEmpty())
978 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </%s> tag without matching <%s>",
979 qPrint(tagName),qPrint(tagName));
981 else if (g_styleStack.top()->style()!=s)
983 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </%s> tag while expecting </%s>",
984 qPrint(tagName),qPrint(g_styleStack.top()->styleString()));
988 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </%s> at different nesting level (%d) than expected (%d)",
989 qPrint(tagName),g_nodeStack.count(),g_styleStack.top()->position());
992 else // end the section
994 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE);
1000 /*! Called at the end of a paragraph to close all open style changes
1001 * (e.g. a <b> without a </b>). The closed styles are pushed onto a stack
1002 * and entered again at the start of a new paragraph.
1004 static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
1006 if (!g_styleStack.isEmpty())
1008 DocStyleChange *sc = g_styleStack.top();
1009 while (sc && sc->position()>=g_nodeStack.count())
1010 { // there are unclosed style modifiers in the paragraph
1011 children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
1012 g_initialStyleStack.push(sc);
1014 sc = g_styleStack.top();
1019 static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
1022 while ((sc=g_initialStyleStack.pop()))
1024 handleStyleEnter(parent,children,sc->style(),&sc->attribs());
1028 static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
1030 HtmlAttribListIterator li(tagHtmlAttribs);
1033 int retval = RetVal_OK;
1034 for (li.toFirst();(opt=li.current());++li,++index)
1036 if (opt->name=="name") // <a name=label> tag
1038 if (!opt->value.isEmpty())
1040 DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE);
1041 children.append(anc);
1042 break; // stop looking for other tag attribs
1046 warn_doc_error(g_fileName,doctokenizerYYlineno,"found <a> tag with name option but without value!");
1049 else if (opt->name=="href") // <a href=url>..</a> tag
1052 HtmlAttribList attrList = tagHtmlAttribs;
1053 // and remove the href attribute
1054 bool result = attrList.remove(index);
1056 DocHRef *href = new DocHRef(parent,attrList,opt->value,g_relPath);
1057 children.append(href);
1058 g_insideHtmlLink=TRUE;
1059 retval = href->parse();
1060 g_insideHtmlLink=FALSE;
1063 else // unsupported option for tag a
1070 const char *DocStyleChange::styleString() const
1074 case DocStyleChange::Bold: return "b";
1075 case DocStyleChange::Italic: return "em";
1076 case DocStyleChange::Code: return "code";
1077 case DocStyleChange::Center: return "center";
1078 case DocStyleChange::Small: return "small";
1079 case DocStyleChange::Subscript: return "subscript";
1080 case DocStyleChange::Superscript: return "superscript";
1081 case DocStyleChange::Preformatted: return "pre";
1082 case DocStyleChange::Div: return "div";
1083 case DocStyleChange::Span: return "span";
1084 case DocStyleChange::Strike: return "strike";
1085 case DocStyleChange::Underline: return "u";
1090 static void handleUnclosedStyleCommands()
1092 if (!g_initialStyleStack.isEmpty())
1094 DocStyleChange *sc = g_initialStyleStack.top();
1095 g_initialStyleStack.pop();
1096 handleUnclosedStyleCommands();
1097 warn_doc_error(g_fileName,doctokenizerYYlineno,
1098 "end of comment block while expecting "
1099 "command </%s>",qPrint(sc->styleString()));
1103 static void handleLinkedWord(DocNode *parent,QList<DocNode> &children,bool ignoreAutoLinkFlag=FALSE)
1105 QCString name = linkToText(SrcLangExt_Unknown,g_token->name,TRUE);
1106 static bool autolinkSupport = Config_getBool(AUTOLINK_SUPPORT);
1107 if (!autolinkSupport && !ignoreAutoLinkFlag) // no autolinking -> add as normal word
1109 children.append(new DocWord(parent,name));
1113 // ------- try to turn the word 'name' into a link
1115 Definition *compound=0;
1116 MemberDef *member=0;
1117 int len = g_token->name.length();
1120 FileDef *fd = findFileDef(Doxygen::inputNameDict,g_fileName,ambig);
1121 //printf("handleLinkedWord(%s) g_context=%s\n",g_token->name.data(),g_context.data());
1122 if (!g_insideHtmlLink &&
1123 (resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member,TRUE,fd,TRUE)
1124 || (!g_context.isEmpty() && // also try with global scope
1125 resolveRef("",g_token->name,g_inSeeBlock,&compound,&member,FALSE,0,TRUE))
1129 //printf("resolveRef %s = %p (linkable?=%d)\n",qPrint(g_token->name),member,member ? member->isLinkable() : FALSE);
1130 if (member && member->isLinkable()) // member link
1132 if (member->isObjCMethod())
1134 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
1135 name = member->objCMethodName(localLink,g_inSeeBlock);
1138 DocLinkedWord(parent,name,
1139 member->getReference(),
1140 member->getOutputFileBase(),
1142 member->briefDescriptionAsTooltip()
1146 else if (compound->isLinkable()) // compound link
1148 QCString anchor = compound->anchor();
1149 if (compound->definitionType()==Definition::TypeFile)
1153 else if (compound->definitionType()==Definition::TypeGroup)
1155 name=((GroupDef*)compound)->groupTitle();
1158 DocLinkedWord(parent,name,
1159 compound->getReference(),
1160 compound->getOutputFileBase(),
1162 compound->briefDescriptionAsTooltip()
1166 else if (compound->definitionType()==Definition::TypeFile &&
1167 ((FileDef*)compound)->generateSourceFile()
1168 ) // undocumented file that has source code we can link to
1171 DocLinkedWord(parent,g_token->name,
1172 compound->getReference(),
1173 compound->getSourceFileBase(),
1175 compound->briefDescriptionAsTooltip()
1179 else // not linkable
1181 children.append(new DocWord(parent,name));
1184 else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':')
1186 // special case, where matching Foo: fails to be an Obj-C reference,
1187 // but Foo itself might be linkable.
1188 g_token->name=g_token->name.left(len-1);
1189 handleLinkedWord(parent,children,ignoreAutoLinkFlag);
1190 children.append(new DocWord(parent,":"));
1192 else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p")))
1194 // special case 2, where the token name is not a class, but could
1195 // be a Obj-C protocol
1197 DocLinkedWord(parent,name,
1199 cd->getOutputFileBase(),
1201 cd->briefDescriptionAsTooltip()
1204 // else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-g")))
1206 // // special case 3, where the token name is not a class, but could
1207 // // be a C# generic
1208 // children.append(new
1209 // DocLinkedWord(parent,name,
1210 // cd->getReference(),
1211 // cd->getOutputFileBase(),
1213 // cd->briefDescriptionAsTooltip()
1216 else // normal non-linkable word
1218 if (g_token->name.left(1)=="#" || g_token->name.left(2)=="::")
1220 warn_doc_error(g_fileName,doctokenizerYYlineno,"explicit link request to '%s' could not be resolved",qPrint(name));
1221 children.append(new DocWord(parent,g_token->name));
1225 children.append(new DocWord(parent,name));
1230 static void handleParameterType(DocNode *parent,QList<DocNode> &children,const QCString ¶mTypes)
1232 QCString name = g_token->name;
1234 while ((i=paramTypes.find('|',p))!=-1)
1236 g_token->name = paramTypes.mid(p,i-p);
1237 handleLinkedWord(parent,children);
1240 g_token->name = paramTypes.mid(p);
1241 handleLinkedWord(parent,children);
1242 g_token->name = name;
1245 static DocInternalRef *handleInternalRef(DocNode *parent)
1247 //printf("CMD_INTERNALREF\n");
1248 int tok=doctokenizerYYlex();
1249 QCString tokenName = g_token->name;
1250 if (tok!=TK_WHITESPACE)
1252 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
1256 doctokenizerYYsetStateInternalRef();
1257 tok=doctokenizerYYlex(); // get the reference id
1258 if (tok!=TK_WORD && tok!=TK_LNKWORD)
1260 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
1261 tokToString(tok),qPrint(tokenName));
1264 return new DocInternalRef(parent,g_token->name);
1267 static DocAnchor *handleAnchor(DocNode *parent)
1269 int tok=doctokenizerYYlex();
1270 if (tok!=TK_WHITESPACE)
1272 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
1273 qPrint(g_token->name));
1276 doctokenizerYYsetStateAnchor();
1277 tok=doctokenizerYYlex();
1280 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
1281 "argument of command %s",qPrint(g_token->name));
1284 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
1286 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
1287 tokToString(tok),qPrint(g_token->name));
1290 doctokenizerYYsetStatePara();
1291 return new DocAnchor(parent,g_token->name,FALSE);
1295 /* Helper function that deals with the title, width, and height arguments of various commands.
1296 * @param[in] cmd Command id for which to extract caption and size info.
1297 * @param[in] parent Parent node, owner of the children list passed as
1298 * the third argument.
1299 * @param[in] children The list of child nodes to which the node representing
1300 * the token can be added.
1301 * @param[out] width the extracted width specifier
1302 * @param[out] height the extracted height specifier
1304 static void defaultHandleTitleAndSize(const int cmd, DocNode *parent, QList<DocNode> &children, QCString &width,QCString &height)
1306 g_nodeStack.push(parent);
1309 doctokenizerYYsetStateTitle();
1311 while ((tok=doctokenizerYYlex()))
1313 if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height="))
1315 // special case: no title, but we do have a size indicator
1318 if (!defaultHandleToken(parent,tok,children))
1320 errorHandleDefaultToken(parent,tok,children,Mappers::cmdMapper->find(cmd).data());
1323 // parse size attributes
1326 tok=doctokenizerYYlex();
1328 while (tok==TK_WHITESPACE || tok==TK_WORD) // there are values following the title
1332 if (g_token->name=="width=" || g_token->name=="height=")
1334 doctokenizerYYsetStateTitleAttrValue();
1335 g_token->name = g_token->name.left(g_token->name.length()-1);
1338 if (g_token->name=="width")
1340 width = g_token->chars;
1342 else if (g_token->name=="height")
1344 height = g_token->chars;
1348 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unknown option '%s' after \\%s command, expected 'width' or 'height'",
1349 qPrint(g_token->name), Mappers::cmdMapper->find(cmd).data());
1354 tok=doctokenizerYYlex();
1356 doctokenizerYYsetStatePara();
1358 handlePendingStyleCommands(parent,children);
1359 DocNode *n=g_nodeStack.pop();
1363 /* Helper function that deals with the most common tokens allowed in
1364 * title like sections.
1365 * @param parent Parent node, owner of the children list passed as
1366 * the third argument.
1367 * @param tok The token to process.
1368 * @param children The list of child nodes to which the node representing
1369 * the token can be added.
1370 * @param handleWord Indicates if word token should be processed
1371 * @retval TRUE The token was handled.
1372 * @retval FALSE The token was not handled.
1374 static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool
1377 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
1378 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
1379 tok==TK_COMMAND_AT || tok==TK_COMMAND_BS || tok==TK_HTMLTAG
1382 DBG((" name=%s",qPrint(g_token->name)));
1386 QCString tokenName = g_token->name;
1392 switch (Mappers::cmdMapper->map(tokenName))
1395 children.append(new DocSymbol(parent,DocSymbol::Sym_BSlash));
1398 children.append(new DocSymbol(parent,DocSymbol::Sym_At));
1401 children.append(new DocSymbol(parent,DocSymbol::Sym_Less));
1404 children.append(new DocSymbol(parent,DocSymbol::Sym_Greater));
1407 children.append(new DocSymbol(parent,DocSymbol::Sym_Amp));
1410 children.append(new DocSymbol(parent,DocSymbol::Sym_Dollar));
1413 children.append(new DocSymbol(parent,DocSymbol::Sym_Hash));
1416 children.append(new DocSymbol(parent,DocSymbol::Sym_DoubleColon));
1419 children.append(new DocSymbol(parent,DocSymbol::Sym_Percent));
1422 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1423 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1426 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1427 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1428 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1431 children.append(new DocSymbol(parent,DocSymbol::Sym_Quot));
1434 children.append(new DocSymbol(parent,DocSymbol::Sym_Dot));
1437 children.append(new DocSymbol(parent,DocSymbol::Sym_Plus));
1440 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1443 children.append(new DocSymbol(parent,DocSymbol::Sym_Equal));
1447 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
1448 tok=handleStyleArgument(parent,children,tokenName);
1449 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
1450 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1451 if (tok==TK_NEWPARA) goto handlepara;
1452 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1454 DBG(("CMD_EMPHASIS: reparsing command %s\n",qPrint(g_token->name)));
1461 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
1462 tok=handleStyleArgument(parent,children,tokenName);
1463 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
1464 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1465 if (tok==TK_NEWPARA) goto handlepara;
1466 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1468 DBG(("CMD_BOLD: reparsing command %s\n",qPrint(g_token->name)));
1475 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE));
1476 tok=handleStyleArgument(parent,children,tokenName);
1477 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE));
1478 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1479 if (tok==TK_NEWPARA) goto handlepara;
1480 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1482 DBG(("CMD_CODE: reparsing command %s\n",qPrint(g_token->name)));
1489 doctokenizerYYsetStateHtmlOnly();
1490 tok = doctokenizerYYlex();
1491 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName,g_token->name=="block"));
1492 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"htmlonly section ended without end marker");
1493 doctokenizerYYsetStatePara();
1498 doctokenizerYYsetStateManOnly();
1499 tok = doctokenizerYYlex();
1500 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
1501 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"manonly section ended without end marker");
1502 doctokenizerYYsetStatePara();
1507 doctokenizerYYsetStateRtfOnly();
1508 tok = doctokenizerYYlex();
1509 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::RtfOnly,g_isExample,g_exampleName));
1510 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"rtfonly section ended without end marker");
1511 doctokenizerYYsetStatePara();
1516 doctokenizerYYsetStateLatexOnly();
1517 tok = doctokenizerYYlex();
1518 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
1519 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"latexonly section ended without end marker",doctokenizerYYlineno);
1520 doctokenizerYYsetStatePara();
1525 doctokenizerYYsetStateXmlOnly();
1526 tok = doctokenizerYYlex();
1527 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
1528 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"xmlonly section ended without end marker",doctokenizerYYlineno);
1529 doctokenizerYYsetStatePara();
1534 doctokenizerYYsetStateDbOnly();
1535 tok = doctokenizerYYlex();
1536 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::DocbookOnly,g_isExample,g_exampleName));
1537 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"docbookonly section ended without end marker",doctokenizerYYlineno);
1538 doctokenizerYYsetStatePara();
1543 DocFormula *form=new DocFormula(parent,g_token->id);
1544 children.append(form);
1549 DocAnchor *anchor = handleAnchor(parent);
1552 children.append(anchor);
1556 case CMD_INTERNALREF:
1558 DocInternalRef *ref = handleInternalRef(parent);
1561 children.append(ref);
1564 doctokenizerYYsetStatePara();
1570 doctokenizerYYsetStateSetScope();
1571 doctokenizerYYlex();
1572 scope = g_token->name;
1574 //printf("Found scope='%s'\n",scope.data());
1575 doctokenizerYYsetStatePara();
1579 ((DocPara *)parent) -> handleImage("image");
1587 switch (Mappers::htmlTagMapper->map(tokenName))
1590 warn_doc_error(g_fileName,doctokenizerYYlineno,"found <div> tag in heading\n");
1593 warn_doc_error(g_fileName,doctokenizerYYlineno,"found <pre> tag in heading\n");
1596 if (!g_token->endTag)
1598 handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs);
1602 handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
1606 if (!g_token->endTag)
1608 handleStyleEnter(parent,children,DocStyleChange::Strike,&g_token->attribs);
1612 handleStyleLeave(parent,children,DocStyleChange::Strike,tokenName);
1615 case HTML_UNDERLINE:
1616 if (!g_token->endTag)
1618 handleStyleEnter(parent,children,DocStyleChange::Underline,&g_token->attribs);
1622 handleStyleLeave(parent,children,DocStyleChange::Underline,tokenName);
1627 if (!g_token->endTag)
1629 handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs);
1633 handleStyleLeave(parent,children,DocStyleChange::Code,tokenName);
1637 if (!g_token->endTag)
1639 handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs);
1643 handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName);
1647 if (!g_token->endTag)
1649 handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs);
1653 handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName);
1657 if (!g_token->endTag)
1659 handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs);
1663 handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName);
1667 if (!g_token->endTag)
1669 handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs);
1673 handleStyleLeave(parent,children,DocStyleChange::Center,tokenName);
1677 if (!g_token->endTag)
1679 handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs);
1683 handleStyleLeave(parent,children,DocStyleChange::Small,tokenName);
1687 if (!g_token->endTag)
1688 handleImg(parent,children,g_token->attribs);
1698 DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName);
1699 if (s!=DocSymbol::Sym_Unknown)
1701 children.append(new DocSymbol(parent,s));
1712 if (insidePRE(parent) || !children.isEmpty())
1714 children.append(new DocWhiteSpace(parent,g_token->chars));
1720 handleLinkedWord(parent,children);
1728 children.append(new DocWord(parent,g_token->name));
1734 if (g_insideHtmlLink)
1736 children.append(new DocWord(parent,g_token->name));
1740 children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr));
1749 //---------------------------------------------------------------------------
1751 static void handleImg(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
1753 HtmlAttribListIterator li(tagHtmlAttribs);
1757 for (li.toFirst();(opt=li.current());++li,++index)
1759 //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
1760 if (opt->name=="src" && !opt->value.isEmpty())
1763 HtmlAttribList attrList = tagHtmlAttribs;
1764 // and remove the src attribute
1765 bool result = attrList.remove(index);
1767 DocImage::Type t = DocImage::Html;
1768 DocImage *img = new DocImage(parent,attrList,findAndCopyImage(opt->value,t,false),t,opt->value);
1769 children.append(img);
1775 warn_doc_error(g_fileName,doctokenizerYYlineno,"IMG tag does not have a SRC attribute!\n");
1779 //---------------------------------------------------------------------------
1781 DocSymbol::SymType DocSymbol::decodeSymbol(const QCString &symName)
1783 DBG(("decodeSymbol(%s)\n",qPrint(symName)));
1784 return HtmlEntityMapper::instance()->name2sym(symName);
1787 //---------------------------------------------------------------------------
1789 DocEmoji::DocEmoji(DocNode *parent,const QCString &symName) :
1790 m_symName(symName), m_index(-1)
1793 QCString locSymName = symName;
1794 int len=locSymName.length();
1797 if (locSymName.at(len-1)!=':') locSymName.append(":");
1798 if (locSymName.at(0)!=':') locSymName.prepend(":");
1800 m_symName = locSymName;
1801 m_index = EmojiEntityMapper::instance()->symbol2index(m_symName);
1804 warn_doc_error(g_fileName,doctokenizerYYlineno,"Found unsupported emoji symbol '%s'\n",qPrint(m_symName));
1808 //---------------------------------------------------------------------------
1810 static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
1811 const QCString &doc)
1813 int retval = RetVal_OK;
1815 if (doc.isEmpty()) return retval;
1817 doctokenizerYYinit(doc,g_fileName);
1819 // first parse any number of paragraphs
1822 if (!children.isEmpty() && children.getLast()->kind()==DocNode::Kind_Para)
1823 { // last child item was a paragraph
1824 lastPar = (DocPara*)children.getLast();
1829 DocPara *par = new DocPara(parent);
1830 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1831 retval=par->parse();
1832 if (!par->isEmpty())
1834 children.append(par);
1835 if (lastPar) lastPar->markLast(FALSE);
1842 } while (retval==TK_NEWPARA);
1843 if (lastPar) lastPar->markLast();
1845 //printf("internalValidateParsingDoc: %p: isFirst=%d isLast=%d\n",
1846 // lastPar,lastPar?lastPar->isFirst():-1,lastPar?lastPar->isLast():-1);
1851 //---------------------------------------------------------------------------
1853 static void readTextFileByName(const QCString &file,QCString &text)
1855 if (portable_isAbsolutePath(file.data()))
1860 text = fileToString(file,Config_getBool(FILTER_SOURCE_FILES));
1864 QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
1865 char *s=examplePathList.first();
1868 QCString absFileName = QCString(s)+portable_pathSeparator()+file;
1869 QFileInfo fi(absFileName);
1872 text = fileToString(absFileName,Config_getBool(FILTER_SOURCE_FILES));
1875 s=examplePathList.next();
1878 // as a fallback we also look in the exampleNameDict
1881 if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
1883 text = fileToString(fd->absFilePath(),Config_getBool(FILTER_SOURCE_FILES));
1887 warn_doc_error(g_fileName,doctokenizerYYlineno,"included file name %s is ambiguous"
1888 "Possible candidates:\n%s",qPrint(file),
1889 qPrint(showFileDefMatches(Doxygen::exampleNameDict,file))
1894 warn_doc_error(g_fileName,doctokenizerYYlineno,"included file %s is not found. "
1895 "Check your EXAMPLE_PATH",qPrint(file));
1899 //---------------------------------------------------------------------------
1901 DocWord::DocWord(DocNode *parent,const QCString &word) :
1905 //printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
1906 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1908 Doxygen::searchIndex->addWord(word,FALSE);
1912 //---------------------------------------------------------------------------
1914 DocLinkedWord::DocLinkedWord(DocNode *parent,const QCString &word,
1915 const QCString &ref,const QCString &file,
1916 const QCString &anchor,const QCString &tooltip) :
1917 m_word(word), m_ref(ref),
1918 m_file(file), m_relPath(g_relPath), m_anchor(anchor),
1922 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
1923 // word.data(),g_searchUrl.data(),tooltip.data());
1924 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1926 Doxygen::searchIndex->addWord(word,FALSE);
1930 //---------------------------------------------------------------------------
1932 DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
1937 warn_doc_error(g_fileName,doctokenizerYYlineno,"Empty anchor label");
1940 if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix)
1942 CiteInfo *cite = Doxygen::citeDict->find(id.mid(CiteConsts::anchorPrefix.length()));
1945 m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE);
1950 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid cite anchor id `%s'",qPrint(id));
1951 m_anchor = "invalid";
1955 else if (newAnchor) // found <a name="label">
1959 else // found \anchor label
1961 SectionInfo *sec = Doxygen::sectionDict->find(id);
1964 //printf("Found anchor %s\n",id.data());
1965 m_file = sec->fileName;
1966 m_anchor = sec->label;
1967 if (g_sectionDict && g_sectionDict->find(id)==0)
1969 //printf("Inserting in dictionary!\n");
1970 g_sectionDict->append(id,sec);
1975 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid anchor id `%s'",qPrint(id));
1976 m_anchor = "invalid";
1982 //---------------------------------------------------------------------------
1984 DocVerbatim::DocVerbatim(DocNode *parent,const QCString &context,
1985 const QCString &text, Type t,bool isExample,
1986 const QCString &exampleFile,bool isBlock,const QCString &lang)
1987 : m_context(context), m_text(text), m_type(t),
1988 m_isExample(isExample), m_exampleFile(exampleFile),
1989 m_relPath(g_relPath), m_lang(lang), m_isBlock(isBlock)
1995 //---------------------------------------------------------------------------
1997 void DocInclude::parse()
1999 DBG(("DocInclude::parse(file=%s,text=%s)\n",qPrint(m_file),qPrint(m_text)));
2007 readTextFileByName(m_file,m_text);
2008 g_includeFileName = m_file;
2009 g_includeFileText = m_text;
2010 g_includeFileOffset = 0;
2011 g_includeFileLength = m_text.length();
2012 //printf("g_includeFile=<<%s>>\n",g_includeFileText.data());
2017 readTextFileByName(m_file,m_text);
2020 readTextFileByName(m_file,m_text);
2024 readTextFileByName(m_file,m_text);
2025 // check here for the existence of the blockId inside the file, so we
2026 // only generate the warning once.
2028 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
2030 warn_doc_error(g_fileName,doctokenizerYYlineno,"block marked with %s for \\snippet should appear twice in file %s, found it %d times\n",
2031 m_blockId.data(),m_file.data(),count);
2034 case DocInclude::SnippetDoc:
2035 case DocInclude::IncludeDoc:
2036 err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
2037 "Please create a bug report\n",__FILE__);
2042 //---------------------------------------------------------------------------
2044 void DocIncOperator::parse()
2046 m_includeFileName = g_includeFileName;
2047 const char *p = g_includeFileText;
2048 uint l = g_includeFileLength;
2049 uint o = g_includeFileOffset;
2050 DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",qPrint(p),o,l));
2052 bool nonEmpty = FALSE;
2061 if (nonEmpty) break; // we have a pattern to match
2062 so=o+1; // no pattern, skip empty line
2064 else if (!isspace((uchar)c)) // no white space char
2070 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2072 m_text = g_includeFileText.mid(so,o-so);
2073 DBG(("DocIncOperator::parse() Line: %s\n",qPrint(m_text)));
2075 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
2086 if (nonEmpty) break; // we have a pattern to match
2087 so=o+1; // no pattern, skip empty line
2089 else if (!isspace((uchar)c)) // no white space char
2095 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2097 m_text = g_includeFileText.mid(so,o-so);
2098 DBG(("DocIncOperator::parse() SkipLine: %s\n",qPrint(m_text)));
2101 o++; // skip new line
2103 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
2114 if (nonEmpty) break; // we have a pattern to match
2115 so=o+1; // no pattern, skip empty line
2117 else if (!isspace((uchar)c)) // no white space char
2123 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2127 o++; // skip new line
2129 g_includeFileOffset = so; // set pointer to start of new line
2141 if (nonEmpty) break; // we have a pattern to match
2142 so=o+1; // no pattern, skip empty line
2144 else if (!isspace((uchar)c)) // no white space char
2150 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2152 m_text = g_includeFileText.mid(bo,o-bo);
2153 DBG(("DocIncOperator::parse() Until: %s\n",qPrint(m_text)));
2156 o++; // skip new line
2158 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
2163 //---------------------------------------------------------------------------
2165 void DocCopy::parse(QList<DocNode> &children)
2169 if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
2171 if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
2173 bool hasParamCommand = g_hasParamCommand;
2174 bool hasReturnCommand = g_hasReturnCommand;
2175 QDict<void> paramsFound = g_paramsFound;
2176 //printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2177 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2179 docParserPushContext(FALSE);
2181 if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
2183 if (def->getOuterScope()!=Doxygen::globalScope)
2185 g_context=def->getOuterScope()->name();
2188 else if (def!=Doxygen::globalScope)
2190 g_context=def->name();
2192 g_styleStack.clear();
2193 g_nodeStack.clear();
2194 g_paramsFound.clear();
2195 g_copyStack.append(def);
2196 // make sure the descriptions end with a newline, so the parser will correctly
2197 // handle them in all cases.
2198 //printf("doc='%s'\n",doc.data());
2199 //printf("brief='%s'\n",brief.data());
2203 internalValidatingParseDoc(m_parent,children,brief);
2205 //printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2206 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2207 hasParamCommand = hasParamCommand || g_hasParamCommand;
2208 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
2209 QDictIterator<void> it(g_paramsFound);
2211 for (;(item=it.current());++it)
2213 paramsFound.insert(it.currentKey(),it.current());
2219 internalValidatingParseDoc(m_parent,children,doc);
2221 //printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2222 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2223 hasParamCommand = hasParamCommand || g_hasParamCommand;
2224 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
2225 QDictIterator<void> it(g_paramsFound);
2227 for (;(item=it.current());++it)
2229 paramsFound.insert(it.currentKey(),it.current());
2232 g_copyStack.remove(def);
2233 ASSERT(g_styleStack.isEmpty());
2234 ASSERT(g_nodeStack.isEmpty());
2235 docParserPopContext(TRUE);
2237 g_hasParamCommand = hasParamCommand;
2238 g_hasReturnCommand = hasReturnCommand;
2239 g_paramsFound = paramsFound;
2241 //printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2242 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2244 else // oops, recursion
2246 warn_doc_error(g_fileName,doctokenizerYYlineno,"recursive call chain of \\copydoc commands detected at %d\n",
2247 doctokenizerYYlineno);
2252 warn_doc_error(g_fileName,doctokenizerYYlineno,"target %s of \\copydoc command not found",
2257 //---------------------------------------------------------------------------
2259 DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) :
2260 m_id(id), m_key(key), m_relPath(g_relPath)
2265 bool DocXRefItem::parse()
2267 RefList *refList = Doxygen::xrefLists->find(m_key);
2270 // either not a built-in list or the list is enabled
2271 (m_key!="todo" || Config_getBool(GENERATE_TODOLIST)) &&
2272 (m_key!="test" || Config_getBool(GENERATE_TESTLIST)) &&
2273 (m_key!="bug" || Config_getBool(GENERATE_BUGLIST)) &&
2274 (m_key!="deprecated" || Config_getBool(GENERATE_DEPRECATEDLIST))
2278 RefItem *item = refList->getRefItem(m_id);
2282 if (g_memberDef && g_memberDef->name().at(0)=='@')
2284 m_file = "@"; // can't cross reference anonymous enum
2289 m_file = refList->fileName();
2290 m_anchor = item->listAnchor;
2292 m_title = refList->sectionTitle();
2293 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
2294 // m_file.data(),m_anchor.data(),m_title.data());
2296 if (!item->text.isEmpty())
2298 docParserPushContext();
2299 internalValidatingParseDoc(this,m_children,item->text);
2300 docParserPopContext();
2308 //---------------------------------------------------------------------------
2310 DocFormula::DocFormula(DocNode *parent,int id) :
2311 m_relPath(g_relPath)
2315 formCmd.sprintf("\\form#%d",id);
2316 Formula *formula=Doxygen::formulaNameDict->find(formCmd);
2319 m_id = formula->getId();
2320 m_name.sprintf("form_%d",m_id);
2321 m_text = formula->getFormulaText();
2323 else // wrong \form#<n> command
2325 warn_doc_error(g_fileName,doctokenizerYYlineno,"Wrong formula id %d",id);
2330 //---------------------------------------------------------------------------
2332 //int DocLanguage::parse()
2335 // DBG(("DocLanguage::parse() start\n"));
2336 // g_nodeStack.push(this);
2338 // // parse one or more paragraphs
2339 // bool isFirst=TRUE;
2343 // par = new DocPara(this);
2344 // if (isFirst) { par->markFirst(); isFirst=FALSE; }
2345 // m_children.append(par);
2346 // retval=par->parse();
2348 // while (retval==TK_NEWPARA);
2349 // if (par) par->markLast();
2351 // DBG(("DocLanguage::parse() end\n"));
2352 // DocNode *n = g_nodeStack.pop();
2357 //---------------------------------------------------------------------------
2359 void DocSecRefItem::parse()
2361 DBG(("DocSecRefItem::parse() start\n"));
2362 g_nodeStack.push(this);
2364 doctokenizerYYsetStateTitle();
2366 while ((tok=doctokenizerYYlex()))
2368 if (!defaultHandleToken(this,tok,m_children))
2370 errorHandleDefaultToken(this,tok,m_children,"\\refitem");
2373 doctokenizerYYsetStatePara();
2374 handlePendingStyleCommands(this,m_children);
2377 if (!m_target.isEmpty())
2379 sec=Doxygen::sectionDict->find(m_target);
2382 m_file = sec->fileName;
2383 m_anchor = sec->label;
2384 if (g_sectionDict && g_sectionDict->find(m_target)==0)
2386 g_sectionDict->append(m_target,sec);
2391 warn_doc_error(g_fileName,doctokenizerYYlineno,"reference to unknown section %s",
2397 warn_doc_error(g_fileName,doctokenizerYYlineno,"reference to empty target");
2400 DBG(("DocSecRefItem::parse() end\n"));
2401 DocNode *n = g_nodeStack.pop();
2405 //---------------------------------------------------------------------------
2407 void DocSecRefList::parse()
2409 DBG(("DocSecRefList::parse() start\n"));
2410 g_nodeStack.push(this);
2412 int tok=doctokenizerYYlex();
2414 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
2418 if (tok==TK_COMMAND_AT || tok == TK_COMMAND_BS)
2420 switch (Mappers::cmdMapper->map(g_token->name))
2422 case CMD_SECREFITEM:
2424 int tok=doctokenizerYYlex();
2425 if (tok!=TK_WHITESPACE)
2427 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\refitem command");
2430 tok=doctokenizerYYlex();
2431 if (tok!=TK_WORD && tok!=TK_LNKWORD)
2433 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of \\refitem",
2438 DocSecRefItem *item = new DocSecRefItem(this,g_token->name);
2439 m_children.append(item);
2443 case CMD_ENDSECREFLIST:
2446 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\secreflist",
2447 qPrint(g_token->name));
2451 else if (tok==TK_WHITESPACE)
2453 // ignore whitespace
2457 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s inside section reference list",
2461 tok=doctokenizerYYlex();
2465 DBG(("DocSecRefList::parse() end\n"));
2466 DocNode *n = g_nodeStack.pop();
2470 //---------------------------------------------------------------------------
2472 DocInternalRef::DocInternalRef(DocNode *parent,const QCString &ref)
2473 : m_relPath(g_relPath)
2476 int i=ref.find('#');
2479 m_anchor = ref.right(ref.length()-i-1);
2480 m_file = ref.left(i);
2488 void DocInternalRef::parse()
2490 g_nodeStack.push(this);
2491 DBG(("DocInternalRef::parse() start\n"));
2494 while ((tok=doctokenizerYYlex()))
2496 if (!defaultHandleToken(this,tok,m_children))
2498 errorHandleDefaultToken(this,tok,m_children,"\\ref");
2502 handlePendingStyleCommands(this,m_children);
2503 DBG(("DocInternalRef::parse() end\n"));
2504 DocNode *n=g_nodeStack.pop();
2508 //---------------------------------------------------------------------------
2510 DocRef::DocRef(DocNode *parent,const QCString &target,const QCString &context) :
2511 m_refType(Unknown), m_isSubPage(FALSE)
2514 Definition *compound = 0;
2516 //printf("DocRef::DocRef(target=%s,context=%s)\n",target.data(),context.data());
2517 ASSERT(!target.isEmpty());
2518 SrcLangExt lang = getLanguageFromFileName(target);
2519 m_relPath = g_relPath;
2520 SectionInfo *sec = Doxygen::sectionDict->find(target);
2521 if (sec==0 && lang==SrcLangExt_Markdown) // lookup as markdown file
2523 sec = Doxygen::sectionDict->find(markdownFileNameToId(target));
2525 if (sec) // ref to section or anchor
2528 if (sec->type==SectionInfo::Page)
2530 pd = Doxygen::pageSDict->find(target);
2532 m_text = sec->title;
2533 if (m_text.isEmpty()) m_text = sec->label;
2536 m_file = stripKnownExtensions(sec->fileName);
2537 if (sec->type==SectionInfo::Anchor)
2541 else if (sec->type==SectionInfo::Table)
2547 m_refType = Section;
2549 m_isSubPage = pd && pd->hasParentPage();
2550 if (sec->type!=SectionInfo::Page || m_isSubPage) m_anchor = sec->label;
2551 //printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d type=%d\n",
2552 // m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor,sec->type);
2555 else if (resolveLink(context,target,TRUE,&compound,anchor))
2557 bool isFile = compound ?
2558 (compound->definitionType()==Definition::TypeFile ||
2559 compound->definitionType()==Definition::TypePage ? TRUE : FALSE) :
2561 m_text = linkToText(compound?compound->getLanguage():SrcLangExt_Unknown,target,isFile);
2563 if (compound && compound->isLinkable()) // ref to compound
2565 if (anchor.isEmpty() && /* compound link */
2566 compound->definitionType()==Definition::TypeGroup && /* is group */
2567 ((GroupDef *)compound)->groupTitle() /* with title */
2570 m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link
2572 else if (compound->definitionType()==Definition::TypeMember &&
2573 ((MemberDef*)compound)->isObjCMethod())
2575 // Objective C Method
2576 MemberDef *member = (MemberDef*)compound;
2577 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
2578 m_text = member->objCMethodName(localLink,g_inSeeBlock);
2581 m_file = compound->getOutputFileBase();
2582 m_ref = compound->getReference();
2583 //printf("isFile=%d compound=%s (%d)\n",isFile,compound->name().data(),
2584 // compound->definitionType());
2587 else if (compound && compound->definitionType()==Definition::TypeFile &&
2588 ((FileDef*)compound)->generateSourceFile()
2589 ) // undocumented file that has source code we can link to
2591 m_file = compound->getSourceFileBase();
2592 m_ref = compound->getReference();
2597 warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to `%s' for \\ref command",
2601 static void flattenParagraphs(DocNode *root,QList<DocNode> &children)
2603 QListIterator<DocNode> li(children);
2604 QList<DocNode> newChildren;
2606 for (li.toFirst();(dn=li.current());++li)
2608 if (dn->kind()==DocNode::Kind_Para)
2610 DocPara *para = (DocPara*)dn;
2611 QList<DocNode> ¶Children = para->children();
2612 paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node
2613 QListIterator<DocNode> li2(paraChildren);
2615 for (li2.toFirst();(dn2=li2.current());++li2)
2617 newChildren.append(dn2); // add them to new node
2622 QListIterator<DocNode> li3(newChildren);
2623 for (li3.toFirst();(dn=li3.current());++li3)
2625 children.append(dn);
2626 dn->setParent(root);
2630 void DocRef::parse()
2632 g_nodeStack.push(this);
2633 DBG(("DocRef::parse() start\n"));
2636 while ((tok=doctokenizerYYlex()))
2638 if (!defaultHandleToken(this,tok,m_children))
2645 errorHandleDefaultToken(this,tok,m_children,"\\ref");
2651 if (m_children.isEmpty() && !m_text.isEmpty())
2653 g_insideHtmlLink=TRUE;
2654 docParserPushContext();
2655 internalValidatingParseDoc(this,m_children,m_text);
2656 docParserPopContext();
2657 g_insideHtmlLink=FALSE;
2658 flattenParagraphs(this,m_children);
2661 handlePendingStyleCommands(this,m_children);
2663 DocNode *n=g_nodeStack.pop();
2667 //---------------------------------------------------------------------------
2669 DocCite::DocCite(DocNode *parent,const QCString &target,const QCString &) //context)
2671 static uint numBibFiles = Config_getList(CITE_BIB_FILES).count();
2673 //printf("DocCite::DocCite(target=%s)\n",target.data());
2674 ASSERT(!target.isEmpty());
2675 m_relPath = g_relPath;
2676 CiteInfo *cite = Doxygen::citeDict->find(target);
2677 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?cite->text.data():"<null>",numBibFiles);
2678 if (numBibFiles>0 && cite && !cite->text.isEmpty()) // ref to citation
2680 m_text = cite->text;
2682 m_anchor = CiteConsts::anchorPrefix+cite->label;
2683 m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE);
2684 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
2685 // m_text.data(),m_ref.data(),m_file.data(),m_anchor.data());
2691 warn_doc_error(g_fileName,doctokenizerYYlineno,"\\cite command found but no bib files specified via CITE_BIB_FILES!");
2695 warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to `%s' for \\cite command",
2700 warn_doc_error(g_fileName,doctokenizerYYlineno,"\\cite command to '%s' does not have an associated number",
2705 //---------------------------------------------------------------------------
2707 DocLink::DocLink(DocNode *parent,const QCString &target)
2710 Definition *compound = 0;
2713 m_relPath = g_relPath;
2714 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
2716 m_refText = m_refText.right(m_refText.length()-1);
2718 if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock,
2722 if (compound && compound->isLinkable())
2724 m_file = compound->getOutputFileBase();
2725 m_ref = compound->getReference();
2727 else if (compound && compound->definitionType()==Definition::TypeFile &&
2728 ((FileDef*)compound)->generateSourceFile()
2729 ) // undocumented file that has source code we can link to
2731 m_file = compound->getSourceFileBase();
2732 m_ref = compound->getReference();
2737 // bogus link target
2738 warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve link to `%s' for \\link command",
2743 QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
2746 g_nodeStack.push(this);
2747 DBG(("DocLink::parse() start\n"));
2750 while ((tok=doctokenizerYYlex()))
2752 if (!defaultHandleToken(this,tok,m_children,FALSE))
2759 switch (Mappers::cmdMapper->map(g_token->name))
2764 warn_doc_error(g_fileName,doctokenizerYYlineno,"{@link.. ended with @endlink command");
2768 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\link",
2769 qPrint(g_token->name));
2774 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found as part of a \\link",
2775 qPrint(g_token->name));
2778 if (g_token->name!="see" || !isXmlLink)
2780 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected xml/html command %s found as part of a \\link",
2781 qPrint(g_token->name));
2786 if (isJavaLink) // special case to detect closing }
2788 QCString w = g_token->name;
2794 else if ((p=w.find('}'))!=-1)
2797 m_children.append(new DocWord(this,w.left(p)));
2798 if ((uint)p<l-1) // something left after the } (for instance a .)
2800 result=w.right(l-p-1);
2805 m_children.append(new DocWord(this,g_token->name));
2808 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
2816 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
2821 if (m_children.isEmpty()) // no link text
2823 m_children.append(new DocWord(this,m_refText));
2826 handlePendingStyleCommands(this,m_children);
2827 DBG(("DocLink::parse() end\n"));
2828 DocNode *n=g_nodeStack.pop();
2834 //---------------------------------------------------------------------------
2836 DocDotFile::DocDotFile(DocNode *parent,const QCString &name,const QCString &context) :
2837 m_name(name), m_relPath(g_relPath), m_context(context)
2842 void DocDotFile::parse()
2844 defaultHandleTitleAndSize(CMD_DOTFILE,this,m_children,m_width,m_height);
2847 FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig);
2848 if (fd==0 && m_name.right(4)!=".dot") // try with .dot extension as well
2850 fd = findFileDef(Doxygen::dotFileNameDict,m_name+".dot",ambig);
2854 m_file = fd->absFilePath();
2858 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dot file name %s is ambiguous.\n"
2859 "Possible candidates:\n%s",qPrint(m_name),
2860 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2865 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dot file %s is not found "
2866 "in any of the paths specified via DOTFILE_DIRS!",qPrint(m_name));
2870 DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &context) :
2871 m_name(name), m_relPath(g_relPath), m_context(context)
2876 void DocMscFile::parse()
2878 defaultHandleTitleAndSize(CMD_MSCFILE,this,m_children,m_width,m_height);
2881 FileDef *fd = findFileDef(Doxygen::mscFileNameDict,m_name,ambig);
2882 if (fd==0 && m_name.right(4)!=".msc") // try with .msc extension as well
2884 fd = findFileDef(Doxygen::mscFileNameDict,m_name+".msc",ambig);
2888 m_file = fd->absFilePath();
2892 warn_doc_error(g_fileName,doctokenizerYYlineno,"included msc file name %s is ambiguous.\n"
2893 "Possible candidates:\n%s",qPrint(m_name),
2894 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2899 warn_doc_error(g_fileName,doctokenizerYYlineno,"included msc file %s is not found "
2900 "in any of the paths specified via MSCFILE_DIRS!",qPrint(m_name));
2904 //---------------------------------------------------------------------------
2906 DocDiaFile::DocDiaFile(DocNode *parent,const QCString &name,const QCString &context) :
2907 m_name(name), m_relPath(g_relPath), m_context(context)
2912 void DocDiaFile::parse()
2914 defaultHandleTitleAndSize(CMD_DIAFILE,this,m_children,m_width,m_height);
2917 FileDef *fd = findFileDef(Doxygen::diaFileNameDict,m_name,ambig);
2918 if (fd==0 && m_name.right(4)!=".dia") // try with .dia extension as well
2920 fd = findFileDef(Doxygen::diaFileNameDict,m_name+".dia",ambig);
2924 m_file = fd->absFilePath();
2928 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dia file name %s is ambiguous.\n"
2929 "Possible candidates:\n%s",qPrint(m_name),
2930 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2935 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dia file %s is not found "
2936 "in any of the paths specified via DIAFILE_DIRS!",qPrint(m_name));
2940 //---------------------------------------------------------------------------
2942 DocVhdlFlow::DocVhdlFlow(DocNode *parent)
2947 void DocVhdlFlow::parse()
2949 g_nodeStack.push(this);
2950 DBG(("DocVhdlFlow::parse() start\n"));
2952 doctokenizerYYsetStateTitle();
2954 while ((tok=doctokenizerYYlex()))
2956 if (!defaultHandleToken(this,tok,m_children))
2958 errorHandleDefaultToken(this,tok,m_children,"\\vhdlflow");
2961 tok=doctokenizerYYlex();
2963 doctokenizerYYsetStatePara();
2964 handlePendingStyleCommands(this,m_children);
2966 DBG(("DocVhdlFlow::parse() end\n"));
2967 DocNode *n=g_nodeStack.pop();
2969 VhdlDocGen::createFlowChart(g_memberDef);
2973 //---------------------------------------------------------------------------
2975 DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QCString &name,
2976 Type t,const QCString &url, bool inlineImage) :
2977 m_attribs(attribs), m_name(name),
2978 m_type(t), m_relPath(g_relPath),
2979 m_url(url), m_inlineImage(inlineImage)
2984 void DocImage::parse()
2986 defaultHandleTitleAndSize(CMD_IMAGE,this,m_children,m_width,m_height);
2990 //---------------------------------------------------------------------------
2992 int DocHtmlHeader::parse()
2994 int retval=RetVal_OK;
2995 g_nodeStack.push(this);
2996 DBG(("DocHtmlHeader::parse() start\n"));
2999 while ((tok=doctokenizerYYlex()))
3001 if (!defaultHandleToken(this,tok,m_children))
3007 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3008 if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
3012 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h1>",
3017 else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag
3021 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h2>",
3026 else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag
3030 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h3>",
3035 else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag
3039 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h4>",
3044 else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag
3048 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h5>",
3053 else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag
3057 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h6>",
3062 else if (tagId==HTML_A)
3064 if (!g_token->endTag)
3066 handleAHref(this,m_children,g_token->attribs);
3069 else if (tagId==HTML_BR)
3071 DocLineBreak *lb = new DocLineBreak(this);
3072 m_children.append(lb);
3076 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <h%d> context",
3077 g_token->endTag?"/":"",qPrint(g_token->name),m_level);
3083 sprintf(tmp,"<h%d>tag",m_level);
3084 errorHandleDefaultToken(this,tok,m_children,tmp);
3090 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3091 " <h%d> tag\n",m_level);
3094 handlePendingStyleCommands(this,m_children);
3095 DBG(("DocHtmlHeader::parse() end\n"));
3096 DocNode *n=g_nodeStack.pop();
3101 //---------------------------------------------------------------------------
3103 int DocHRef::parse()
3105 int retval=RetVal_OK;
3106 g_nodeStack.push(this);
3107 DBG(("DocHRef::parse() start\n"));
3110 while ((tok=doctokenizerYYlex()))
3112 if (!defaultHandleToken(this,tok,m_children))
3118 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3119 if (tagId==HTML_A && g_token->endTag) // found </a> tag
3125 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <a href=...> context",
3126 g_token->endTag?"/":"",qPrint(g_token->name),doctokenizerYYlineno);
3131 errorHandleDefaultToken(this,tok,m_children,"<a>..</a> block");
3138 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3139 " <a href=...> tag",doctokenizerYYlineno);
3142 handlePendingStyleCommands(this,m_children);
3143 DBG(("DocHRef::parse() end\n"));
3144 DocNode *n=g_nodeStack.pop();
3149 //---------------------------------------------------------------------------
3151 int DocInternal::parse(int level)
3153 int retval=RetVal_OK;
3154 g_nodeStack.push(this);
3155 DBG(("DocInternal::parse() start\n"));
3157 // first parse any number of paragraphs
3162 DocPara *par = new DocPara(this);
3163 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3164 retval=par->parse();
3165 if (!par->isEmpty())
3167 m_children.append(par);
3174 if (retval==TK_LISTITEM)
3176 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found",doctokenizerYYlineno);
3178 } while (retval!=0 &&
3179 retval!=RetVal_Section &&
3180 retval!=RetVal_Subsection &&
3181 retval!=RetVal_Subsubsection &&
3182 retval!=RetVal_Paragraph &&
3183 retval!=RetVal_EndInternal
3185 if (lastPar) lastPar->markLast();
3187 // then parse any number of level-n sections
3188 while ((level==1 && retval==RetVal_Section) ||
3189 (level==2 && retval==RetVal_Subsection) ||
3190 (level==3 && retval==RetVal_Subsubsection) ||
3191 (level==4 && retval==RetVal_Paragraph)
3194 DocSection *s=new DocSection(this,
3195 QMIN(level+Doxygen::subpageNestingLevel,5),g_token->sectionId);
3196 m_children.append(s);
3197 retval = s->parse();
3200 if (retval==RetVal_Internal)
3202 warn_doc_error(g_fileName,doctokenizerYYlineno,"\\internal command found inside internal section");
3205 DBG(("DocInternal::parse() end: retval=%x\n",retval));
3206 DocNode *n=g_nodeStack.pop();
3211 //---------------------------------------------------------------------------
3213 int DocIndexEntry::parse()
3215 int retval=RetVal_OK;
3216 g_nodeStack.push(this);
3217 DBG(("DocIndexEntry::parse() start\n"));
3218 int tok=doctokenizerYYlex();
3219 if (tok!=TK_WHITESPACE)
3221 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\addindex command");
3224 doctokenizerYYsetStateTitle();
3226 while ((tok=doctokenizerYYlex()))
3235 m_entry+=g_token->name;
3239 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name);
3242 case DocSymbol::Sym_BSlash: m_entry+='\\'; break;
3243 case DocSymbol::Sym_At: m_entry+='@'; break;
3244 case DocSymbol::Sym_Less: m_entry+='<'; break;
3245 case DocSymbol::Sym_Greater: m_entry+='>'; break;
3246 case DocSymbol::Sym_Amp: m_entry+='&'; break;
3247 case DocSymbol::Sym_Dollar: m_entry+='$'; break;
3248 case DocSymbol::Sym_Hash: m_entry+='#'; break;
3249 case DocSymbol::Sym_Percent: m_entry+='%'; break;
3250 case DocSymbol::Sym_apos: m_entry+='\''; break;
3251 case DocSymbol::Sym_Quot: m_entry+='"'; break;
3252 case DocSymbol::Sym_lsquo: m_entry+='`'; break;
3253 case DocSymbol::Sym_rsquo: m_entry+='\''; break;
3254 case DocSymbol::Sym_ldquo: m_entry+="``"; break;
3255 case DocSymbol::Sym_rdquo: m_entry+="''"; break;
3256 case DocSymbol::Sym_ndash: m_entry+="--"; break;
3257 case DocSymbol::Sym_mdash: m_entry+="---"; break;
3259 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected symbol found as argument of \\addindex");
3267 switch (Mappers::cmdMapper->map(g_token->name))
3269 case CMD_BSLASH: m_entry+='\\'; break;
3270 case CMD_AT: m_entry+='@'; break;
3271 case CMD_LESS: m_entry+='<'; break;
3272 case CMD_GREATER: m_entry+='>'; break;
3273 case CMD_AMP: m_entry+='&'; break;
3274 case CMD_DOLLAR: m_entry+='$'; break;
3275 case CMD_HASH: m_entry+='#'; break;
3276 case CMD_DCOLON: m_entry+="::"; break;
3277 case CMD_PERCENT: m_entry+='%'; break;
3278 case CMD_NDASH: m_entry+="--"; break;
3279 case CMD_MDASH: m_entry+="---"; break;
3280 case CMD_QUOTE: m_entry+='"'; break;
3281 case CMD_PUNT: m_entry+='.'; break;
3282 case CMD_PLUS: m_entry+='+'; break;
3283 case CMD_MINUS: m_entry+='-'; break;
3284 case CMD_EQUAL: m_entry+='='; break;
3286 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command %s found as argument of \\addindex",
3287 qPrint(g_token->name));
3292 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
3297 doctokenizerYYsetStatePara();
3298 m_entry = m_entry.stripWhiteSpace();
3300 DBG(("DocIndexEntry::parse() end retval=%x\n",retval));
3301 DocNode *n=g_nodeStack.pop();
3306 //---------------------------------------------------------------------------
3308 DocHtmlCaption::DocHtmlCaption(DocNode *parent,const HtmlAttribList &attribs)
3310 m_hasCaptionId = FALSE;
3311 HtmlAttribListIterator li(attribs);
3313 for (li.toFirst();(opt=li.current());++li)
3315 if (opt->name=="id") // interpret id attribute as an anchor
3317 SectionInfo *sec = Doxygen::sectionDict->find(opt->value);
3320 //printf("Found anchor %s\n",id.data());
3321 m_file = sec->fileName;
3322 m_anchor = sec->label;
3323 m_hasCaptionId = TRUE;
3324 if (g_sectionDict && g_sectionDict->find(opt->value)==0)
3326 //printf("Inserting in dictionary!\n");
3327 g_sectionDict->append(opt->value,sec);
3332 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid caption id `%s'",qPrint(opt->value));
3335 else // copy attribute
3337 m_attribs.append(new HtmlAttrib(*opt));
3343 int DocHtmlCaption::parse()
3346 g_nodeStack.push(this);
3347 DBG(("DocHtmlCaption::parse() start\n"));
3349 while ((tok=doctokenizerYYlex()))
3351 if (!defaultHandleToken(this,tok,m_children))
3357 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3358 if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
3365 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <caption> context",
3366 g_token->endTag?"/":"",qPrint(g_token->name));
3371 errorHandleDefaultToken(this,tok,m_children,"<caption> tag");
3378 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3379 " <caption> tag",doctokenizerYYlineno);
3382 handlePendingStyleCommands(this,m_children);
3383 DBG(("DocHtmlCaption::parse() end\n"));
3384 DocNode *n=g_nodeStack.pop();
3389 //---------------------------------------------------------------------------
3391 int DocHtmlCell::parse()
3393 int retval=RetVal_OK;
3394 g_nodeStack.push(this);
3395 DBG(("DocHtmlCell::parse() start\n"));
3397 // parse one or more paragraphs
3402 par = new DocPara(this);
3403 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3404 m_children.append(par);
3405 retval=par->parse();
3406 if (retval==TK_HTMLTAG)
3408 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3409 if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
3411 retval=TK_NEWPARA; // ignore the tag
3413 else if (tagId==HTML_TH && g_token->endTag) // found </th> tag
3415 retval=TK_NEWPARA; // ignore the tag
3419 while (retval==TK_NEWPARA);
3420 if (par) par->markLast();
3422 DBG(("DocHtmlCell::parse() end\n"));
3423 DocNode *n=g_nodeStack.pop();
3428 int DocHtmlCell::parseXml()
3430 int retval=RetVal_OK;
3431 g_nodeStack.push(this);
3432 DBG(("DocHtmlCell::parseXml() start\n"));
3434 // parse one or more paragraphs
3439 par = new DocPara(this);
3440 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3441 m_children.append(par);
3442 retval=par->parse();
3443 if (retval==TK_HTMLTAG)
3445 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3446 if (tagId==XML_ITEM && g_token->endTag) // found </item> tag
3448 retval=TK_NEWPARA; // ignore the tag
3450 else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag
3452 retval=TK_NEWPARA; // ignore the tag
3456 while (retval==TK_NEWPARA);
3457 if (par) par->markLast();
3459 DBG(("DocHtmlCell::parseXml() end\n"));
3460 DocNode *n=g_nodeStack.pop();
3465 int DocHtmlCell::rowSpan() const
3468 HtmlAttribList attrs = attribs();
3470 for (i=0; i<attrs.count(); ++i)
3472 if (attrs.at(i)->name.lower()=="rowspan")
3474 retval = attrs.at(i)->value.toInt();
3481 int DocHtmlCell::colSpan() const
3484 HtmlAttribList attrs = attribs();
3486 for (i=0; i<attrs.count(); ++i)
3488 if (attrs.at(i)->name.lower()=="colspan")
3490 retval = QMAX(1,attrs.at(i)->value.toInt());
3497 DocHtmlCell::Alignment DocHtmlCell::alignment() const
3499 HtmlAttribList attrs = attribs();
3501 for (i=0; i<attrs.count(); ++i)
3503 if (attrs.at(i)->name.lower()=="align")
3505 if (attrs.at(i)->value.lower()=="center")
3507 else if (attrs.at(i)->value.lower()=="right")
3511 else if (attrs.at(i)->name.lower()=="class")
3513 if (attrs.at(i)->value.lower()=="markdowntableheadcenter")
3515 else if (attrs.at(i)->value.lower()=="markdowntableheadright")
3517 else if (attrs.at(i)->value.lower()=="markdowntableheadleft")
3519 else if (attrs.at(i)->value.lower()=="markdowntableheadnone")
3521 else if (attrs.at(i)->value.lower()=="markdowntablebodycenter")
3523 else if (attrs.at(i)->value.lower()=="markdowntablebodyright")
3525 else if (attrs.at(i)->value.lower()=="markdowntablebodyleft")
3527 else if (attrs.at(i)->value.lower()=="markdowntablebodynone")
3536 //---------------------------------------------------------------------------
3538 int DocHtmlRow::parse()
3540 int retval=RetVal_OK;
3541 g_nodeStack.push(this);
3542 DBG(("DocHtmlRow::parse() start\n"));
3544 bool isHeading=FALSE;
3546 DocHtmlCell *cell=0;
3549 int tok=doctokenizerYYlex();
3551 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3552 // should find a html tag now
3553 if (tok==TK_HTMLTAG)
3555 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3556 if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
3559 else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag
3563 else // found some other tag
3565 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <td> or <th> tag but "
3566 "found <%s> instead!",qPrint(g_token->name));
3567 doctokenizerYYpushBackHtmlTag(g_token->name);
3571 else if (tok==0) // premature end of comment
3573 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
3574 " for a html description title");
3577 else // token other than html token
3579 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <td> or <th> tag but found %s token instead!",
3584 // parse one or more cells
3587 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3588 cell->markFirst(isFirst);
3590 m_children.append(cell);
3591 retval=cell->parse();
3592 isHeading = retval==RetVal_TableHCell;
3594 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3595 if (cell) cell->markLast(TRUE);
3598 DBG(("DocHtmlRow::parse() end\n"));
3599 DocNode *n=g_nodeStack.pop();
3604 int DocHtmlRow::parseXml(bool isHeading)
3606 int retval=RetVal_OK;
3607 g_nodeStack.push(this);
3608 DBG(("DocHtmlRow::parseXml() start\n"));
3611 DocHtmlCell *cell=0;
3614 int tok=doctokenizerYYlex();
3616 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3617 // should find a html tag now
3618 if (tok==TK_HTMLTAG)
3620 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3621 if (tagId==XML_TERM && !g_token->endTag) // found <term> tag
3624 else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag
3627 else // found some other tag
3629 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <term> or <description> tag but "
3630 "found <%s> instead!",qPrint(g_token->name));
3631 doctokenizerYYpushBackHtmlTag(g_token->name);
3635 else if (tok==0) // premature end of comment
3637 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
3638 " for a html description title");
3641 else // token other than html token
3643 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <td> or <th> tag but found %s token instead!",
3650 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3651 cell->markFirst(isFirst);
3653 m_children.append(cell);
3654 retval=cell->parseXml();
3656 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3657 if (cell) cell->markLast(TRUE);
3660 DBG(("DocHtmlRow::parseXml() end\n"));
3661 DocNode *n=g_nodeStack.pop();
3666 //---------------------------------------------------------------------------
3668 int DocHtmlTable::parse()
3670 int retval=RetVal_OK;
3671 g_nodeStack.push(this);
3672 DBG(("DocHtmlTable::parse() start\n"));
3676 int tok=doctokenizerYYlex();
3678 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3679 // should find a html tag now
3680 if (tok==TK_HTMLTAG)
3682 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3683 if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
3685 // no caption, just rows
3686 retval=RetVal_TableRow;
3688 else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag
3692 warn_doc_error(g_fileName,doctokenizerYYlineno,"table already has a caption, found another one");
3696 m_caption = new DocHtmlCaption(this,g_token->attribs);
3697 retval=m_caption->parse();
3699 if (retval==RetVal_OK) // caption was parsed ok
3705 else // found wrong token
3707 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <tr> or <caption> tag but "
3708 "found <%s%s> instead!", g_token->endTag ? "/" : "", qPrint(g_token->name));
3711 else if (tok==0) // premature end of comment
3713 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
3714 " for a <tr> or <caption> tag");
3716 else // token other than html token
3718 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <tr> tag but found %s token instead!",
3722 // parse one or more rows
3723 while (retval==RetVal_TableRow)
3725 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3726 m_children.append(tr);
3732 DBG(("DocHtmlTable::parse() end\n"));
3733 DocNode *n=g_nodeStack.pop();
3735 return retval==RetVal_EndTable ? RetVal_OK : retval;
3738 int DocHtmlTable::parseXml()
3740 int retval=RetVal_OK;
3741 g_nodeStack.push(this);
3742 DBG(("DocHtmlTable::parseXml() start\n"));
3745 int tok=doctokenizerYYlex();
3747 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3748 // should find a html tag now
3750 bool isHeader=FALSE;
3751 if (tok==TK_HTMLTAG)
3753 tagId=Mappers::htmlTagMapper->map(g_token->name);
3754 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
3756 retval=RetVal_TableRow;
3758 if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag
3760 retval=RetVal_TableRow;
3765 // parse one or more rows
3766 while (retval==RetVal_TableRow)
3768 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3769 m_children.append(tr);
3770 retval=tr->parseXml(isHeader);
3776 DBG(("DocHtmlTable::parseXml() end\n"));
3777 DocNode *n=g_nodeStack.pop();
3779 tagId=Mappers::htmlTagMapper->map(g_token->name);
3780 return tagId==XML_LIST && g_token->endTag ? RetVal_OK : retval;
3783 /** Helper class to compute the grid for an HTML style table */
3784 struct ActiveRowSpan
3786 ActiveRowSpan(int rows,int col) : rowsLeft(rows), column(col) {}
3791 /** List of ActiveRowSpan classes. */
3792 typedef QList<ActiveRowSpan> RowSpanList;
3794 /** determines the location of all cells in a grid, resolving row and
3795 column spans. For each the total number of visible cells is computed,
3796 and the total number of visible columns over all rows is stored.
3798 void DocHtmlTable::computeTableGrid()
3800 //printf("computeTableGrid()\n");
3801 RowSpanList rowSpans;
3802 rowSpans.setAutoDelete(TRUE);
3805 QListIterator<DocNode> li(children());
3807 for (li.toFirst();(rowNode=li.current());++li)
3811 if (rowNode->kind()==DocNode::Kind_HtmlRow)
3814 DocHtmlRow *row = (DocHtmlRow*)rowNode;
3815 QListIterator<DocNode> rli(row->children());
3817 for (rli.toFirst();(cellNode=rli.current());++rli)
3819 if (cellNode->kind()==DocNode::Kind_HtmlCell)
3821 DocHtmlCell *cell = (DocHtmlCell*)cellNode;
3822 int rs = cell->rowSpan();
3823 int cs = cell->colSpan();
3825 for (i=0;i<rowSpans.count();i++)
3827 if (rowSpans.at(i)->rowsLeft>0 &&
3828 rowSpans.at(i)->column==colIdx)
3830 colIdx=rowSpans.at(i)->column+1;
3834 if (rs>0) rowSpans.append(new ActiveRowSpan(rs,colIdx));
3835 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
3836 cell->setRowIndex(rowIdx);
3837 cell->setColumnIndex(colIdx);
3842 for (i=0;i<rowSpans.count();i++)
3844 if (rowSpans.at(i)->rowsLeft>0) rowSpans.at(i)->rowsLeft--;
3846 row->setVisibleCells(cells);
3847 row->setRowIndex(rowIdx);
3850 if (colIdx-1>maxCols) maxCols=colIdx-1;
3852 m_numCols = maxCols;
3855 void DocHtmlTable::accept(DocVisitor *v)
3858 // for HTML output we put the caption first
3859 //if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v);
3860 // doxygen 1.8.11: always put the caption first
3861 if (m_caption) m_caption->accept(v);
3862 QListIterator<DocNode> cli(m_children);
3864 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
3865 // for other output formats we put the caption last
3866 //if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v);
3870 //---------------------------------------------------------------------------
3872 int DocHtmlDescTitle::parse()
3875 g_nodeStack.push(this);
3876 DBG(("DocHtmlDescTitle::parse() start\n"));
3879 while ((tok=doctokenizerYYlex()))
3881 if (!defaultHandleToken(this,tok,m_children))
3889 QCString cmdName=g_token->name;
3890 bool isJavaLink=FALSE;
3891 switch (Mappers::cmdMapper->map(cmdName))
3895 int tok=doctokenizerYYlex();
3896 if (tok!=TK_WHITESPACE)
3898 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
3899 qPrint(g_token->name));
3903 doctokenizerYYsetStateRef();
3904 tok=doctokenizerYYlex(); // get the reference id
3907 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of \\%s command",
3908 tokToString(tok),qPrint(cmdName));
3912 DocRef *ref = new DocRef(this,g_token->name,g_context);
3913 m_children.append(ref);
3916 doctokenizerYYsetStatePara();
3925 int tok=doctokenizerYYlex();
3926 if (tok!=TK_WHITESPACE)
3928 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\%s command",
3933 doctokenizerYYsetStateLink();
3934 tok=doctokenizerYYlex();
3937 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of \\%s command",
3938 tokToString(tok),qPrint(cmdName));
3942 doctokenizerYYsetStatePara();
3943 DocLink *lnk = new DocLink(this,g_token->name);
3944 m_children.append(lnk);
3945 QCString leftOver = lnk->parse(isJavaLink);
3946 if (!leftOver.isEmpty())
3948 m_children.append(new DocWord(this,leftOver));
3956 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command \\%s found as part of a <dt> tag",
3957 qPrint(g_token->name));
3962 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol \\%s found as part of a <dt> tag",
3963 qPrint(g_token->name));
3967 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3968 if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
3970 retval = RetVal_DescData;
3973 else if (tagId==HTML_DT && g_token->endTag)
3975 // ignore </dt> tag.
3977 else if (tagId==HTML_DT)
3979 // missing <dt> tag.
3980 retval = RetVal_DescTitle;
3983 else if (tagId==HTML_DL && g_token->endTag)
3985 retval=RetVal_EndDesc;
3988 else if (tagId==HTML_A)
3990 if (!g_token->endTag)
3992 handleAHref(this,m_children,g_token->attribs);
3997 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <dt> context",
3998 g_token->endTag?"/":"",qPrint(g_token->name));
4003 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s found as part of a <dt> tag",
4011 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
4015 handlePendingStyleCommands(this,m_children);
4016 DBG(("DocHtmlDescTitle::parse() end\n"));
4017 DocNode *n=g_nodeStack.pop();
4022 //---------------------------------------------------------------------------
4024 int DocHtmlDescData::parse()
4026 m_attribs = g_token->attribs;
4028 g_nodeStack.push(this);
4029 DBG(("DocHtmlDescData::parse() start\n"));
4035 par = new DocPara(this);
4036 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4037 m_children.append(par);
4038 retval=par->parse();
4040 while (retval==TK_NEWPARA);
4041 if (par) par->markLast();
4043 DBG(("DocHtmlDescData::parse() end\n"));
4044 DocNode *n=g_nodeStack.pop();
4049 //---------------------------------------------------------------------------
4051 int DocHtmlDescList::parse()
4053 int retval=RetVal_OK;
4054 g_nodeStack.push(this);
4055 DBG(("DocHtmlDescList::parse() start\n"));
4058 int tok=doctokenizerYYlex();
4060 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4061 // should find a html tag now
4062 if (tok==TK_HTMLTAG)
4064 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4065 if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
4069 else // found some other tag
4071 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <dt> tag but "
4072 "found <%s> instead!",qPrint(g_token->name));
4073 doctokenizerYYpushBackHtmlTag(g_token->name);
4077 else if (tok==0) // premature end of comment
4079 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
4080 " for a html description title");
4083 else // token other than html token
4085 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <dt> tag but found %s token instead!",
4092 DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs);
4093 m_children.append(dt);
4094 DocHtmlDescData *dd=new DocHtmlDescData(this);
4095 m_children.append(dd);
4097 if (retval==RetVal_DescData)
4101 else if (retval!=RetVal_DescTitle)
4106 } while (retval==RetVal_DescTitle);
4110 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while inside <dl> block");
4115 DocNode *n=g_nodeStack.pop();
4117 DBG(("DocHtmlDescList::parse() end\n"));
4118 return retval==RetVal_EndDesc ? RetVal_OK : retval;
4121 //---------------------------------------------------------------------------
4123 int DocHtmlListItem::parse()
4125 DBG(("DocHtmlListItem::parse() start\n"));
4127 g_nodeStack.push(this);
4129 // parse one or more paragraphs
4134 par = new DocPara(this);
4135 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4136 m_children.append(par);
4137 retval=par->parse();
4139 while (retval==TK_NEWPARA);
4140 if (par) par->markLast();
4142 DocNode *n=g_nodeStack.pop();
4144 DBG(("DocHtmlListItem::parse() end retval=%x\n",retval));
4148 int DocHtmlListItem::parseXml()
4150 DBG(("DocHtmlListItem::parseXml() start\n"));
4152 g_nodeStack.push(this);
4154 // parse one or more paragraphs
4159 par = new DocPara(this);
4160 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4161 m_children.append(par);
4162 retval=par->parse();
4163 if (retval==0) break;
4165 //printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
4166 // retval,qPrint(g_token->name),g_token->endTag);
4167 if (retval==RetVal_ListItem)
4172 while (retval!=RetVal_CloseXml);
4174 if (par) par->markLast();
4176 DocNode *n=g_nodeStack.pop();
4178 DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
4182 //---------------------------------------------------------------------------
4184 int DocHtmlList::parse()
4186 DBG(("DocHtmlList::parse() start\n"));
4187 int retval=RetVal_OK;
4189 g_nodeStack.push(this);
4192 int tok=doctokenizerYYlex();
4193 // skip whitespace and paragraph breaks
4194 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4195 // should find a html tag now
4196 if (tok==TK_HTMLTAG)
4198 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4199 if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
4201 // ok, we can go on.
4203 else if (((m_type==Unordered && tagId==HTML_UL) ||
4204 (m_type==Ordered && tagId==HTML_OL)
4205 ) && g_token->endTag
4206 ) // found empty list
4208 // add dummy item to obtain valid HTML
4209 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4210 warn_doc_error(g_fileName,doctokenizerYYlineno,"empty list!");
4211 retval = RetVal_EndList;
4214 else // found some other tag
4216 // add dummy item to obtain valid HTML
4217 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4218 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <li> tag but "
4219 "found <%s%s> instead!",g_token->endTag?"/":"",qPrint(g_token->name));
4220 doctokenizerYYpushBackHtmlTag(g_token->name);
4224 else if (tok==0) // premature end of comment
4226 // add dummy item to obtain valid HTML
4227 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4228 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
4229 " for a html list item");
4232 else // token other than html token
4234 // add dummy item to obtain valid HTML
4235 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4236 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <li> tag but found %s token instead!",
4243 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
4244 m_children.append(li);
4246 } while (retval==RetVal_ListItem);
4250 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while inside <%cl> block",
4251 m_type==Unordered ? 'u' : 'o');
4255 DBG(("DocHtmlList::parse() end retval=%x\n",retval));
4256 DocNode *n=g_nodeStack.pop();
4258 return retval==RetVal_EndList ? RetVal_OK : retval;
4261 int DocHtmlList::parseXml()
4263 DBG(("DocHtmlList::parseXml() start\n"));
4264 int retval=RetVal_OK;
4266 g_nodeStack.push(this);
4269 int tok=doctokenizerYYlex();
4270 // skip whitespace and paragraph breaks
4271 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4272 // should find a html tag now
4273 if (tok==TK_HTMLTAG)
4275 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4276 //printf("g_token->name=%s g_token->endTag=%d\n",qPrint(g_token->name),g_token->endTag);
4277 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
4279 // ok, we can go on.
4281 else // found some other tag
4283 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <item> tag but "
4284 "found <%s> instead!",qPrint(g_token->name));
4285 doctokenizerYYpushBackHtmlTag(g_token->name);
4289 else if (tok==0) // premature end of comment
4291 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
4292 " for a html list item");
4295 else // token other than html token
4297 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <item> tag but found %s token instead!",
4304 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
4305 m_children.append(li);
4306 retval=li->parseXml();
4307 if (retval==0) break;
4308 //printf("retval=%x g_token->name=%s\n",retval,qPrint(g_token->name));
4309 } while (retval==RetVal_ListItem);
4313 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while inside <list type=\"%s\"> block",
4314 m_type==Unordered ? "bullet" : "number");
4318 DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
4319 DocNode *n=g_nodeStack.pop();
4321 return retval==RetVal_EndList ||
4322 (retval==RetVal_CloseXml || g_token->name=="list") ?
4326 //--------------------------------------------------------------------------
4328 int DocHtmlBlockQuote::parse()
4330 DBG(("DocHtmlBlockQuote::parse() start\n"));
4332 g_nodeStack.push(this);
4334 // parse one or more paragraphs
4339 par = new DocPara(this);
4340 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4341 m_children.append(par);
4342 retval=par->parse();
4344 while (retval==TK_NEWPARA);
4345 if (par) par->markLast();
4347 DocNode *n=g_nodeStack.pop();
4349 DBG(("DocHtmlBlockQuote::parse() end retval=%x\n",retval));
4350 return (retval==RetVal_EndBlockQuote) ? RetVal_OK : retval;
4353 //---------------------------------------------------------------------------
4355 int DocParBlock::parse()
4357 DBG(("DocParBlock::parse() start\n"));
4359 g_nodeStack.push(this);
4361 // parse one or more paragraphs
4366 par = new DocPara(this);
4367 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4368 m_children.append(par);
4369 retval=par->parse();
4371 while (retval==TK_NEWPARA);
4372 if (par) par->markLast();
4374 DocNode *n=g_nodeStack.pop();
4376 DBG(("DocParBlock::parse() end retval=%x\n",retval));
4377 return (retval==RetVal_EndBlockQuote) ? RetVal_OK : retval;
4380 //---------------------------------------------------------------------------
4382 int DocSimpleListItem::parse()
4384 g_nodeStack.push(this);
4385 int rv=m_paragraph->parse();
4386 m_paragraph->markFirst();
4387 m_paragraph->markLast();
4388 DocNode *n=g_nodeStack.pop();
4393 //--------------------------------------------------------------------------
4395 int DocSimpleList::parse()
4397 g_nodeStack.push(this);
4401 DocSimpleListItem *li=new DocSimpleListItem(this);
4402 m_children.append(li);
4404 } while (rv==RetVal_ListItem);
4405 DocNode *n=g_nodeStack.pop();
4407 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4410 //--------------------------------------------------------------------------
4412 DocAutoListItem::DocAutoListItem(DocNode *parent,int indent,int num)
4413 : m_indent(indent), m_itemNum(num)
4418 int DocAutoListItem::parse()
4420 int retval = RetVal_OK;
4421 g_nodeStack.push(this);
4423 // first parse any number of paragraphs
4428 DocPara *par = new DocPara(this);
4429 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4430 retval=par->parse();
4431 if (!par->isEmpty())
4433 m_children.append(par);
4434 if (lastPar) lastPar->markLast(FALSE);
4441 // next paragraph should be more indented than the - marker to belong
4443 } while (retval==TK_NEWPARA && g_token->indent>m_indent);
4444 if (lastPar) lastPar->markLast();
4446 DocNode *n=g_nodeStack.pop();
4448 //printf("DocAutoListItem: retval=%d indent=%d\n",retval,g_token->indent);
4452 //--------------------------------------------------------------------------
4454 DocAutoList::DocAutoList(DocNode *parent,int indent,bool isEnumList,
4456 m_indent(indent), m_isEnumList(isEnumList),
4462 int DocAutoList::parse()
4464 int retval = RetVal_OK;
4466 g_nodeStack.push(this);
4467 doctokenizerYYstartAutoList();
4468 // first item or sub list => create new list
4471 if (g_token->id!=-1) // explicitly numbered list
4473 num=g_token->id; // override num with real number given
4475 DocAutoListItem *li = new DocAutoListItem(this,m_indent,num++);
4476 m_children.append(li);
4478 //printf("DocAutoList::parse(): retval=0x%x g_token->indent=%d m_indent=%d "
4479 // "m_isEnumList=%d g_token->isEnumList=%d g_token->name=%s\n",
4480 // retval,g_token->indent,m_indent,m_isEnumList,g_token->isEnumList,
4481 // g_token->name.data());
4482 //printf("num=%d g_token->id=%d\n",num,g_token->id);
4484 while (retval==TK_LISTITEM && // new list item
4485 m_indent==g_token->indent && // at same indent level
4486 m_isEnumList==g_token->isEnumList && // of the same kind
4487 (g_token->id==-1 || g_token->id>=num) // increasing number (or no number)
4490 doctokenizerYYendAutoList();
4491 DocNode *n=g_nodeStack.pop();
4496 //--------------------------------------------------------------------------
4498 void DocTitle::parse()
4500 DBG(("DocTitle::parse() start\n"));
4501 g_nodeStack.push(this);
4502 doctokenizerYYsetStateTitle();
4504 while ((tok=doctokenizerYYlex()))
4506 if (!defaultHandleToken(this,tok,m_children))
4508 errorHandleDefaultToken(this,tok,m_children,"title section");
4511 doctokenizerYYsetStatePara();
4512 handlePendingStyleCommands(this,m_children);
4513 DBG(("DocTitle::parse() end\n"));
4514 DocNode *n = g_nodeStack.pop();
4518 void DocTitle::parseFromString(const QCString &text)
4520 m_children.append(new DocWord(this,text));
4523 //--------------------------------------------------------------------------
4525 DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) :
4532 DocSimpleSect::~DocSimpleSect()
4537 void DocSimpleSect::accept(DocVisitor *v)
4540 if (m_title) m_title->accept(v);
4541 QListIterator<DocNode> cli(m_children);
4543 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
4547 int DocSimpleSect::parse(bool userTitle,bool needsSeparator)
4549 DBG(("DocSimpleSect::parse() start\n"));
4550 g_nodeStack.push(this);
4552 // handle case for user defined title
4555 m_title = new DocTitle(this);
4559 // add new paragraph as child
4560 DocPara *par = new DocPara(this);
4561 if (m_children.isEmpty())
4567 ASSERT(m_children.getLast()->kind()==DocNode::Kind_Para);
4568 ((DocPara *)m_children.getLast())->markLast(FALSE);
4571 if (needsSeparator) m_children.append(new DocSimpleSectSep(this));
4572 m_children.append(par);
4574 // parse the contents of the paragraph
4575 int retval = par->parse();
4577 DBG(("DocSimpleSect::parse() end retval=%d\n",retval));
4578 DocNode *n=g_nodeStack.pop();
4580 return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec
4583 int DocSimpleSect::parseRcs()
4585 DBG(("DocSimpleSect::parseRcs() start\n"));
4586 g_nodeStack.push(this);
4588 m_title = new DocTitle(this);
4589 m_title->parseFromString(g_token->name);
4591 QCString text = g_token->text;
4592 docParserPushContext(); // this will create a new g_token
4593 internalValidatingParseDoc(this,m_children,text);
4594 docParserPopContext(); // this will restore the old g_token
4596 DBG(("DocSimpleSect::parseRcs()\n"));
4597 DocNode *n=g_nodeStack.pop();
4602 int DocSimpleSect::parseXml()
4604 DBG(("DocSimpleSect::parse() start\n"));
4605 g_nodeStack.push(this);
4607 int retval = RetVal_OK;
4610 // add new paragraph as child
4611 DocPara *par = new DocPara(this);
4612 if (m_children.isEmpty())
4618 ASSERT(m_children.getLast()->kind()==DocNode::Kind_Para);
4619 ((DocPara *)m_children.getLast())->markLast(FALSE);
4622 m_children.append(par);
4624 // parse the contents of the paragraph
4625 retval = par->parse();
4626 if (retval == 0) break;
4627 if (retval == RetVal_CloseXml)
4634 DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
4635 DocNode *n=g_nodeStack.pop();
4640 void DocSimpleSect::appendLinkWord(const QCString &word)
4643 if (m_children.isEmpty() || m_children.getLast()->kind()!=DocNode::Kind_Para)
4645 p = new DocPara(this);
4646 m_children.append(p);
4650 p = (DocPara *)m_children.getLast();
4652 // Comma-seperate <seealso> links.
4653 p->injectToken(TK_WORD,",");
4654 p->injectToken(TK_WHITESPACE," ");
4658 p->injectToken(TK_LNKWORD,word);
4662 QCString DocSimpleSect::typeString() const
4666 case Unknown: break;
4667 case See: return "see";
4668 case Return: return "return";
4669 case Author: // fall through
4670 case Authors: return "author";
4671 case Version: return "version";
4672 case Since: return "since";
4673 case Date: return "date";
4674 case Note: return "note";
4675 case Warning: return "warning";
4676 case Pre: return "pre";
4677 case Post: return "post";
4678 case Copyright: return "copyright";
4679 case Invar: return "invariant";
4680 case Remark: return "remark";
4681 case Attention: return "attention";
4682 case User: return "user";
4683 case Rcs: return "rcs";
4688 //--------------------------------------------------------------------------
4690 int DocParamList::parse(const QCString &cmdName)
4692 int retval=RetVal_OK;
4693 DBG(("DocParamList::parse() start\n"));
4694 g_nodeStack.push(this);
4696 QCString saveCmdName = cmdName;
4698 int tok=doctokenizerYYlex();
4699 if (tok!=TK_WHITESPACE)
4701 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
4706 doctokenizerYYsetStateParam();
4707 tok=doctokenizerYYlex();
4708 while (tok==TK_WORD) /* there is a parameter name */
4710 if (m_type==DocParamSect::Param)
4712 int typeSeparator = g_token->name.find('#'); // explicit type position
4713 if (typeSeparator!=-1)
4715 handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator));
4716 g_token->name = g_token->name.mid(typeSeparator+1);
4717 g_hasParamCommand=TRUE;
4718 checkArgumentName(g_token->name,TRUE);
4719 ((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE;
4723 g_hasParamCommand=TRUE;
4724 checkArgumentName(g_token->name,TRUE);
4727 else if (m_type==DocParamSect::RetVal)
4729 g_hasReturnCommand=TRUE;
4730 checkArgumentName(g_token->name,FALSE);
4732 //m_params.append(g_token->name);
4733 handleLinkedWord(this,m_params);
4734 tok=doctokenizerYYlex();
4736 doctokenizerYYsetStatePara();
4737 if (tok==0) /* premature end of comment block */
4739 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
4740 "argument of command %s",qPrint(cmdName));
4744 if (tok!=TK_WHITESPACE) /* premature end of comment block */
4746 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token in comment block while parsing the "
4747 "argument of command %s",qPrint(saveCmdName));
4752 par = new DocPara(this);
4753 m_paragraphs.append(par);
4754 retval = par->parse();
4759 DBG(("DocParamList::parse() end retval=%d\n",retval));
4760 DocNode *n=g_nodeStack.pop();
4765 int DocParamList::parseXml(const QCString ¶mName)
4767 int retval=RetVal_OK;
4768 DBG(("DocParamList::parseXml() start\n"));
4769 g_nodeStack.push(this);
4771 g_token->name = paramName;
4772 if (m_type==DocParamSect::Param)
4774 g_hasParamCommand=TRUE;
4775 checkArgumentName(g_token->name,TRUE);
4777 else if (m_type==DocParamSect::RetVal)
4779 g_hasReturnCommand=TRUE;
4780 checkArgumentName(g_token->name,FALSE);
4783 handleLinkedWord(this,m_params);
4787 DocPara *par = new DocPara(this);
4788 retval = par->parse();
4789 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
4790 // after </para> and before </param>
4795 else // append the paragraph to the list
4797 if (m_paragraphs.isEmpty())
4803 m_paragraphs.getLast()->markLast(FALSE);
4806 m_paragraphs.append(par);
4809 if (retval == 0) break;
4811 } while (retval==RetVal_CloseXml &&
4812 Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
4813 Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM &&
4814 Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
4817 if (retval==0) /* premature end of comment block */
4819 warn_doc_error(g_fileName,doctokenizerYYlineno,"unterminated param or exception tag");
4827 DBG(("DocParamList::parse() end retval=%d\n",retval));
4828 DocNode *n=g_nodeStack.pop();
4833 //--------------------------------------------------------------------------
4835 int DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
4837 int retval=RetVal_OK;
4838 DBG(("DocParamSect::parse() start\n"));
4839 g_nodeStack.push(this);
4843 m_hasInOutSpecifier=TRUE;
4846 DocParamList *pl = new DocParamList(this,m_type,d);
4847 if (m_children.isEmpty())
4854 ASSERT(m_children.getLast()->kind()==DocNode::Kind_ParamList);
4855 ((DocParamList *)m_children.getLast())->markLast(FALSE);
4858 m_children.append(pl);
4861 retval = pl->parseXml(cmdName);
4865 retval = pl->parse(cmdName);
4867 if (retval==RetVal_EndParBlock)
4872 DBG(("DocParamSect::parse() end retval=%d\n",retval));
4873 DocNode *n=g_nodeStack.pop();
4878 //--------------------------------------------------------------------------
4880 int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
4882 DocSimpleSect *ss=0;
4883 bool needsSeparator = FALSE;
4884 if (!m_children.isEmpty() && // previous element
4885 m_children.getLast()->kind()==Kind_SimpleSect && // was a simple sect
4886 ((DocSimpleSect *)m_children.getLast())->type()==t && // of same type
4887 t!=DocSimpleSect::User) // but not user defined
4889 // append to previous section
4890 ss=(DocSimpleSect *)m_children.getLast();
4891 needsSeparator = TRUE;
4893 else // start new section
4895 ss=new DocSimpleSect(this,t);
4896 m_children.append(ss);
4901 return ss->parseXml();
4905 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
4907 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4910 int DocPara::handleParamSection(const QCString &cmdName,
4911 DocParamSect::Type t,
4912 bool xmlContext=FALSE,
4913 int direction=DocParamSect::Unspecified)
4916 if (!m_children.isEmpty() && // previous element
4917 m_children.getLast()->kind()==Kind_ParamSect && // was a param sect
4918 ((DocParamSect *)m_children.getLast())->type()==t) // of same type
4920 // append to previous section
4921 ps=(DocParamSect *)m_children.getLast();
4923 else // start new section
4925 ps=new DocParamSect(this,t);
4926 m_children.append(ps);
4928 int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
4929 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4932 void DocPara::handleCite()
4934 // get the argument of the cite command.
4935 int tok=doctokenizerYYlex();
4936 if (tok!=TK_WHITESPACE)
4938 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
4942 doctokenizerYYsetStateCite();
4943 tok=doctokenizerYYlex();
4946 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
4947 "argument of command %s\n", qPrint("cite"));
4950 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
4952 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
4953 tokToString(tok),qPrint("cite"));
4956 g_token->sectionId = g_token->name;
4957 DocCite *cite = new DocCite(this,g_token->name,g_context);
4958 m_children.append(cite);
4961 doctokenizerYYsetStatePara();
4964 void DocPara::handleEmoji()
4966 // get the argument of the emoji command.
4967 int tok=doctokenizerYYlex();
4968 if (tok!=TK_WHITESPACE)
4970 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
4974 doctokenizerYYsetStateEmoji();
4975 tok=doctokenizerYYlex();
4978 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
4979 "argument of command %s\n", qPrint("emoji"));
4982 else if (tok!=TK_WORD)
4984 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
4985 tokToString(tok),qPrint("emoji"));
4988 DocEmoji *emoji = new DocEmoji(this,g_token->name);
4989 m_children.append(emoji);
4990 doctokenizerYYsetStatePara();
4993 int DocPara::handleXRefItem()
4995 int retval=doctokenizerYYlex();
4996 ASSERT(retval==TK_WHITESPACE);
4997 doctokenizerYYsetStateXRefItem();
4998 retval=doctokenizerYYlex();
4999 if (retval==RetVal_OK)
5001 DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name);
5004 m_children.append(ref);
5011 doctokenizerYYsetStatePara();
5015 void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t)
5017 DBG(("handleIncludeOperator(%s)\n",qPrint(cmdName)));
5018 int tok=doctokenizerYYlex();
5019 if (tok!=TK_WHITESPACE)
5021 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5025 doctokenizerYYsetStatePattern();
5026 tok=doctokenizerYYlex();
5027 doctokenizerYYsetStatePara();
5030 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
5031 "argument of command %s", qPrint(cmdName));
5034 else if (tok!=TK_WORD)
5036 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5037 tokToString(tok),qPrint(cmdName));
5040 DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
5041 QListIterator<DocNode> it(m_children);
5042 DocNode *n1 = it.toLast();
5044 DocNode *n2 = n1!=0 ? it.current() : 0;
5045 bool isFirst = n1==0 || // no last node
5046 (n1->kind()!=DocNode::Kind_IncOperator &&
5047 n1->kind()!=DocNode::Kind_WhiteSpace
5048 ) || // last node is not operator or whitespace
5049 (n1->kind()==DocNode::Kind_WhiteSpace &&
5050 n2!=0 && n2->kind()!=DocNode::Kind_IncOperator
5051 ); // previous not is not operator
5052 op->markFirst(isFirst);
5054 if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator)
5056 ((DocIncOperator *)n1)->markLast(FALSE);
5058 else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace &&
5059 n2!=0 && n2->kind()==DocNode::Kind_IncOperator
5062 ((DocIncOperator *)n2)->markLast(FALSE);
5064 m_children.append(op);
5068 void DocPara::handleImage(const QCString &cmdName)
5070 QCString saveCmdName = cmdName;
5071 bool inlineImage = FALSE;
5073 int tok=doctokenizerYYlex();
5074 if (tok!=TK_WHITESPACE)
5078 if (g_token->name == "{")
5080 while ((tok=doctokenizerYYlex())==TK_WHITESPACE);
5081 if (g_token->name != "}") // non-empty option string
5083 if (g_token->name.lower() != "inline")
5085 warn_doc_error(g_fileName,doctokenizerYYlineno,"currently only 'inline' suported as option of %s command",
5086 qPrint(saveCmdName));
5092 while ((tok=doctokenizerYYlex())==TK_WHITESPACE);
5094 if (!((tok==TK_WORD) && (g_token->name == "}")))
5096 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected closing '}' at option of %s command",
5097 qPrint(saveCmdName));
5100 tok=doctokenizerYYlex();
5101 if (tok!=TK_WHITESPACE)
5103 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command with option",
5104 qPrint(saveCmdName));
5111 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5112 qPrint(saveCmdName));
5116 tok=doctokenizerYYlex();
5117 if (tok!=TK_WORD && tok!=TK_LNKWORD)
5119 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5120 tokToString(tok),qPrint(saveCmdName));
5123 tok=doctokenizerYYlex();
5124 if (tok!=TK_WHITESPACE)
5126 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5127 qPrint(saveCmdName));
5131 QCString imgType = g_token->name.lower();
5132 if (imgType=="html") t=DocImage::Html;
5133 else if (imgType=="latex") t=DocImage::Latex;
5134 else if (imgType=="docbook") t=DocImage::DocBook;
5135 else if (imgType=="rtf") t=DocImage::Rtf;
5138 warn_doc_error(g_fileName,doctokenizerYYlineno,"output format %s specified as the first argument of "
5139 "%s command is not valid",
5140 qPrint(imgType),qPrint(saveCmdName));
5143 doctokenizerYYsetStateFile();
5144 tok=doctokenizerYYlex();
5145 doctokenizerYYsetStatePara();
5148 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5149 tokToString(tok),qPrint(saveCmdName));
5152 HtmlAttribList attrList;
5153 DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t,"",inlineImage);
5154 m_children.append(img);
5159 void DocPara::handleFile(const QCString &cmdName)
5161 int tok=doctokenizerYYlex();
5162 if (tok!=TK_WHITESPACE)
5164 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5168 doctokenizerYYsetStateFile();
5169 tok=doctokenizerYYlex();
5170 doctokenizerYYsetStatePara();
5173 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5174 tokToString(tok),qPrint(cmdName));
5177 QCString name = g_token->name;
5178 T *df = new T(this,name,g_context);
5179 m_children.append(df);
5183 void DocPara::handleVhdlFlow()
5185 DocVhdlFlow *vf = new DocVhdlFlow(this);
5186 m_children.append(vf);
5190 void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
5192 int tok=doctokenizerYYlex();
5193 if (tok!=TK_WHITESPACE)
5195 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5199 doctokenizerYYsetStateLink();
5200 tok=doctokenizerYYlex();
5203 warn_doc_error(g_fileName,doctokenizerYYlineno,"%s as the argument of %s",
5204 tokToString(tok),qPrint(cmdName));
5207 doctokenizerYYsetStatePara();
5208 DocLink *lnk = new DocLink(this,g_token->name);
5209 m_children.append(lnk);
5210 QCString leftOver = lnk->parse(isJavaLink);
5211 if (!leftOver.isEmpty())
5213 m_children.append(new DocWord(this,leftOver));
5217 void DocPara::handleRef(const QCString &cmdName)
5219 DBG(("handleRef(%s)\n",qPrint(cmdName)));
5220 int tok=doctokenizerYYlex();
5221 if (tok!=TK_WHITESPACE)
5223 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5227 doctokenizerYYsetStateRef();
5228 tok=doctokenizerYYlex(); // get the reference id
5232 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5233 tokToString(tok),qPrint(cmdName));
5236 ref = new DocRef(this,g_token->name,g_context);
5237 m_children.append(ref);
5240 doctokenizerYYsetStatePara();
5243 void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
5245 DBG(("handleInclude(%s)\n",qPrint(cmdName)));
5246 int tok=doctokenizerYYlex();
5247 bool isBlock = false;
5248 if (tok==TK_WORD && g_token->name=="{")
5250 doctokenizerYYsetStateOptions();
5251 tok=doctokenizerYYlex();
5252 doctokenizerYYsetStatePara();
5253 QCStringList optList=QCStringList::split(",",g_token->name);
5254 if (t==DocInclude::Include && optList.contains("lineno"))
5256 t = DocInclude::IncWithLines;
5258 else if (t==DocInclude::Snippet && optList.contains("lineno"))
5260 t = DocInclude::SnipWithLines;
5262 else if (t==DocInclude::Include && optList.contains("doc"))
5264 t = DocInclude::IncludeDoc;
5266 else if (t==DocInclude::Snippet && optList.contains("doc"))
5268 t = DocInclude::SnippetDoc;
5270 tok=doctokenizerYYlex();
5272 else if (tok==TK_WORD && g_token->name=="[")
5274 doctokenizerYYsetStateBlock();
5275 tok=doctokenizerYYlex();
5276 isBlock = (g_token->name.stripWhiteSpace() == "block");
5277 doctokenizerYYsetStatePara();
5278 tok=doctokenizerYYlex();
5280 else if (tok!=TK_WHITESPACE)
5282 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5286 doctokenizerYYsetStateFile();
5287 tok=doctokenizerYYlex();
5288 doctokenizerYYsetStatePara();
5291 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
5292 "argument of command %s",qPrint(cmdName));
5295 else if (tok!=TK_WORD)
5297 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5298 tokToString(tok),qPrint(cmdName));
5301 QCString fileName = g_token->name;
5303 if (t==DocInclude::Snippet || t==DocInclude::SnipWithLines || t==DocInclude::SnippetDoc)
5305 if (fileName == "this") fileName=g_fileName;
5306 doctokenizerYYsetStateSnippet();
5307 tok=doctokenizerYYlex();
5308 doctokenizerYYsetStatePara();
5311 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected block identifier, but found token %s instead while parsing the %s command",
5312 tokToString(tok),qPrint(cmdName));
5315 blockId = "["+g_token->name+"]";
5318 // This is the only place to handle the \includedoc and \snippetdoc commands,
5319 // as the content is included here as if it is really here.
5320 if (t==DocInclude::IncludeDoc || t==DocInclude::SnippetDoc)
5324 readTextFileByName(fileName,inc_text);
5325 if (t==DocInclude::SnippetDoc)
5327 inc_line = lineBlock(inc_text, blockId);
5328 inc_text = extractBlock(inc_text, blockId);
5330 docParserPushContext();
5331 g_fileName = fileName;
5332 doctokenizerYYlineno=inc_line;
5333 internalValidatingParseDoc(this,m_children,inc_text);
5334 docParserPopContext();
5338 DocInclude *inc = new DocInclude(this,fileName,g_context,t,g_isExample,g_exampleName,blockId,isBlock);
5339 m_children.append(inc);
5344 void DocPara::handleSection(const QCString &cmdName)
5346 // get the argument of the section command.
5347 int tok=doctokenizerYYlex();
5348 if (tok!=TK_WHITESPACE)
5350 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5354 tok=doctokenizerYYlex();
5357 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
5358 "argument of command %s\n", qPrint(cmdName));
5361 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
5363 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5364 tokToString(tok),qPrint(cmdName));
5367 g_token->sectionId = g_token->name;
5368 doctokenizerYYsetStateSkipTitle();
5369 doctokenizerYYlex();
5370 doctokenizerYYsetStatePara();
5373 int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
5375 DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level);
5376 m_children.append(header);
5377 int retval = header->parse();
5378 return (retval==RetVal_OK) ? TK_NEWPARA : retval;
5381 // For XML tags whose content is stored in attributes rather than
5382 // contained within the element, we need a way to inject the attribute
5383 // text into the current paragraph.
5384 bool DocPara::injectToken(int tok,const QCString &tokText)
5386 g_token->name = tokText;
5387 return defaultHandleToken(this,tok,m_children);
5390 int DocPara::handleStartCode()
5392 int retval = doctokenizerYYlex();
5393 QCString lang = g_token->name;
5394 if (!lang.isEmpty() && lang.at(0)!='.')
5400 g_token->verb = substitute(substitute(g_token->verb,"<","<"),">",">");
5402 // search for the first non-whitespace line, index is stored in li
5403 int i=0,li=0,l=g_token->verb.length();
5404 while (i<l && (g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n'))
5406 if (g_token->verb.at(i)=='\n') li=i+1;
5409 m_children.append(new DocVerbatim(this,g_context,stripIndentation(g_token->verb.mid(li)),DocVerbatim::Code,g_isExample,g_exampleName,FALSE,lang));
5410 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"code section ended without end marker");
5411 doctokenizerYYsetStatePara();
5415 void DocPara::handleInheritDoc()
5417 if (g_memberDef) // inheriting docs from a member
5419 MemberDef *reMd = g_memberDef->reimplements();
5420 if (reMd) // member from which was inherited.
5422 MemberDef *thisMd = g_memberDef;
5423 //printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data());
5424 docParserPushContext();
5425 g_scope=reMd->getOuterScope();
5426 if (g_scope!=Doxygen::globalScope)
5428 g_context=g_scope->name();
5431 g_styleStack.clear();
5432 g_nodeStack.clear();
5433 g_copyStack.append(reMd);
5434 internalValidatingParseDoc(this,m_children,reMd->briefDescription());
5435 internalValidatingParseDoc(this,m_children,reMd->documentation());
5436 g_copyStack.remove(reMd);
5437 docParserPopContext(TRUE);
5438 g_memberDef = thisMd;
5444 int DocPara::handleCommand(const QCString &cmdName, const int tok)
5446 DBG(("handleCommand(%s)\n",qPrint(cmdName)));
5447 int retval = RetVal_OK;
5448 int cmdId = Mappers::cmdMapper->map(cmdName);
5452 m_children.append(new DocWord(this,TK_COMMAND_CHAR(tok) + cmdName));
5453 warn_doc_error(g_fileName,doctokenizerYYlineno,"Found unknown command `\\%s'",qPrint(cmdName));
5456 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
5457 retval=handleStyleArgument(this,m_children,cmdName);
5458 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
5459 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5462 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
5463 retval=handleStyleArgument(this,m_children,cmdName);
5464 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
5465 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5468 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
5469 retval=handleStyleArgument(this,m_children,cmdName);
5470 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
5471 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5474 m_children.append(new DocSymbol(this,DocSymbol::Sym_BSlash));
5477 m_children.append(new DocSymbol(this,DocSymbol::Sym_At));
5480 m_children.append(new DocSymbol(this,DocSymbol::Sym_Less));
5483 m_children.append(new DocSymbol(this,DocSymbol::Sym_Greater));
5486 m_children.append(new DocSymbol(this,DocSymbol::Sym_Amp));
5489 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dollar));
5492 m_children.append(new DocSymbol(this,DocSymbol::Sym_Hash));
5495 m_children.append(new DocSymbol(this,DocSymbol::Sym_Pipe));
5498 m_children.append(new DocSymbol(this,DocSymbol::Sym_DoubleColon));
5501 m_children.append(new DocSymbol(this,DocSymbol::Sym_Percent));
5504 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5505 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5508 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5509 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5510 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5513 m_children.append(new DocSymbol(this,DocSymbol::Sym_Quot));
5516 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dot));
5519 m_children.append(new DocSymbol(this,DocSymbol::Sym_Plus));
5522 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5525 m_children.append(new DocSymbol(this,DocSymbol::Sym_Equal));
5529 retval = handleSimpleSection(DocSimpleSect::See);
5533 retval = handleSimpleSection(DocSimpleSect::Return);
5534 g_hasReturnCommand=TRUE;
5537 retval = handleSimpleSection(DocSimpleSect::Author);
5540 retval = handleSimpleSection(DocSimpleSect::Authors);
5543 retval = handleSimpleSection(DocSimpleSect::Version);
5546 retval = handleSimpleSection(DocSimpleSect::Since);
5549 retval = handleSimpleSection(DocSimpleSect::Date);
5552 retval = handleSimpleSection(DocSimpleSect::Note);
5555 retval = handleSimpleSection(DocSimpleSect::Warning);
5558 retval = handleSimpleSection(DocSimpleSect::Pre);
5561 retval = handleSimpleSection(DocSimpleSect::Post);
5564 retval = handleSimpleSection(DocSimpleSect::Copyright);
5567 retval = handleSimpleSection(DocSimpleSect::Invar);
5570 retval = handleSimpleSection(DocSimpleSect::Remark);
5573 retval = handleSimpleSection(DocSimpleSect::Attention);
5576 retval = handleSimpleSection(DocSimpleSect::User);
5580 DocSimpleList *sl=new DocSimpleList(this);
5581 m_children.append(sl);
5582 retval = sl->parse();
5587 handleSection(cmdName);
5588 retval = RetVal_Section;
5591 case CMD_SUBSECTION:
5593 handleSection(cmdName);
5594 retval = RetVal_Subsection;
5597 case CMD_SUBSUBSECTION:
5599 handleSection(cmdName);
5600 retval = RetVal_Subsubsection;
5605 handleSection(cmdName);
5606 retval = RetVal_Paragraph;
5611 doctokenizerYYsetStateCode();
5612 retval = handleStartCode();
5617 doctokenizerYYsetStateHtmlOnly();
5618 retval = doctokenizerYYlex();
5619 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName,g_token->name=="block"));
5620 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"htmlonly section ended without end marker");
5621 doctokenizerYYsetStatePara();
5626 doctokenizerYYsetStateManOnly();
5627 retval = doctokenizerYYlex();
5628 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
5629 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"manonly section ended without end marker");
5630 doctokenizerYYsetStatePara();
5635 doctokenizerYYsetStateRtfOnly();
5636 retval = doctokenizerYYlex();
5637 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::RtfOnly,g_isExample,g_exampleName));
5638 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"rtfonly section ended without end marker");
5639 doctokenizerYYsetStatePara();
5644 doctokenizerYYsetStateLatexOnly();
5645 retval = doctokenizerYYlex();
5646 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
5647 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"latexonly section ended without end marker");
5648 doctokenizerYYsetStatePara();
5653 doctokenizerYYsetStateXmlOnly();
5654 retval = doctokenizerYYlex();
5655 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
5656 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"xmlonly section ended without end marker");
5657 doctokenizerYYsetStatePara();
5662 doctokenizerYYsetStateDbOnly();
5663 retval = doctokenizerYYlex();
5664 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::DocbookOnly,g_isExample,g_exampleName));
5665 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"docbookonly section ended without end marker",doctokenizerYYlineno);
5666 doctokenizerYYsetStatePara();
5671 doctokenizerYYsetStateVerbatim();
5672 retval = doctokenizerYYlex();
5673 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName));
5674 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"verbatim section ended without end marker");
5675 doctokenizerYYsetStatePara();
5680 DocVerbatim *dv = new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName);
5681 doctokenizerYYsetStatePara();
5682 QCString width,height;
5683 defaultHandleTitleAndSize(CMD_DOT,dv,dv->children(),width,height);
5684 doctokenizerYYsetStateDot();
5685 retval = doctokenizerYYlex();
5686 dv->setText(g_token->verb);
5687 dv->setWidth(width);
5688 dv->setHeight(height);
5689 m_children.append(dv);
5690 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"dot section ended without end marker");
5691 doctokenizerYYsetStatePara();
5696 DocVerbatim *dv = new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName);
5697 doctokenizerYYsetStatePara();
5698 QCString width,height;
5699 defaultHandleTitleAndSize(CMD_MSC,dv,dv->children(),width,height);
5700 doctokenizerYYsetStateMsc();
5701 retval = doctokenizerYYlex();
5702 dv->setText(g_token->verb);
5703 dv->setWidth(width);
5704 dv->setHeight(height);
5705 m_children.append(dv);
5706 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"msc section ended without end marker");
5707 doctokenizerYYsetStatePara();
5712 static QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
5713 doctokenizerYYsetStatePlantUMLOpt();
5714 retval = doctokenizerYYlex();
5715 QCString plantFile(g_token->sectionId);
5716 DocVerbatim *dv = new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::PlantUML,FALSE,plantFile);
5717 doctokenizerYYsetStatePara();
5718 QCString width,height;
5719 defaultHandleTitleAndSize(CMD_STARTUML,dv,dv->children(),width,height);
5720 doctokenizerYYsetStatePlantUML();
5721 retval = doctokenizerYYlex();
5723 dv->setText(stripLeadingAndTrailingEmptyLines(g_token->verb,line));
5724 dv->setWidth(width);
5725 dv->setHeight(height);
5726 if (jarPath.isEmpty())
5728 warn_doc_error(g_fileName,doctokenizerYYlineno,"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
5733 m_children.append(dv);
5735 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"startuml section ended without end marker");
5736 doctokenizerYYsetStatePara();
5739 case CMD_ENDPARBLOCK:
5740 retval=RetVal_EndParBlock;
5743 case CMD_ENDHTMLONLY:
5744 case CMD_ENDMANONLY:
5745 case CMD_ENDRTFONLY:
5746 case CMD_ENDLATEXONLY:
5747 case CMD_ENDXMLONLY:
5750 case CMD_ENDVERBATIM:
5754 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5757 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
5760 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir);
5763 retval = handleParamSection(cmdName,DocParamSect::RetVal);
5766 retval = handleParamSection(cmdName,DocParamSect::Exception);
5769 retval = handleXRefItem();
5773 DocLineBreak *lb = new DocLineBreak(this);
5774 m_children.append(lb);
5779 DocAnchor *anchor = handleAnchor(this);
5782 m_children.append(anchor);
5788 DocIndexEntry *ie = new DocIndexEntry(this,
5789 g_scope!=Doxygen::globalScope?g_scope:0,
5791 m_children.append(ie);
5792 retval = ie->parse();
5796 retval = RetVal_Internal;
5798 case CMD_ENDINTERNAL:
5799 retval = RetVal_EndInternal;
5803 DocParBlock *block = new DocParBlock(this);
5804 m_children.append(block);
5805 retval = block->parse();
5808 case CMD_COPYDOC: // fall through
5809 case CMD_COPYBRIEF: // fall through
5810 case CMD_COPYDETAILS:
5811 //retval = RetVal_CopyDoc;
5812 // these commands should already be resolved by processCopyDoc()
5815 handleInclude(cmdName,DocInclude::Include);
5817 case CMD_INCWITHLINES:
5818 handleInclude(cmdName,DocInclude::IncWithLines);
5820 case CMD_DONTINCLUDE:
5821 handleInclude(cmdName,DocInclude::DontInclude);
5823 case CMD_HTMLINCLUDE:
5824 handleInclude(cmdName,DocInclude::HtmlInclude);
5826 case CMD_LATEXINCLUDE:
5827 handleInclude(cmdName,DocInclude::LatexInclude);
5829 case CMD_VERBINCLUDE:
5830 handleInclude(cmdName,DocInclude::VerbInclude);
5833 handleInclude(cmdName,DocInclude::Snippet);
5835 case CMD_SNIPWITHLINES:
5836 handleInclude(cmdName,DocInclude::SnipWithLines);
5838 case CMD_INCLUDEDOC:
5839 handleInclude(cmdName,DocInclude::IncludeDoc);
5841 case CMD_SNIPPETDOC:
5842 handleInclude(cmdName,DocInclude::SnippetDoc);
5845 handleIncludeOperator(cmdName,DocIncOperator::Skip);
5848 handleIncludeOperator(cmdName,DocIncOperator::Until);
5851 handleIncludeOperator(cmdName,DocIncOperator::SkipLine);
5854 handleIncludeOperator(cmdName,DocIncOperator::Line);
5857 handleImage(cmdName);
5860 handleFile<DocDotFile>(cmdName);
5866 handleFile<DocMscFile>(cmdName);
5869 handleFile<DocDiaFile>(cmdName);
5872 handleLink(cmdName,FALSE);
5875 handleLink(cmdName,TRUE);
5883 case CMD_REF: // fall through
5887 case CMD_SECREFLIST:
5889 DocSecRefList *list = new DocSecRefList(this);
5890 m_children.append(list);
5894 case CMD_SECREFITEM:
5895 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5897 case CMD_ENDSECREFLIST:
5898 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5902 DocFormula *form=new DocFormula(this,g_token->id);
5903 m_children.append(form);
5906 //case CMD_LANGSWITCH:
5907 // retval = handleLanguageSwitch();
5909 case CMD_INTERNALREF:
5910 //warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5912 DocInternalRef *ref = handleInternalRef(this);
5915 m_children.append(ref);
5918 doctokenizerYYsetStatePara();
5921 case CMD_INHERITDOC:
5925 // we should not get here!
5929 INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec ||
5930 retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA ||
5931 retval==RetVal_Section || retval==RetVal_EndList ||
5932 retval==RetVal_Internal || retval==RetVal_SwitchLang ||
5933 retval==RetVal_EndInternal
5935 DBG(("handleCommand(%s) end retval=%x\n",qPrint(cmdName),retval));
5939 static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
5940 const char *attrName,
5944 HtmlAttribListIterator li(tagHtmlAttribs);
5946 for (li.toFirst();(opt=li.current());++li)
5948 if (opt->name==attrName)
5950 *result = opt->value;
5957 int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
5959 DBG(("handleHtmlStartTag(%s,%d)\n",qPrint(tagName),tagHtmlAttribs.count()));
5960 int retval=RetVal_OK;
5961 int tagId = Mappers::htmlTagMapper->map(tagName);
5962 if (g_token->emptyTag && !(tagId&XML_CmdMask) &&
5963 tagId!=HTML_UNKNOWN && tagId!=HTML_IMG && tagId!=HTML_BR)
5965 warn_doc_error(g_fileName,doctokenizerYYlineno,"HTML tags may not use the 'empty tag' XHTML syntax.");
5971 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered);
5972 m_children.append(list);
5973 retval=list->parse();
5978 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered);
5979 m_children.append(list);
5980 retval=list->parse();
5984 if (!insideUL(this) && !insideOL(this))
5986 warn_doc_error(g_fileName,doctokenizerYYlineno,"lonely <li> tag found");
5990 retval=RetVal_ListItem;
5994 handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
5997 handleStyleEnter(this,m_children,DocStyleChange::Strike,&g_token->attribs);
5999 case HTML_UNDERLINE:
6000 handleStyleEnter(this,m_children,DocStyleChange::Underline,&g_token->attribs);
6003 if (/*getLanguageFromFileName(g_fileName)==SrcLangExt_CSharp ||*/ g_xmlComment)
6004 // for C# source or inside a <summary> or <remark> section we
6005 // treat <code> as an XML tag (so similar to @code)
6007 doctokenizerYYsetStateXmlCode();
6008 retval = handleStartCode();
6010 else // normal HTML markup
6012 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
6016 handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
6019 handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs);
6022 handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs);
6025 handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs);
6028 handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs);
6031 handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs);
6034 handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs);
6037 handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
6038 setInsidePreformatted(TRUE);
6039 doctokenizerYYsetInsidePre(TRUE);
6046 DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs);
6047 m_children.append(list);
6048 retval=list->parse();
6052 retval = RetVal_DescTitle;
6055 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag <dd> found");
6059 DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
6060 m_children.append(table);
6061 retval=table->parse();
6065 retval = RetVal_TableRow;
6068 retval = RetVal_TableCell;
6071 retval = RetVal_TableHCell;
6074 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag <caption> found");
6078 DocLineBreak *lb = new DocLineBreak(this);
6079 m_children.append(lb);
6084 DocHorRuler *hr = new DocHorRuler(this);
6085 m_children.append(hr);
6089 retval=handleAHref(this,m_children,tagHtmlAttribs);
6092 retval=handleHtmlHeader(tagHtmlAttribs,1);
6095 retval=handleHtmlHeader(tagHtmlAttribs,2);
6098 retval=handleHtmlHeader(tagHtmlAttribs,3);
6101 retval=handleHtmlHeader(tagHtmlAttribs,4);
6104 retval=handleHtmlHeader(tagHtmlAttribs,5);
6107 retval=handleHtmlHeader(tagHtmlAttribs,6);
6111 handleImg(this,m_children,tagHtmlAttribs);
6114 case HTML_BLOCKQUOTE:
6116 DocHtmlBlockQuote *block = new DocHtmlBlockQuote(this,tagHtmlAttribs);
6117 m_children.append(block);
6118 retval = block->parse();
6129 if (!m_children.isEmpty())
6131 retval = TK_NEWPARA;
6134 case XML_DESCRIPTION:
6135 if (insideTable(this))
6137 retval=RetVal_TableCell;
6141 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
6148 if (findAttribute(tagHtmlAttribs,"name",¶mName))
6150 if (paramName.isEmpty())
6152 if (Config_getBool(WARN_NO_PARAMDOC))
6154 warn_doc_error(g_fileName,doctokenizerYYlineno,"empty 'name' attribute for <param%s> tag.",tagId==XML_PARAM?"":"type");
6159 retval = handleParamSection(paramName,
6160 tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam,
6166 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'name' attribute from <param%s> tag.",tagId==XML_PARAM?"":"type");
6171 case XML_TYPEPARAMREF:
6174 if (findAttribute(tagHtmlAttribs,"name",¶mName))
6176 //printf("paramName=%s\n",paramName.data());
6177 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
6178 m_children.append(new DocWord(this,paramName));
6179 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
6180 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
6184 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type");
6191 QCString exceptName;
6192 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
6194 unescapeCRef(exceptName);
6195 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
6199 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'cref' attribute from <exception> tag.");
6204 case XML_LISTHEADER:
6205 if (insideTable(this))
6207 retval=RetVal_TableRow;
6209 else if (insideUL(this) || insideOL(this))
6211 retval=RetVal_ListItem;
6215 warn_doc_error(g_fileName,doctokenizerYYlineno,"lonely <item> tag found");
6220 retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
6221 g_hasReturnCommand=TRUE;
6224 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
6225 if (insideTable(this))
6227 retval=RetVal_TableCell;
6231 // I'm not sure if <see> is the same as <seealso> or if it
6232 // should you link a member without producing a section. The
6233 // C# specification is extremely vague about this (but what else
6234 // can we expect from Microsoft...)
6237 //printf("XML_SEE: empty tag=%d\n",g_token->emptyTag);
6238 if (findAttribute(tagHtmlAttribs,"cref",&cref))
6241 if (g_token->emptyTag) // <see cref="..."/> style
6243 bool inSeeBlock = g_inSeeBlock;
6244 g_token->name = cref;
6245 g_inSeeBlock = TRUE;
6246 handleLinkedWord(this,m_children,TRUE);
6247 g_inSeeBlock = inSeeBlock;
6249 else // <see cref="...">...</see> style
6251 //DocRef *ref = new DocRef(this,cref);
6252 //m_children.append(ref);
6254 doctokenizerYYsetStatePara();
6255 DocLink *lnk = new DocLink(this,cref);
6256 m_children.append(lnk);
6257 QCString leftOver = lnk->parse(FALSE,TRUE);
6258 if (!leftOver.isEmpty())
6260 m_children.append(new DocWord(this,leftOver));
6264 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langword="..."></see>
6266 bool inSeeBlock = g_inSeeBlock;
6267 g_token->name = cref;
6268 g_inSeeBlock = TRUE;
6269 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
6270 handleLinkedWord(this,m_children,TRUE);
6271 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
6272 g_inSeeBlock = inSeeBlock;
6276 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'cref' or 'langword' attribute from <see> tag.");
6284 if (findAttribute(tagHtmlAttribs,"cref",&cref))
6287 // Look for an existing "see" section
6288 DocSimpleSect *ss=0;
6289 QListIterator<DocNode> cli(m_children);
6291 for (cli.toFirst();(n=cli.current());++cli)
6293 if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
6295 ss = (DocSimpleSect *)n;
6299 if (!ss) // start new section
6301 ss=new DocSimpleSect(this,DocSimpleSect::See);
6302 m_children.append(ss);
6305 ss->appendLinkWord(cref);
6310 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'cref' attribute from <seealso> tag.");
6317 findAttribute(tagHtmlAttribs,"type",&type);
6318 DocHtmlList::Type listType = DocHtmlList::Unordered;
6319 HtmlAttribList emptyList;
6322 listType=DocHtmlList::Ordered;
6326 DocHtmlTable *table = new DocHtmlTable(this,emptyList);
6327 m_children.append(table);
6328 retval=table->parseXml();
6332 DocHtmlList *list = new DocHtmlList(this,emptyList,listType);
6333 m_children.append(list);
6334 retval=list->parseXml();
6339 case XML_PERMISSION:
6340 // These tags are defined in .Net but are currently unsupported
6344 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported xml/html tag <%s> found", qPrint(tagName));
6345 m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
6347 case XML_INHERITDOC:
6351 // we should not get here!
6358 int DocPara::handleHtmlEndTag(const QCString &tagName)
6360 DBG(("handleHtmlEndTag(%s)\n",qPrint(tagName)));
6361 int tagId = Mappers::htmlTagMapper->map(tagName);
6362 int retval=RetVal_OK;
6366 if (!insideUL(this))
6368 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </ul> tag without matching <ul>");
6372 retval=RetVal_EndList;
6376 if (!insideOL(this))
6378 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </ol> tag without matching <ol>");
6382 retval=RetVal_EndList;
6386 if (!insideLI(this))
6388 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </li> tag without matching <li>");
6392 // ignore </li> tags
6395 case HTML_BLOCKQUOTE:
6396 retval=RetVal_EndBlockQuote;
6399 // if (!insidePRE(this))
6401 // warn_doc_error(g_fileName,doctokenizerYYlineno,"found </pre> tag without matching <pre>");
6405 // retval=RetVal_EndPre;
6409 handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
6412 handleStyleLeave(this,m_children,DocStyleChange::Strike,"strike");
6414 case HTML_UNDERLINE:
6415 handleStyleLeave(this,m_children,DocStyleChange::Underline,"u");
6418 handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
6421 handleStyleLeave(this,m_children,DocStyleChange::Italic,"em");
6424 handleStyleLeave(this,m_children,DocStyleChange::Div,"div");
6427 handleStyleLeave(this,m_children,DocStyleChange::Span,"span");
6430 handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub");
6433 handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup");
6436 handleStyleLeave(this,m_children,DocStyleChange::Center,"center");
6439 handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
6442 handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
6443 setInsidePreformatted(FALSE);
6444 doctokenizerYYsetInsidePre(FALSE);
6450 retval=RetVal_EndDesc;
6459 retval=RetVal_EndTable;
6471 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </caption> found");
6474 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal </br> tag found\n");
6477 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h1> found");
6480 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h2> found");
6483 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h3> found");
6486 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h4> found");
6489 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h5> found");
6492 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h6> found");
6495 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </img> found");
6498 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </hr> found");
6501 //warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </a> found");
6502 // ignore </a> tag (can be part of <a name=...></a>
6506 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
6520 case XML_INHERITDOC:
6521 retval = RetVal_CloseXml;
6524 handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
6527 case XML_LISTHEADER:
6529 case XML_PERMISSION:
6530 case XML_DESCRIPTION:
6532 case XML_TYPEPARAMREF:
6533 // These tags are defined in .Net but are currently unsupported
6536 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported xml/html tag </%s> found", qPrint(tagName));
6537 m_children.append(new DocWord(this,"</"+tagName+">"));
6540 // we should not get here!
6541 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",qPrint(tagName));
6548 int DocPara::parse()
6550 DBG(("DocPara::parse() start\n"));
6551 g_nodeStack.push(this);
6552 // handle style commands "inherited" from the previous paragraph
6553 handleInitialStyleCommands(this,m_children);
6556 while ((tok=doctokenizerYYlex())) // get the next token
6559 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
6560 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
6561 tok==TK_COMMAND_AT || tok == TK_COMMAND_BS || tok==TK_HTMLTAG
6564 DBG((" name=%s",qPrint(g_token->name)));
6570 m_children.append(new DocWord(this,g_token->name));
6573 handleLinkedWord(this,m_children);
6576 m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr));
6580 // prevent leading whitespace and collapse multiple whitespace areas
6582 if (insidePRE(this) || // all whitespace is relevant
6584 // remove leading whitespace
6585 !m_children.isEmpty() &&
6586 // and whitespace after certain constructs
6587 (k=m_children.getLast()->kind())!=DocNode::Kind_HtmlDescList &&
6588 k!=DocNode::Kind_HtmlTable &&
6589 k!=DocNode::Kind_HtmlList &&
6590 k!=DocNode::Kind_SimpleSect &&
6591 k!=DocNode::Kind_AutoList &&
6592 k!=DocNode::Kind_SimpleList &&
6593 /*k!=DocNode::Kind_Verbatim &&*/
6594 k!=DocNode::Kind_HtmlHeader &&
6595 k!=DocNode::Kind_HtmlBlockQuote &&
6596 k!=DocNode::Kind_ParamSect &&
6597 k!=DocNode::Kind_XRefItem
6601 m_children.append(new DocWhiteSpace(this,g_token->chars));
6607 DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind()));
6608 DocNode *n=parent();
6609 while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent();
6610 if (n) // we found an auto list up in the hierarchy
6612 DocAutoList *al = (DocAutoList *)n;
6613 DBG(("previous list item at %d\n",al->indent()));
6614 if (al->indent()>=g_token->indent)
6615 // new item at the same or lower indent level
6622 // determine list depth
6627 if (n->kind() == DocNode::Kind_AutoList &&
6628 ((DocAutoList*)n)->isEnumList()) depth++;
6632 // first item or sub list => create new list
6636 al = new DocAutoList(this,g_token->indent,
6637 g_token->isEnumList,depth);
6638 m_children.append(al);
6639 retval = al->parse();
6640 } while (retval==TK_LISTITEM && // new list
6641 al->indent()==g_token->indent // at same indent level
6644 // check the return value
6645 if (retval==RetVal_SimpleSec) // auto list ended due to simple section command
6647 // Reparse the token that ended the section at this level,
6648 // so a new simple section will be started at this level.
6649 // This is the same as unputting the last read token and continuing.
6650 g_token->name = g_token->simpleSectName;
6651 if (g_token->name.left(4)=="rcs:") // RCS section
6653 g_token->name = g_token->name.mid(4);
6654 g_token->text = g_token->simpleSectText;
6657 else // other section
6659 tok = TK_COMMAND_BS;
6661 DBG(("reparsing command %s\n",qPrint(g_token->name)));
6664 else if (retval==TK_ENDLIST)
6666 if (al->indent()>g_token->indent) // end list
6670 else // continue with current paragraph
6674 else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF
6681 DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno));
6682 if (parent()->kind()==DocNode::Kind_AutoListItem)
6684 ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList);
6685 DocAutoList *al = (DocAutoList *)parent()->parent();
6686 if (al->indent()>=g_token->indent)
6688 // end of list marker ends this paragraph
6694 warn_doc_error(g_fileName,doctokenizerYYlineno,"End of list marker found "
6695 "has invalid indent level");
6700 warn_doc_error(g_fileName,doctokenizerYYlineno,"End of list marker found without any preceding "
6708 // see if we have to start a simple section
6709 int cmd = Mappers::cmdMapper->map(g_token->name);
6710 DocNode *n=parent();
6712 n->kind()!=DocNode::Kind_SimpleSect &&
6713 n->kind()!=DocNode::Kind_ParamSect
6718 if (cmd&SIMPLESECT_BIT)
6720 if (n) // already in a simple section
6722 // simple section cannot start in this paragraph, need
6723 // to unwind the stack and remember the command.
6724 g_token->simpleSectName = g_token->name.copy();
6725 retval=RetVal_SimpleSec;
6729 // see if we are in a simple list
6731 while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent();
6736 retval=RetVal_ListItem;
6741 // handle the command
6742 retval=handleCommand(g_token->name,tok);
6743 DBG(("handleCommand returns %x\n",retval));
6745 // check the return value
6746 if (retval==RetVal_SimpleSec)
6748 // Reparse the token that ended the section at this level,
6749 // so a new simple section will be started at this level.
6750 // This is the same as unputting the last read token and continuing.
6751 g_token->name = g_token->simpleSectName;
6752 if (g_token->name.left(4)=="rcs:") // RCS section
6754 g_token->name = g_token->name.mid(4);
6755 g_token->text = g_token->simpleSectText;
6758 else // other section
6760 tok = TK_COMMAND_BS;
6762 DBG(("reparsing command %s\n",qPrint(g_token->name)));
6765 else if (retval==RetVal_OK)
6767 // the command ended normally, keep scanning for new tokens.
6770 else if (retval>0 && retval<RetVal_OK)
6772 // the command ended with a new command, reparse this token
6776 else // end of file, end of paragraph, start or end of section
6777 // or some auto list marker
6785 if (!g_token->endTag) // found a start tag
6787 retval = handleHtmlStartTag(g_token->name,g_token->attribs);
6789 else // found an end tag
6791 retval = handleHtmlEndTag(g_token->name);
6793 if (retval==RetVal_OK)
6795 // the command ended normally, keep scanner for new tokens.
6806 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name);
6807 if (s!=DocSymbol::Sym_Unknown)
6809 m_children.append(new DocSymbol(this,s));
6813 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
6814 qPrint(g_token->name));
6823 DocNode *n=parent();
6825 n->kind()!=DocNode::Kind_SimpleSect &&
6826 n->kind()!=DocNode::Kind_ParamSect
6831 if (n) // already in a simple section
6833 // simple section cannot start in this paragraph, need
6834 // to unwind the stack and remember the command.
6835 g_token->simpleSectName = "rcs:"+g_token->name;
6836 g_token->simpleSectText = g_token->text;
6837 retval=RetVal_SimpleSec;
6841 // see if we are in a simple list
6842 DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs);
6843 m_children.append(ss);
6848 warn_doc_error(g_fileName,doctokenizerYYlineno,
6849 "Found unexpected token (id=%x)\n",tok);
6855 handlePendingStyleCommands(this,m_children);
6856 DocNode *n = g_nodeStack.pop();
6858 DBG(("DocPara::parse() end retval=%x\n",retval));
6859 INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM ||
6860 retval==TK_ENDLIST || retval>RetVal_OK
6866 //--------------------------------------------------------------------------
6868 int DocSection::parse()
6870 DBG(("DocSection::parse() start %s level=%d\n",qPrint(g_token->sectionId),m_level));
6871 int retval=RetVal_OK;
6872 g_nodeStack.push(this);
6875 if (!m_id.isEmpty())
6877 sec=Doxygen::sectionDict->find(m_id);
6880 m_file = sec->fileName;
6881 m_anchor = sec->label;
6882 m_title = sec->title;
6883 if (m_title.isEmpty()) m_title = sec->label;
6884 if (g_sectionDict && g_sectionDict->find(m_id)==0)
6886 g_sectionDict->append(m_id,sec);
6891 // first parse any number of paragraphs
6896 DocPara *par = new DocPara(this);
6897 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6898 retval=par->parse();
6899 if (!par->isEmpty())
6901 m_children.append(par);
6908 if (retval==TK_LISTITEM)
6910 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
6912 if (retval==RetVal_Internal)
6914 DocInternal *in = new DocInternal(this);
6915 m_children.append(in);
6916 retval = in->parse(m_level+1);
6917 if (retval==RetVal_EndInternal)
6922 } while (retval!=0 &&
6923 retval!=RetVal_Section &&
6924 retval!=RetVal_Subsection &&
6925 retval!=RetVal_Subsubsection &&
6926 retval!=RetVal_Paragraph &&
6927 retval!=RetVal_EndInternal
6930 if (lastPar) lastPar->markLast();
6932 //printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel);
6934 if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1)
6936 // then parse any number of nested sections
6937 while (retval==RetVal_Subsection) // more sections follow
6939 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6940 DocSection *s=new DocSection(this,
6941 QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6942 m_children.append(s);
6943 retval = s->parse();
6946 else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2)
6948 // then parse any number of nested sections
6949 while (retval==RetVal_Subsubsection) // more sections follow
6951 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6952 DocSection *s=new DocSection(this,
6953 QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6954 m_children.append(s);
6955 retval = s->parse();
6958 else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3))
6960 // then parse any number of nested sections
6961 while (retval==RetVal_Paragraph) // more sections follow
6963 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6964 DocSection *s=new DocSection(this,
6965 QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6966 m_children.append(s);
6967 retval = s->parse();
6970 else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) ||
6971 (m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph)
6974 int level = (retval==RetVal_Subsubsection) ? 3 : 4;
6975 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected %s "
6976 "command found inside %s!",
6977 sectionLevelToName[level],sectionLevelToName[m_level]);
6978 retval=0; // stop parsing
6984 INTERNAL_ASSERT(retval==0 ||
6985 retval==RetVal_Section ||
6986 retval==RetVal_Subsection ||
6987 retval==RetVal_Subsubsection ||
6988 retval==RetVal_Paragraph ||
6989 retval==RetVal_Internal ||
6990 retval==RetVal_EndInternal
6993 DBG(("DocSection::parse() end: retval=%x\n",retval));
6994 DocNode *n = g_nodeStack.pop();
6999 //--------------------------------------------------------------------------
7001 void DocText::parse()
7003 DBG(("DocText::parse() start\n"));
7004 g_nodeStack.push(this);
7005 doctokenizerYYsetStateText();
7008 while ((tok=doctokenizerYYlex())) // get the next token
7013 m_children.append(new DocWord(this,g_token->name));
7016 m_children.append(new DocWhiteSpace(this,g_token->chars));
7020 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name);
7021 if (s!=DocSymbol::Sym_Unknown)
7023 m_children.append(new DocSymbol(this,s));
7027 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
7028 qPrint(g_token->name));
7035 switch (Mappers::cmdMapper->map(g_token->name))
7038 m_children.append(new DocSymbol(this,DocSymbol::Sym_BSlash));
7041 m_children.append(new DocSymbol(this,DocSymbol::Sym_At));
7044 m_children.append(new DocSymbol(this,DocSymbol::Sym_Less));
7047 m_children.append(new DocSymbol(this,DocSymbol::Sym_Greater));
7050 m_children.append(new DocSymbol(this,DocSymbol::Sym_Amp));
7053 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dollar));
7056 m_children.append(new DocSymbol(this,DocSymbol::Sym_Hash));
7059 m_children.append(new DocSymbol(this,DocSymbol::Sym_DoubleColon));
7062 m_children.append(new DocSymbol(this,DocSymbol::Sym_Percent));
7065 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
7066 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
7069 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
7070 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
7071 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
7074 m_children.append(new DocSymbol(this,DocSymbol::Sym_Quot));
7077 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dot));
7080 m_children.append(new DocSymbol(this,DocSymbol::Sym_Plus));
7083 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
7086 m_children.append(new DocSymbol(this,DocSymbol::Sym_Equal));
7089 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command `%s' found",
7090 qPrint(g_token->name));
7095 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
7101 handleUnclosedStyleCommands();
7103 DocNode *n = g_nodeStack.pop();
7105 DBG(("DocText::parse() end\n"));
7109 //--------------------------------------------------------------------------
7111 void DocRoot::parse()
7113 DBG(("DocRoot::parse() start\n"));
7114 g_nodeStack.push(this);
7115 doctokenizerYYsetStatePara();
7118 // first parse any number of paragraphs
7123 DocPara *par = new DocPara(this);
7124 if (isFirst) { par->markFirst(); isFirst=FALSE; }
7125 retval=par->parse();
7126 if (!par->isEmpty())
7128 m_children.append(par);
7135 if (retval==TK_LISTITEM)
7137 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
7139 else if (retval==RetVal_Subsection)
7141 warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsection command outside of section context!");
7143 else if (retval==RetVal_Subsubsection)
7145 warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsubsection command outside of subsection context!");
7147 else if (retval==RetVal_Paragraph)
7149 warn_doc_error(g_fileName,doctokenizerYYlineno,"found paragraph command outside of subsubsection context!");
7151 if (retval==RetVal_Internal)
7153 DocInternal *in = new DocInternal(this);
7154 m_children.append(in);
7155 retval = in->parse(1);
7157 } while (retval!=0 && retval!=RetVal_Section);
7158 if (lastPar) lastPar->markLast();
7160 //printf("DocRoot::parse() retval=%d %d\n",retval,RetVal_Section);
7161 // then parse any number of level1 sections
7162 while (retval==RetVal_Section)
7164 SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
7167 DocSection *s=new DocSection(this,
7168 QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
7169 m_children.append(s);
7170 retval = s->parse();
7174 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid section id `%s'; ignoring section",qPrint(g_token->sectionId));
7179 handleUnclosedStyleCommands();
7181 DocNode *n = g_nodeStack.pop();
7183 DBG(("DocRoot::parse() end\n"));
7186 static QCString extractCopyDocId(const char *data, uint &j, uint len)
7191 bool insideDQuote=FALSE;
7192 bool insideSQuote=FALSE;
7194 while (j<len && !found)
7196 if (!insideSQuote && !insideDQuote)
7200 case '(': round++; break;
7201 case ')': round--; break;
7202 case '"': insideDQuote=TRUE; break;
7203 case '\'': insideSQuote=TRUE; break;
7204 case ' ': // fall through
7205 case '\t': // fall through
7211 else if (insideSQuote) // look for single quote end
7213 if (data[j]=='\'' && (j==0 || data[j]!='\\'))
7218 else if (insideDQuote) // look for double quote end
7220 if (data[j]=='"' && (j==0 || data[j]!='\\'))
7227 if (qstrncmp(data+j," const",6)==0)
7231 else if (qstrncmp(data+j," volatile",9)==0)
7237 if (e>s) memcpy(id.rawData(),data+s,e-s);
7239 //printf("extractCopyDocId='%s' input='%s'\n",id.data(),&data[s]);
7243 // macro to check if the input starts with a specific command.
7244 // note that data[i] should point to the start of the command (\ or @ character)
7245 // and the sizeof(str) returns the size of str including the '\0' terminator;
7246 // a fact we abuse to skip over the start of the command character.
7247 #define CHECK_FOR_COMMAND(str,action) \
7248 do if ((i+sizeof(str)<len) && qstrncmp(data+i+1,str,sizeof(str)-1)==0) \
7249 { j=i+sizeof(str); action; } while(0)
7251 static uint isCopyBriefOrDetailsCmd(const char *data, uint i,uint len,bool &brief)
7254 if (i==0 || (data[i-1]!='@' && data[i-1]!='\\')) // not an escaped command
7256 CHECK_FOR_COMMAND("copybrief",brief=TRUE); // @copybrief or \copybrief
7257 CHECK_FOR_COMMAND("copydetails",brief=FALSE); // @copydetails or \copydetails
7262 static uint isVerbatimSection(const char *data,uint i,uint len,QCString &endMarker)
7265 if (i==0 || (data[i-1]!='@' && data[i-1]!='\\')) // not an escaped command
7267 CHECK_FOR_COMMAND("dot",endMarker="enddot");
7268 CHECK_FOR_COMMAND("code",endMarker="endcode");
7269 CHECK_FOR_COMMAND("msc",endMarker="endmsc");
7270 CHECK_FOR_COMMAND("verbatim",endMarker="endverbatim");
7271 CHECK_FOR_COMMAND("latexonly",endMarker="endlatexonly");
7272 CHECK_FOR_COMMAND("htmlonly",endMarker="endhtmlonly");
7273 CHECK_FOR_COMMAND("xmlonly",endMarker="endxmlonly");
7274 CHECK_FOR_COMMAND("rtfonly",endMarker="endrtfonly");
7275 CHECK_FOR_COMMAND("manonly",endMarker="endmanonly");
7276 CHECK_FOR_COMMAND("docbookonly",endMarker="enddocbookonly");
7277 CHECK_FOR_COMMAND("startuml",endMarker="enduml");
7279 //printf("isVerbatimSection(%s)=%d)\n",QCString(&data[i]).left(10).data(),j);
7283 static uint skipToEndMarker(const char *data,uint i,uint len,const QCString &endMarker)
7287 if ((data[i]=='@' || data[i]=='\\') && // start of command character
7288 (i==0 || (data[i-1]!='@' && data[i-1]!='\\'))) // that is not escaped
7290 if (i+endMarker.length()+1<=len && qstrncmp(data+i+1,endMarker,endMarker.length())==0)
7292 return i+endMarker.length()+1;
7297 // oops no endmarker found...
7298 return i<len ? i+1 : len;
7301 static QCString processCopyDoc(const char *data,uint &len)
7303 //printf("processCopyDoc start '%s'\n",data);
7309 if (c=='@' || c=='\\') // look for a command
7312 uint j=isCopyBriefOrDetailsCmd(data,i,len,isBrief);
7316 while (j<len && (data[j]==' ' || data[j]=='\t')) j++;
7317 // extract the argument
7318 QCString id = extractCopyDocId(data,j,len);
7321 //printf("resolving docs='%s'\n",id.data());
7322 if (findDocsForMemberOrCompound(id,&doc,&brief,&def))
7324 //printf("found it def=%p brief='%s' doc='%s' isBrief=%d\n",def,brief.data(),doc.data(),isBrief);
7325 if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
7327 g_copyStack.append(def);
7330 uint l=brief.length();
7331 buf.addStr(processCopyDoc(brief,l));
7335 uint l=doc.length();
7336 buf.addStr(processCopyDoc(doc,l));
7338 g_copyStack.remove(def);
7342 warn_doc_error(g_fileName,doctokenizerYYlineno,
7343 "Found recursive @copy%s or @copydoc relation for argument '%s'.\n",
7344 isBrief?"brief":"details",id.data());
7349 warn_doc_error(g_fileName,doctokenizerYYlineno,
7350 "@copy%s or @copydoc target '%s' not found", isBrief?"brief":"details",
7353 // skip over command
7359 uint k = isVerbatimSection(data,i,len,endMarker);
7363 i=skipToEndMarker(data,k,len,endMarker);
7364 buf.addStr(data+orgPos,i-orgPos);
7373 else // not a command, just copy
7383 //---------------------------------------------------------------------------
7384 QString::Direction getTextDirByConfig(const QString &text)
7386 QCString configDir = Config_getEnum(OUTPUT_TEXT_DIRECTION);
7387 if (configDir == "None")
7388 return QString::DirNeutral;
7389 if (configDir == "Context")
7390 return text.basicDirection();
7391 if (configDir == "LTR")
7393 QString::Direction textDir = text.direction();
7394 if (textDir == QString::DirMixed)
7395 return QString::DirLTR;
7398 if (configDir == "RTL")
7400 QString::Direction textDir = text.direction();
7401 if (textDir == QString::DirMixed)
7402 return QString::DirRTL;
7405 return QString::DirNeutral;
7408 QString::Direction getTextDirByConfig(const DocNode *node)
7410 QCString configDir = Config_getEnum(OUTPUT_TEXT_DIRECTION);
7411 if (configDir == "None")
7412 return QString::DirNeutral;
7413 if (configDir == "Context")
7414 return node->getTextBasicDir();
7415 if (configDir == "LTR")
7417 QString::Direction textDir = node->getTextDir();
7418 if (textDir == QString::DirMixed)
7419 return QString::DirLTR;
7422 if (configDir == "RTL")
7424 QString::Direction textDir = node->getTextDir();
7425 if (textDir == QString::DirMixed)
7426 return QString::DirRTL;
7429 return QString::DirNeutral;
7432 QString::Direction getTextDirByConfig(const DocPara *para, int nodeIndex)
7434 QCString configDir = Config_getEnum(OUTPUT_TEXT_DIRECTION);
7435 if (configDir == "None")
7436 return QString::DirNeutral;
7437 if (configDir == "Context")
7438 return para->getTextBasicDir(nodeIndex);
7439 if (configDir == "LTR")
7441 QString::Direction textDir = para->getTextDir(nodeIndex);
7442 if (textDir == QString::DirMixed)
7443 return QString::DirLTR;
7446 if (configDir == "RTL")
7448 QString::Direction textDir = para->getTextDir(nodeIndex);
7449 if (textDir == QString::DirMixed)
7450 return QString::DirRTL;
7453 return QString::DirNeutral;
7456 QCString getDirHtmlClassOfNode(QString::Direction textDir, const QCString &initValue)
7458 QCString classFromDir;
7459 if (textDir == QString::DirLTR)
7460 classFromDir = "DocNodeLTR";
7461 else if (textDir == QString::DirRTL)
7462 classFromDir = "DocNodeRTL";
7466 if (initValue && !classFromDir.isEmpty())
7467 return QCString(" class=\"") + initValue + " " + classFromDir + "\"";
7469 return QCString(" class=\"") + initValue + "\"";
7470 if (!classFromDir.isEmpty())
7471 return QCString(" class=\"") + classFromDir + "\"";
7475 QCString getDirHtmlClassOfPage(QCString pageTitle)
7477 QCString result = "";
7478 result += " class=\"PageDoc";
7479 QString::Direction titleDir = getTextDirByConfig(pageTitle);
7480 if (titleDir == QString::DirLTR)
7481 result += " PageDocLTR-title";
7482 else if (titleDir == QString::DirRTL)
7483 result += " PageDocRTL-title";
7488 QCString getHtmlDirEmbedingChar(QString::Direction textDir)
7490 if (textDir == QString::DirLTR)
7492 if (textDir == QString::DirRTL)
7497 QCString getJsDirEmbedingChar(QString::Direction textDir)
7499 if (textDir == QString::DirLTR)
7501 if (textDir == QString::DirRTL)
7505 //---------------------------------------------------------------------------
7507 DocRoot *validatingParseDoc(const char *fileName,int startLine,
7508 Definition *ctx,MemberDef *md,
7509 const char *input,bool indexWords,
7510 bool isExample, const char *exampleName,
7511 bool singleLine, bool linkFromIndex)
7513 //printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>",
7514 // md?md->name().data():"<none>",
7516 //printf("========== validating %s at line %d\n",fileName,startLine);
7517 //printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input);
7518 //g_token = new TokenInfo;
7520 // store parser state so we can re-enter this function if needed
7521 //bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN);
7522 docParserPushContext();
7524 if (ctx && ctx!=Doxygen::globalScope &&
7525 (ctx->definitionType()==Definition::TypeClass ||
7526 ctx->definitionType()==Definition::TypeNamespace
7530 g_context = ctx->name();
7532 else if (ctx && ctx->definitionType()==Definition::TypePage)
7534 Definition *scope = ((PageDef*)ctx)->getPageScope();
7535 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
7537 else if (ctx && ctx->definitionType()==Definition::TypeGroup)
7539 Definition *scope = ((GroupDef*)ctx)->getGroupScope();
7540 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
7548 if (indexWords && Doxygen::searchIndex)
7552 g_searchUrl=md->getOutputFileBase();
7553 Doxygen::searchIndex->setCurrentDoc(md,md->anchor(),FALSE);
7557 g_searchUrl=ctx->getOutputFileBase();
7558 Doxygen::searchIndex->setCurrentDoc(ctx,ctx->anchor(),FALSE);
7562 if (indexWords && md && Doxygen::searchIndex)
7564 g_searchUrl=md->getOutputFileBase();
7565 Doxygen::searchIndex->setCurrentDoc(
7566 (md->getLanguage()==SrcLangExt_Fortran ?
7567 theTranslator->trSubprogram(TRUE,TRUE):
7568 theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(),
7572 else if (indexWords && ctx && Doxygen::searchIndex)
7574 g_searchUrl=ctx->getOutputFileBase();
7575 QCString name = ctx->qualifiedName();
7577 SrcLangExt lang = ctx->getLanguage();
7578 QCString sep = getLanguageSpecificSeparator(lang);
7581 name = substitute(name,"::",sep);
7584 switch (ctx->definitionType())
7586 case Definition::TypePage:
7588 PageDef *pd = (PageDef *)ctx;
7589 if (!pd->title().isEmpty())
7591 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title();
7595 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name();
7599 case Definition::TypeClass:
7601 ClassDef *cd = (ClassDef *)ctx;
7602 name.prepend(cd->compoundTypeString()+" ");
7605 case Definition::TypeNamespace:
7607 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
7609 name = theTranslator->trPackage(name);
7611 else if (lang==SrcLangExt_Fortran)
7613 name.prepend(theTranslator->trModule(TRUE,TRUE)+" ");
7617 name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" ");
7621 case Definition::TypeGroup:
7623 GroupDef *gd = (GroupDef *)ctx;
7624 if (gd->groupTitle())
7626 name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle();
7630 name.prepend(theTranslator->trGroup(TRUE,TRUE)+" ");
7637 Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl);
7645 g_fileName = fileName;
7646 g_relPath = (!linkFromIndex && ctx) ?
7647 QCString(relativePathToRoot(ctx->getOutputFileBase())) :
7649 //printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data());
7651 g_nodeStack.clear();
7652 g_styleStack.clear();
7653 g_initialStyleStack.clear();
7654 g_inSeeBlock = FALSE;
7655 g_xmlComment = FALSE;
7656 g_insideHtmlLink = FALSE;
7657 g_includeFileText = "";
7658 g_includeFileOffset = 0;
7659 g_includeFileLength = 0;
7660 g_isExample = isExample;
7661 g_exampleName = exampleName;
7662 g_hasParamCommand = FALSE;
7663 g_hasReturnCommand = FALSE;
7664 g_paramsFound.setAutoDelete(FALSE);
7665 g_paramsFound.clear();
7666 g_sectionDict = 0; //sections;
7668 //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
7669 doctokenizerYYlineno=startLine;
7670 uint inpLen=qstrlen(input);
7671 QCString inpStr = processCopyDoc(input,inpLen);
7672 if (inpStr.isEmpty() || inpStr.at(inpStr.length()-1)!='\n')
7676 //printf("processCopyDoc(in='%s' out='%s')\n",input,inpStr.data());
7677 doctokenizerYYinit(inpStr,g_fileName);
7679 // build abstract syntax tree
7680 DocRoot *root = new DocRoot(md!=0,singleLine);
7684 if (Debug::isFlagSet(Debug::PrintTree))
7686 // pretty print the result
7687 PrintDocVisitor *v = new PrintDocVisitor;
7692 checkUnOrMultipleDocumentedParams();
7693 detectNoDocumentedParams();
7695 // TODO: These should be called at the end of the program.
7696 //doctokenizerYYcleanup();
7697 //Mappers::cmdMapper->freeInstance();
7698 //Mappers::htmlTagMapper->freeInstance();
7700 // restore original parser state
7701 docParserPopContext();
7703 //printf(">>>>>> end validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>",
7704 // md?md->name().data():"<none>");
7709 DocText *validatingParseText(const char *input)
7711 // store parser state so we can re-enter this function if needed
7712 docParserPushContext();
7714 //printf("------------ input ---------\n%s\n"
7715 // "------------ end input -----\n",input);
7716 //g_token = new TokenInfo;
7718 g_fileName = "<parseText>";
7721 g_nodeStack.clear();
7722 g_styleStack.clear();
7723 g_initialStyleStack.clear();
7724 g_inSeeBlock = FALSE;
7725 g_xmlComment = FALSE;
7726 g_insideHtmlLink = FALSE;
7727 g_includeFileText = "";
7728 g_includeFileOffset = 0;
7729 g_includeFileLength = 0;
7730 g_isExample = FALSE;
7732 g_hasParamCommand = FALSE;
7733 g_hasReturnCommand = FALSE;
7734 g_paramsFound.setAutoDelete(FALSE);
7735 g_paramsFound.clear();
7738 DocText *txt = new DocText;
7742 doctokenizerYYlineno=1;
7743 doctokenizerYYinit(input,g_fileName);
7745 // build abstract syntax tree
7748 if (Debug::isFlagSet(Debug::PrintTree))
7750 // pretty print the result
7751 PrintDocVisitor *v = new PrintDocVisitor;
7757 // restore original parser state
7758 docParserPopContext();
7762 void docFindSections(const char *input,
7765 const char *fileName)
7767 doctokenizerYYFindSections(input,d,mg,fileName);