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>
34 #include "docparser.h"
35 #include "doctokenizer.h"
36 #include "cmdmapper.h"
37 #include "printdocvisitor.h"
40 #include "searchindex.h"
44 #include "arguments.h"
45 #include "vhdldocgen.h"
47 #include "classlist.h"
49 #include "memberdef.h"
50 #include "namespacedef.h"
56 #include "htmlentity.h"
59 #define DBG(x) do {} while(0)
62 //#define DBG(x) printf x
65 //#define myprintf(x...) fprintf(stderr,x)
66 //#define DBG(x) myprintf x
68 #define INTERNAL_ASSERT(x) do {} while(0)
69 //#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__));
71 //---------------------------------------------------------------------------
73 static const char *sectionLevelToName[] =
83 //---------------------------------------------------------------------------
85 // Parser state: global variables during a call to validatingParseDoc
86 static Definition * g_scope;
87 static QCString g_context;
88 static bool g_inSeeBlock;
89 static bool g_xmlComment;
90 static bool g_insideHtmlLink;
91 static QStack<DocNode> g_nodeStack;
92 static QStack<DocStyleChange> g_styleStack;
93 static QStack<DocStyleChange> g_initialStyleStack;
94 static QList<Definition> g_copyStack;
95 static QCString g_fileName;
96 static QCString g_relPath;
98 static bool g_hasParamCommand;
99 static bool g_hasReturnCommand;
100 static QDict<void> g_paramsFound;
101 static MemberDef * g_memberDef;
102 static bool g_isExample;
103 static QCString g_exampleName;
104 static SectionDict * g_sectionDict;
105 static QCString g_searchUrl;
107 static QCString g_includeFileName;
108 static QCString g_includeFileText;
109 static uint g_includeFileOffset;
110 static uint g_includeFileLength;
113 /** Parser's context to store all global variables.
115 struct DocParserContext
122 QStack<DocNode> nodeStack;
123 QStack<DocStyleChange> styleStack;
124 QStack<DocStyleChange> initialStyleStack;
125 QList<Definition> copyStack;
130 bool hasParamCommand;
131 bool hasReturnCommand;
132 MemberDef * memberDef;
133 QDict<void> paramsFound;
135 QCString exampleName;
136 SectionDict *sectionDict;
139 QCString includeFileText;
140 uint includeFileOffset;
141 uint includeFileLength;
146 static QStack<DocParserContext> g_parserStack;
148 //---------------------------------------------------------------------------
149 static void docParserPushContext(bool saveParamInfo=TRUE)
152 //indent.fill(' ',g_parserStack.count()*2+2);
153 //printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count());
155 doctokenizerYYpushContext();
156 DocParserContext *ctx = new DocParserContext;
157 ctx->scope = g_scope;
158 ctx->context = g_context;
159 ctx->inSeeBlock = g_inSeeBlock;
160 ctx->xmlComment = g_xmlComment;
161 ctx->insideHtmlLink = g_insideHtmlLink;
162 ctx->nodeStack = g_nodeStack;
163 ctx->styleStack = g_styleStack;
164 ctx->initialStyleStack = g_initialStyleStack;
165 ctx->copyStack = g_copyStack;
166 ctx->fileName = g_fileName;
167 ctx->lineNo = doctokenizerYYlineno;
168 ctx->relPath = g_relPath;
172 ctx->hasParamCommand = g_hasParamCommand;
173 ctx->hasReturnCommand = g_hasReturnCommand;
174 ctx->paramsFound = g_paramsFound;
177 ctx->memberDef = g_memberDef;
178 ctx->isExample = g_isExample;
179 ctx->exampleName = g_exampleName;
180 ctx->sectionDict = g_sectionDict;
181 ctx->searchUrl = g_searchUrl;
183 ctx->includeFileText = g_includeFileText;
184 ctx->includeFileOffset = g_includeFileOffset;
185 ctx->includeFileLength = g_includeFileLength;
187 ctx->token = g_token;
188 g_token = new TokenInfo;
190 g_parserStack.push(ctx);
193 static void docParserPopContext(bool keepParamInfo=FALSE)
195 DocParserContext *ctx = g_parserStack.pop();
196 g_scope = ctx->scope;
197 g_context = ctx->context;
198 g_inSeeBlock = ctx->inSeeBlock;
199 g_xmlComment = ctx->xmlComment;
200 g_insideHtmlLink = ctx->insideHtmlLink;
201 g_nodeStack = ctx->nodeStack;
202 g_styleStack = ctx->styleStack;
203 g_initialStyleStack = ctx->initialStyleStack;
204 g_copyStack = ctx->copyStack;
205 g_fileName = ctx->fileName;
206 doctokenizerYYlineno = ctx->lineNo;
207 g_relPath = ctx->relPath;
211 g_hasParamCommand = ctx->hasParamCommand;
212 g_hasReturnCommand = ctx->hasReturnCommand;
213 g_paramsFound = ctx->paramsFound;
215 g_memberDef = ctx->memberDef;
216 g_isExample = ctx->isExample;
217 g_exampleName = ctx->exampleName;
218 g_sectionDict = ctx->sectionDict;
219 g_searchUrl = ctx->searchUrl;
221 g_includeFileText = ctx->includeFileText;
222 g_includeFileOffset = ctx->includeFileOffset;
223 g_includeFileLength = ctx->includeFileLength;
226 g_token = ctx->token;
229 doctokenizerYYpopContext();
232 //indent.fill(' ',g_parserStack.count()*2+2);
233 //printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count());
236 //---------------------------------------------------------------------------
238 // replaces { with < and } with > and also
239 // replaces > with < and > with > within string s
240 static void unescapeCRef(QCString &s)
243 char *p = tmp.rawData();
249 if (c=='{') c='<'; else if (c=='}') c='>';
254 tmp=substitute(tmp,"<","<");
255 tmp=substitute(tmp,">",">");
259 //---------------------------------------------------------------------------
261 /*! search for an image in the imageNameDict and if found
262 * copies the image to the output directory (which depends on the \a type
265 static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
270 //printf("Search for %s\n",fileName);
271 if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
273 QCString inputFile = fd->absFilePath();
274 QFile inImage(inputFile);
275 if (inImage.open(IO_ReadOnly))
279 if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1)
281 result = result.right(result.length()-i-1);
283 //printf("fileName=%s result=%s\n",fileName,result.data());
288 if (!Config_getBool(GENERATE_HTML)) return result;
289 outputDir = Config_getString(HTML_OUTPUT);
291 case DocImage::Latex:
292 if (!Config_getBool(GENERATE_LATEX)) return result;
293 outputDir = Config_getString(LATEX_OUTPUT);
295 case DocImage::DocBook:
296 if (!Config_getBool(GENERATE_DOCBOOK)) return result;
297 outputDir = Config_getString(DOCBOOK_OUTPUT);
300 if (!Config_getBool(GENERATE_RTF)) return result;
301 outputDir = Config_getString(RTF_OUTPUT);
304 QCString outputFile = outputDir+"/"+result;
305 QFileInfo outfi(outputFile);
306 if (outfi.isSymLink())
308 QFile::remove(outputFile);
309 warn_doc_error(g_fileName,doctokenizerYYlineno,
310 "destination of image %s is a symlink, replacing with image",
313 if (outputFile!=inputFile) // prevent copying to ourself
315 QFile outImage(outputFile.data());
316 if (outImage.open(IO_WriteOnly)) // copy the image
318 char *buffer = new char[inImage.size()];
319 inImage.readBlock(buffer,inImage.size());
320 outImage.writeBlock(buffer,inImage.size());
323 if (type==DocImage::Html) Doxygen::indexList->addImageFile(result);
327 warn_doc_error(g_fileName,doctokenizerYYlineno,
328 "could not write output image %s",qPrint(outputFile));
333 printf("Source & Destination are the same!\n");
338 warn_doc_error(g_fileName,doctokenizerYYlineno,
339 "could not open image %s",qPrint(fileName));
342 if (type==DocImage::Latex && Config_getBool(USE_PDFLATEX) &&
343 fd->name().right(4)==".eps"
345 { // we have an .eps image in pdflatex mode => convert it to a pdf.
346 QCString outputDir = Config_getString(LATEX_OUTPUT);
347 QCString baseName = fd->name().left(fd->name().length()-4);
348 QCString epstopdfArgs(4096);
349 epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"",
350 outputDir.data(), baseName.data(),
351 outputDir.data(), baseName.data());
352 portable_sysTimerStart();
353 if (portable_system("epstopdf",epstopdfArgs)!=0)
355 err("Problems running epstopdf. Check your TeX installation!\n");
357 portable_sysTimerStop();
364 text.sprintf("image file name %s is ambiguous.\n",qPrint(fileName));
365 text+="Possible candidates:\n";
366 text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
367 warn_doc_error(g_fileName,doctokenizerYYlineno,text);
372 if (result.left(5)!="http:" && result.left(6)!="https:")
374 warn_doc_error(g_fileName,doctokenizerYYlineno,
375 "image file %s is not found in IMAGE_PATH: "
376 "assuming external image.",qPrint(fileName)
383 /*! Collects the parameters found with \@param or \@retval commands
384 * in a global list g_paramsFound. If \a isParam is set to TRUE
385 * and the parameter is not an actual parameter of the current
386 * member g_memberDef, then a warning is raised (unless warnings
387 * are disabled altogether).
389 static void checkArgumentName(const QCString &name,bool isParam)
391 if (!Config_getBool(WARN_IF_DOC_ERROR)) return;
392 if (g_memberDef==0) return; // not a member
393 ArgumentList *al=g_memberDef->isDocsForDefinition() ?
394 g_memberDef->argumentList() :
395 g_memberDef->declArgumentList();
396 SrcLangExt lang = g_memberDef->getLanguage();
397 //printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition());
398 if (al==0) return; // no argument list
400 static QRegExp re("$?[a-zA-Z0-9_\\x80-\\xFF]+\\.*");
402 while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
404 QCString aName=name.mid(i,l);
405 if (lang==SrcLangExt_Fortran) aName=aName.lower();
406 //printf("aName=`%s'\n",aName.data());
407 ArgumentListIterator ali(*al);
410 for (ali.toFirst();(a=ali.current());++ali)
412 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
413 if (lang==SrcLangExt_Fortran) argName=argName.lower();
414 argName=argName.stripWhiteSpace();
415 //printf("argName=`%s' aName=%s\n",argName.data(),aName.data());
416 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
419 g_paramsFound.insert(aName,(void *)(0x8));
424 if (!found && isParam)
426 //printf("member type=%d\n",memberDef->memberType());
427 QCString scope=g_memberDef->getScopeString();
428 if (!scope.isEmpty()) scope+="::"; else scope="";
429 QCString inheritedFrom = "";
430 QCString docFile = g_memberDef->docFile();
431 int docLine = g_memberDef->docLine();
432 MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom();
433 if (inheritedMd) // documentation was inherited
435 inheritedFrom.sprintf(" inherited from member %s at line "
436 "%d in file %s",qPrint(inheritedMd->name()),
437 inheritedMd->docLine(),qPrint(inheritedMd->docFile()));
438 docFile = g_memberDef->getDefFileName();
439 docLine = g_memberDef->getDefLine();
442 QCString alStr = argListToString(al);
443 warn_doc_error(docFile,docLine,
444 "argument '%s' of command @param "
445 "is not found in the argument list of %s%s%s%s",
446 qPrint(aName), qPrint(scope), qPrint(g_memberDef->name()),
447 qPrint(alStr), qPrint(inheritedFrom));
453 /*! Checks if the parameters that have been specified using \@param are
454 * indeed all parameters.
455 * Must be called after checkArgumentName() has been called for each
458 static void checkUndocumentedParams()
460 if (g_memberDef && g_hasParamCommand && Config_getBool(WARN_IF_DOC_ERROR))
462 ArgumentList *al=g_memberDef->isDocsForDefinition() ?
463 g_memberDef->argumentList() :
464 g_memberDef->declArgumentList();
465 SrcLangExt lang = g_memberDef->getLanguage();
468 ArgumentListIterator ali(*al);
471 for (ali.toFirst();(a=ali.current());++ali)
473 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
474 if (lang==SrcLangExt_Fortran) argName = argName.lower();
475 argName=argName.stripWhiteSpace();
476 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
477 if (g_memberDef->getLanguage()==SrcLangExt_Python && (argName=="self" || argName=="cls"))
479 // allow undocumented self / cls parameter for Python
481 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty())
491 "The following parameters of "+
492 QCString(g_memberDef->qualifiedName()) +
493 QCString(argListToString(al)) +
494 " are not documented:\n";
495 for (ali.toFirst();(a=ali.current());++ali)
497 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
498 if (lang==SrcLangExt_Fortran) argName = argName.lower();
499 argName=argName.stripWhiteSpace();
500 if (g_memberDef->getLanguage()==SrcLangExt_Python && (argName=="self" || argName=="cls"))
502 // allow undocumented self / cls parameter for Python
504 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0)
514 errMsg+=" parameter '"+argName+"'";
517 warn_doc_error(g_memberDef->getDefFileName(),
518 g_memberDef->getDefLine(),
519 substitute(errMsg,"%","%%"));
525 /*! Check if a member has documentation for its parameter and or return
526 * type, if applicable. If found this will be stored in the member, this
527 * is needed as a member can have brief and detailed documentation, while
528 * only one of these needs to document the parameters.
530 static void detectNoDocumentedParams()
532 if (g_memberDef && Config_getBool(WARN_NO_PARAMDOC))
534 ArgumentList *al = g_memberDef->argumentList();
535 ArgumentList *declAl = g_memberDef->declArgumentList();
536 QCString returnType = g_memberDef->typeString();
537 bool isPython = g_memberDef->getLanguage()==SrcLangExt_Python;
539 if (!g_memberDef->hasDocumentedParams() &&
542 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
543 g_memberDef->setHasDocumentedParams(TRUE);
545 else if (!g_memberDef->hasDocumentedParams())
547 bool allDoc=TRUE; // no parameter => all parameters are documented
548 if ( // member has parameters
549 al!=0 && // but the member has a parameter list
550 al->count()>0 // with at least one parameter (that is not void)
553 ArgumentListIterator ali(*al);
556 // see if all parameters have documentation
557 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
559 if (!a->name.isEmpty() && a->type!="void" &&
560 !(isPython && (a->name=="self" || a->name=="cls"))
563 allDoc = !a->docs.isEmpty();
565 //printf("a->type=%s a->name=%s doc=%s\n",
566 // a->type.data(),a->name.data(),a->docs.data());
568 if (!allDoc && declAl!=0) // try declaration arguments as well
571 ArgumentListIterator ali(*declAl);
573 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
575 if (!a->name.isEmpty() && a->type!="void" &&
576 !(isPython && (a->name=="self" || a->name=="cls"))
579 allDoc = !a->docs.isEmpty();
581 //printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data());
587 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
588 g_memberDef->setHasDocumentedParams(TRUE);
591 //printf("Member %s hadDocumentedReturnType()=%d hasReturnCommand=%d\n",
592 // g_memberDef->name().data(),g_memberDef->hasDocumentedReturnType(),g_hasReturnCommand);
593 if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found
596 g_memberDef->setHasDocumentedReturnType(TRUE);
598 else if ( // see if return needs to documented
599 g_memberDef->hasDocumentedReturnType() ||
600 returnType.isEmpty() || // empty return type
601 returnType.find("void")!=-1 || // void return type
602 returnType.find("subroutine")!=-1 || // fortran subroutine
603 g_memberDef->isConstructor() || // a constructor
604 g_memberDef->isDestructor() // or destructor
607 g_memberDef->setHasDocumentedReturnType(TRUE);
609 else if ( // see if return type is documented in a function w/o return type
610 g_memberDef->hasDocumentedReturnType() &&
611 (returnType.isEmpty() || // empty return type
612 returnType.find("void")!=-1 || // void return type
613 returnType.find("subroutine")!=-1 || // fortran subroutine
614 g_memberDef->isConstructor() || // a constructor
615 g_memberDef->isDestructor() // or destructor
619 warn_doc_error(g_fileName,doctokenizerYYlineno,"documented empty return type");
625 //---------------------------------------------------------------------------
627 /*! Strips known html and tex extensions from \a text. */
628 static QCString stripKnownExtensions(const char *text)
630 QCString result=text;
631 if (result.right(4)==".tex")
633 result=result.left(result.length()-4);
635 else if (result.right(Doxygen::htmlFileExtension.length())==
636 QCString(Doxygen::htmlFileExtension))
638 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
644 //---------------------------------------------------------------------------
646 /*! Returns TRUE iff node n is a child of a preformatted node */
647 static bool insidePRE(DocNode *n)
651 if (n->isPreformatted()) return TRUE;
657 //---------------------------------------------------------------------------
659 /*! Returns TRUE iff node n is a child of a html list item node */
660 static bool insideLI(DocNode *n)
664 if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE;
670 //---------------------------------------------------------------------------
672 /*! Returns TRUE iff node n is a child of a unordered html list node */
673 static bool insideUL(DocNode *n)
677 if (n->kind()==DocNode::Kind_HtmlList &&
678 ((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE;
684 //---------------------------------------------------------------------------
686 /*! Returns TRUE iff node n is a child of a ordered html list node */
687 static bool insideOL(DocNode *n)
691 if (n->kind()==DocNode::Kind_HtmlList &&
692 ((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE;
698 //---------------------------------------------------------------------------
700 static bool insideTable(DocNode *n)
704 if (n->kind()==DocNode::Kind_HtmlTable) return TRUE;
710 //---------------------------------------------------------------------------
712 /*! Looks for a documentation block with name commandName in the current
713 * context (g_context). The resulting documentation string is
714 * put in pDoc, the definition in which the documentation was found is
716 * @retval TRUE if name was found.
717 * @retval FALSE if name was not found.
719 static bool findDocsForMemberOrCompound(const char *commandName,
724 //printf("findDocsForMemberOrCompound(%s)\n",commandName);
728 QCString cmdArg=substitute(commandName,"#","::");
729 int l=cmdArg.length();
730 if (l==0) return FALSE;
732 int funcStart=cmdArg.find('(');
739 // Check for the case of operator() and the like.
740 // beware of scenarios like operator()((foo)bar)
741 int secondParen = cmdArg.find('(', funcStart+1);
742 int leftParen = cmdArg.find(')', funcStart+1);
743 if (leftParen!=-1 && secondParen!=-1)
745 if (leftParen<secondParen)
747 funcStart=secondParen;
752 QCString name=removeRedundantWhiteSpace(cmdArg.left(funcStart));
753 QCString args=cmdArg.right(l-funcStart);
755 // try if the link is to a member
762 bool found = getDefs(
763 g_context.find('.')==-1?g_context.data():"", // `find('.') is a hack to detect files
765 args.isEmpty()?0:args.data(),
766 md,cd,fd,nd,gd,FALSE,0,TRUE);
767 //printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data());
770 *pDoc=md->documentation();
771 *pBrief=md->briefDescription();
777 int scopeOffset=g_context.length();
780 QCString fullName=cmdArg;
783 fullName.prepend(g_context.left(scopeOffset)+"::");
785 //printf("Trying fullName=`%s'\n",fullName.data());
787 // try class, namespace, group, page, file reference
788 cd = Doxygen::classSDict->find(fullName);
791 *pDoc=cd->documentation();
792 *pBrief=cd->briefDescription();
796 nd = Doxygen::namespaceSDict->find(fullName);
799 *pDoc=nd->documentation();
800 *pBrief=nd->briefDescription();
804 gd = Doxygen::groupSDict->find(cmdArg);
807 *pDoc=gd->documentation();
808 *pBrief=gd->briefDescription();
812 pd = Doxygen::pageSDict->find(cmdArg);
815 *pDoc=pd->documentation();
816 *pBrief=pd->briefDescription();
821 fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig);
822 if (fd && !ambig) // file
824 *pDoc=fd->documentation();
825 *pBrief=fd->briefDescription();
836 scopeOffset = g_context.findRev("::",scopeOffset-1);
837 if (scopeOffset==-1) scopeOffset=0;
839 } while (scopeOffset>=0);
844 //---------------------------------------------------------------------------
846 // forward declaration
847 static bool defaultHandleToken(DocNode *parent,int tok,
848 QList<DocNode> &children,bool
851 static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
852 const QCString &cmdName)
854 DBG(("handleStyleArgument(%s)\n",qPrint(cmdName)));
855 int tok=doctokenizerYYlex();
856 if (tok!=TK_WHITESPACE)
858 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
862 while ((tok=doctokenizerYYlex()) &&
863 tok!=TK_WHITESPACE &&
869 static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
870 if (tok==TK_WORD && g_token->name.length()==1 &&
871 g_token->name.find(specialChar)!=-1)
873 // special character that ends the markup command
876 if (!defaultHandleToken(parent,tok,children))
881 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command \\%s as the argument of a \\%s command",
882 qPrint(g_token->name),qPrint(cmdName));
885 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found while handling command %s",
886 qPrint(g_token->name),qPrint(cmdName));
889 if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
890 { // ignore </li> as the end of a style command
896 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s while handling command %s",
897 tokToString(tok),qPrint(cmdName));
903 DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(cmdName),tok));
904 return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
908 /*! Called when a style change starts. For instance a \<b\> command is
911 static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
912 DocStyleChange::Style s,const HtmlAttribList *attribs)
914 DBG(("HandleStyleEnter\n"));
915 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs);
917 g_styleStack.push(sc);
920 /*! Called when a style change ends. For instance a \</b\> command is
923 static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
924 DocStyleChange::Style s,const char *tagName)
926 DBG(("HandleStyleLeave\n"));
927 if (g_styleStack.isEmpty() || // no style change
928 g_styleStack.top()->style()!=s || // wrong style change
929 g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
932 if (g_styleStack.isEmpty())
934 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </%s> tag without matching <%s>",
935 qPrint(tagName),qPrint(tagName));
937 else if (g_styleStack.top()->style()!=s)
939 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </%s> tag while expecting </%s>",
940 qPrint(tagName),qPrint(g_styleStack.top()->styleString()));
944 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </%s> at different nesting level (%d) than expected (%d)",
945 qPrint(tagName),g_nodeStack.count(),g_styleStack.top()->position());
948 else // end the section
950 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE);
956 /*! Called at the end of a paragraph to close all open style changes
957 * (e.g. a <b> without a </b>). The closed styles are pushed onto a stack
958 * and entered again at the start of a new paragraph.
960 static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
962 if (!g_styleStack.isEmpty())
964 DocStyleChange *sc = g_styleStack.top();
965 while (sc && sc->position()>=g_nodeStack.count())
966 { // there are unclosed style modifiers in the paragraph
967 children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
968 g_initialStyleStack.push(sc);
970 sc = g_styleStack.top();
975 static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
978 while ((sc=g_initialStyleStack.pop()))
980 handleStyleEnter(parent,children,sc->style(),&sc->attribs());
984 static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
986 HtmlAttribListIterator li(tagHtmlAttribs);
989 int retval = RetVal_OK;
990 for (li.toFirst();(opt=li.current());++li,++index)
992 if (opt->name=="name") // <a name=label> tag
994 if (!opt->value.isEmpty())
996 DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE);
997 children.append(anc);
998 break; // stop looking for other tag attribs
1002 warn_doc_error(g_fileName,doctokenizerYYlineno,"found <a> tag with name option but without value!");
1005 else if (opt->name=="href") // <a href=url>..</a> tag
1008 HtmlAttribList attrList = tagHtmlAttribs;
1009 // and remove the href attribute
1010 bool result = attrList.remove(index);
1012 DocHRef *href = new DocHRef(parent,attrList,opt->value,g_relPath);
1013 children.append(href);
1014 g_insideHtmlLink=TRUE;
1015 retval = href->parse();
1016 g_insideHtmlLink=FALSE;
1019 else // unsupported option for tag a
1026 const char *DocStyleChange::styleString() const
1030 case DocStyleChange::Bold: return "b";
1031 case DocStyleChange::Italic: return "em";
1032 case DocStyleChange::Code: return "code";
1033 case DocStyleChange::Center: return "center";
1034 case DocStyleChange::Small: return "small";
1035 case DocStyleChange::Subscript: return "subscript";
1036 case DocStyleChange::Superscript: return "superscript";
1037 case DocStyleChange::Preformatted: return "pre";
1038 case DocStyleChange::Div: return "div";
1039 case DocStyleChange::Span: return "span";
1044 static void handleUnclosedStyleCommands()
1046 if (!g_initialStyleStack.isEmpty())
1048 DocStyleChange *sc = g_initialStyleStack.top();
1049 g_initialStyleStack.pop();
1050 handleUnclosedStyleCommands();
1051 warn_doc_error(g_fileName,doctokenizerYYlineno,
1052 "end of comment block while expecting "
1053 "command </%s>",qPrint(sc->styleString()));
1057 static void handleLinkedWord(DocNode *parent,QList<DocNode> &children,bool ignoreAutoLinkFlag=FALSE)
1059 QCString name = linkToText(SrcLangExt_Unknown,g_token->name,TRUE);
1060 static bool autolinkSupport = Config_getBool(AUTOLINK_SUPPORT);
1061 if (!autolinkSupport && !ignoreAutoLinkFlag) // no autolinking -> add as normal word
1063 children.append(new DocWord(parent,name));
1067 // ------- try to turn the word 'name' into a link
1069 Definition *compound=0;
1070 MemberDef *member=0;
1071 int len = g_token->name.length();
1074 FileDef *fd = findFileDef(Doxygen::inputNameDict,g_fileName,ambig);
1075 //printf("handleLinkedWord(%s) g_context=%s\n",g_token->name.data(),g_context.data());
1076 if (!g_insideHtmlLink &&
1077 (resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member,TRUE,fd,TRUE)
1078 || (!g_context.isEmpty() && // also try with global scope
1079 resolveRef("",g_token->name,g_inSeeBlock,&compound,&member,FALSE,0,TRUE))
1083 //printf("resolveRef %s = %p (linkable?=%d)\n",qPrint(g_token->name),member,member ? member->isLinkable() : FALSE);
1084 if (member && member->isLinkable()) // member link
1086 if (member->isObjCMethod())
1088 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
1089 name = member->objCMethodName(localLink,g_inSeeBlock);
1092 DocLinkedWord(parent,name,
1093 member->getReference(),
1094 member->getOutputFileBase(),
1096 member->briefDescriptionAsTooltip()
1100 else if (compound->isLinkable()) // compound link
1102 QCString anchor = compound->anchor();
1103 if (compound->definitionType()==Definition::TypeFile)
1107 else if (compound->definitionType()==Definition::TypeGroup)
1109 name=((GroupDef*)compound)->groupTitle();
1112 DocLinkedWord(parent,name,
1113 compound->getReference(),
1114 compound->getOutputFileBase(),
1116 compound->briefDescriptionAsTooltip()
1120 else if (compound->definitionType()==Definition::TypeFile &&
1121 ((FileDef*)compound)->generateSourceFile()
1122 ) // undocumented file that has source code we can link to
1125 DocLinkedWord(parent,g_token->name,
1126 compound->getReference(),
1127 compound->getSourceFileBase(),
1129 compound->briefDescriptionAsTooltip()
1133 else // not linkable
1135 children.append(new DocWord(parent,name));
1138 else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':')
1140 // special case, where matching Foo: fails to be an Obj-C reference,
1141 // but Foo itself might be linkable.
1142 g_token->name=g_token->name.left(len-1);
1143 handleLinkedWord(parent,children,ignoreAutoLinkFlag);
1144 children.append(new DocWord(parent,":"));
1146 else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p")))
1148 // special case 2, where the token name is not a class, but could
1149 // be a Obj-C protocol
1151 DocLinkedWord(parent,name,
1153 cd->getOutputFileBase(),
1155 cd->briefDescriptionAsTooltip()
1158 // else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-g")))
1160 // // special case 3, where the token name is not a class, but could
1161 // // be a C# generic
1162 // children.append(new
1163 // DocLinkedWord(parent,name,
1164 // cd->getReference(),
1165 // cd->getOutputFileBase(),
1167 // cd->briefDescriptionAsTooltip()
1170 else // normal non-linkable word
1172 if (g_token->name.left(1)=="#" || g_token->name.left(2)=="::")
1174 warn_doc_error(g_fileName,doctokenizerYYlineno,"explicit link request to '%s' could not be resolved",qPrint(name));
1175 children.append(new DocWord(parent,g_token->name));
1179 children.append(new DocWord(parent,name));
1184 static void handleParameterType(DocNode *parent,QList<DocNode> &children,const QCString ¶mTypes)
1186 QCString name = g_token->name;
1188 while ((i=paramTypes.find('|',p))!=-1)
1190 g_token->name = paramTypes.mid(p,i-p);
1191 handleLinkedWord(parent,children);
1194 g_token->name = paramTypes.mid(p);
1195 handleLinkedWord(parent,children);
1196 g_token->name = name;
1199 static DocInternalRef *handleInternalRef(DocNode *parent)
1201 //printf("CMD_INTERNALREF\n");
1202 int tok=doctokenizerYYlex();
1203 QCString tokenName = g_token->name;
1204 if (tok!=TK_WHITESPACE)
1206 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
1210 doctokenizerYYsetStateInternalRef();
1211 tok=doctokenizerYYlex(); // get the reference id
1212 if (tok!=TK_WORD && tok!=TK_LNKWORD)
1214 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
1215 tokToString(tok),qPrint(tokenName));
1218 return new DocInternalRef(parent,g_token->name);
1221 static DocAnchor *handleAnchor(DocNode *parent)
1223 int tok=doctokenizerYYlex();
1224 if (tok!=TK_WHITESPACE)
1226 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
1227 qPrint(g_token->name));
1230 doctokenizerYYsetStateAnchor();
1231 tok=doctokenizerYYlex();
1234 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
1235 "argument of command %s",qPrint(g_token->name));
1238 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
1240 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
1241 tokToString(tok),qPrint(g_token->name));
1244 doctokenizerYYsetStatePara();
1245 return new DocAnchor(parent,g_token->name,FALSE);
1249 /* Helper function that deals with the title, width, and height arguments of various commands.
1250 * @param[in] cmd Command id for which to extract caption and size info.
1251 * @param[in] parent Parent node, owner of the children list passed as
1252 * the third argument.
1253 * @param[in] children The list of child nodes to which the node representing
1254 * the token can be added.
1255 * @param[out] width the extracted width specifier
1256 * @param[out] height the extracted height specifier
1258 static void defaultHandleTitleAndSize(const int cmd, DocNode *parent, QList<DocNode> &children, QCString &width,QCString &height)
1260 g_nodeStack.push(parent);
1263 doctokenizerYYsetStateTitle();
1265 while ((tok=doctokenizerYYlex()))
1267 if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height="))
1269 // special case: no title, but we do have a size indicator
1272 if (!defaultHandleToken(parent,tok,children))
1277 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\%s",
1278 qPrint(g_token->name), Mappers::cmdMapper->find(cmd).data());
1281 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
1282 qPrint(g_token->name));
1285 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
1291 // parse size attributes
1294 tok=doctokenizerYYlex();
1296 while (tok==TK_WHITESPACE || tok==TK_WORD) // there are values following the title
1300 if (g_token->name=="width=" || g_token->name=="height=")
1302 doctokenizerYYsetStateTitleAttrValue();
1303 g_token->name = g_token->name.left(g_token->name.length()-1);
1306 if (g_token->name=="width")
1308 width = g_token->chars;
1310 else if (g_token->name=="height")
1312 height = g_token->chars;
1316 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unknown option '%s' after \\%s command, expected 'width' or 'height'",
1317 qPrint(g_token->name), Mappers::cmdMapper->find(cmd).data());
1322 tok=doctokenizerYYlex();
1324 doctokenizerYYsetStatePara();
1326 handlePendingStyleCommands(parent,children);
1327 DocNode *n=g_nodeStack.pop();
1331 /* Helper function that deals with the most common tokens allowed in
1332 * title like sections.
1333 * @param parent Parent node, owner of the children list passed as
1334 * the third argument.
1335 * @param tok The token to process.
1336 * @param children The list of child nodes to which the node representing
1337 * the token can be added.
1338 * @param handleWord Indicates if word token should be processed
1339 * @retval TRUE The token was handled.
1340 * @retval FALSE The token was not handled.
1342 static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool
1345 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
1346 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
1347 tok==TK_COMMAND || tok==TK_HTMLTAG
1350 DBG((" name=%s",qPrint(g_token->name)));
1354 QCString tokenName = g_token->name;
1358 switch (Mappers::cmdMapper->map(tokenName))
1361 children.append(new DocSymbol(parent,DocSymbol::Sym_BSlash));
1364 children.append(new DocSymbol(parent,DocSymbol::Sym_At));
1367 children.append(new DocSymbol(parent,DocSymbol::Sym_Less));
1370 children.append(new DocSymbol(parent,DocSymbol::Sym_Greater));
1373 children.append(new DocSymbol(parent,DocSymbol::Sym_Amp));
1376 children.append(new DocSymbol(parent,DocSymbol::Sym_Dollar));
1379 children.append(new DocSymbol(parent,DocSymbol::Sym_Hash));
1382 children.append(new DocSymbol(parent,DocSymbol::Sym_DoubleColon));
1385 children.append(new DocSymbol(parent,DocSymbol::Sym_Percent));
1388 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1389 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1392 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1393 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1394 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1397 children.append(new DocSymbol(parent,DocSymbol::Sym_Quot));
1400 children.append(new DocSymbol(parent,DocSymbol::Sym_Dot));
1403 children.append(new DocSymbol(parent,DocSymbol::Sym_Plus));
1406 children.append(new DocSymbol(parent,DocSymbol::Sym_Minus));
1410 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
1411 tok=handleStyleArgument(parent,children,tokenName);
1412 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
1413 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1414 if (tok==TK_NEWPARA) goto handlepara;
1415 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1417 DBG(("CMD_EMPHASIS: reparsing command %s\n",qPrint(g_token->name)));
1424 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
1425 tok=handleStyleArgument(parent,children,tokenName);
1426 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
1427 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1428 if (tok==TK_NEWPARA) goto handlepara;
1429 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1431 DBG(("CMD_BOLD: reparsing command %s\n",qPrint(g_token->name)));
1438 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE));
1439 tok=handleStyleArgument(parent,children,tokenName);
1440 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE));
1441 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1442 if (tok==TK_NEWPARA) goto handlepara;
1443 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1445 DBG(("CMD_CODE: reparsing command %s\n",qPrint(g_token->name)));
1452 doctokenizerYYsetStateHtmlOnly();
1453 tok = doctokenizerYYlex();
1454 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName,g_token->name=="block"));
1455 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"htmlonly section ended without end marker");
1456 doctokenizerYYsetStatePara();
1461 doctokenizerYYsetStateManOnly();
1462 tok = doctokenizerYYlex();
1463 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
1464 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"manonly section ended without end marker");
1465 doctokenizerYYsetStatePara();
1470 doctokenizerYYsetStateRtfOnly();
1471 tok = doctokenizerYYlex();
1472 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::RtfOnly,g_isExample,g_exampleName));
1473 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"rtfonly section ended without end marker");
1474 doctokenizerYYsetStatePara();
1479 doctokenizerYYsetStateLatexOnly();
1480 tok = doctokenizerYYlex();
1481 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
1482 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"latexonly section ended without end marker",doctokenizerYYlineno);
1483 doctokenizerYYsetStatePara();
1488 doctokenizerYYsetStateXmlOnly();
1489 tok = doctokenizerYYlex();
1490 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
1491 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"xmlonly section ended without end marker",doctokenizerYYlineno);
1492 doctokenizerYYsetStatePara();
1497 doctokenizerYYsetStateDbOnly();
1498 tok = doctokenizerYYlex();
1499 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::DocbookOnly,g_isExample,g_exampleName));
1500 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"docbookonly section ended without end marker",doctokenizerYYlineno);
1501 doctokenizerYYsetStatePara();
1506 DocFormula *form=new DocFormula(parent,g_token->id);
1507 children.append(form);
1512 DocAnchor *anchor = handleAnchor(parent);
1515 children.append(anchor);
1519 case CMD_INTERNALREF:
1521 DocInternalRef *ref = handleInternalRef(parent);
1524 children.append(ref);
1527 doctokenizerYYsetStatePara();
1533 doctokenizerYYsetStateSetScope();
1534 doctokenizerYYlex();
1535 scope = g_token->name;
1537 //printf("Found scope='%s'\n",scope.data());
1538 doctokenizerYYsetStatePara();
1547 switch (Mappers::htmlTagMapper->map(tokenName))
1550 warn_doc_error(g_fileName,doctokenizerYYlineno,"found <div> tag in heading\n");
1553 warn_doc_error(g_fileName,doctokenizerYYlineno,"found <pre> tag in heading\n");
1556 if (!g_token->endTag)
1558 handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs);
1562 handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
1567 if (!g_token->endTag)
1569 handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs);
1573 handleStyleLeave(parent,children,DocStyleChange::Code,tokenName);
1577 if (!g_token->endTag)
1579 handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs);
1583 handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName);
1587 if (!g_token->endTag)
1589 handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs);
1593 handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName);
1597 if (!g_token->endTag)
1599 handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs);
1603 handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName);
1607 if (!g_token->endTag)
1609 handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs);
1613 handleStyleLeave(parent,children,DocStyleChange::Center,tokenName);
1617 if (!g_token->endTag)
1619 handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs);
1623 handleStyleLeave(parent,children,DocStyleChange::Small,tokenName);
1634 DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName);
1635 if (s!=DocSymbol::Sym_Unknown)
1637 children.append(new DocSymbol(parent,s));
1648 if (insidePRE(parent) || !children.isEmpty())
1650 children.append(new DocWhiteSpace(parent,g_token->chars));
1656 handleLinkedWord(parent,children);
1664 children.append(new DocWord(parent,g_token->name));
1670 if (g_insideHtmlLink)
1672 children.append(new DocWord(parent,g_token->name));
1676 children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr));
1685 //---------------------------------------------------------------------------
1687 static void handleImg(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
1689 HtmlAttribListIterator li(tagHtmlAttribs);
1693 for (li.toFirst();(opt=li.current());++li,++index)
1695 //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
1696 if (opt->name=="src" && !opt->value.isEmpty())
1699 HtmlAttribList attrList = tagHtmlAttribs;
1700 // and remove the src attribute
1701 bool result = attrList.remove(index);
1703 DocImage *img = new DocImage(parent,attrList,opt->value,DocImage::Html,opt->value);
1704 children.append(img);
1710 warn_doc_error(g_fileName,doctokenizerYYlineno,"IMG tag does not have a SRC attribute!\n");
1714 //---------------------------------------------------------------------------
1716 DocSymbol::SymType DocSymbol::decodeSymbol(const QCString &symName)
1718 DBG(("decodeSymbol(%s)\n",qPrint(symName)));
1719 return HtmlEntityMapper::instance()->name2sym(symName);
1722 //---------------------------------------------------------------------------
1724 static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
1725 const QCString &doc)
1727 int retval = RetVal_OK;
1729 if (doc.isEmpty()) return retval;
1731 doctokenizerYYinit(doc,g_fileName);
1733 // first parse any number of paragraphs
1736 if (!children.isEmpty() && children.getLast()->kind()==DocNode::Kind_Para)
1737 { // last child item was a paragraph
1738 lastPar = (DocPara*)children.getLast();
1743 DocPara *par = new DocPara(parent);
1744 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1745 retval=par->parse();
1746 if (!par->isEmpty())
1748 children.append(par);
1749 if (lastPar) lastPar->markLast(FALSE);
1756 } while (retval==TK_NEWPARA);
1757 if (lastPar) lastPar->markLast();
1759 //printf("internalValidateParsingDoc: %p: isFirst=%d isLast=%d\n",
1760 // lastPar,lastPar?lastPar->isFirst():-1,lastPar?lastPar->isLast():-1);
1765 //---------------------------------------------------------------------------
1767 static void readTextFileByName(const QCString &file,QCString &text)
1769 if (portable_isAbsolutePath(file.data()))
1774 text = fileToString(file,Config_getBool(FILTER_SOURCE_FILES));
1778 QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
1779 char *s=examplePathList.first();
1782 QCString absFileName = QCString(s)+portable_pathSeparator()+file;
1783 QFileInfo fi(absFileName);
1786 text = fileToString(absFileName,Config_getBool(FILTER_SOURCE_FILES));
1789 s=examplePathList.next();
1792 // as a fallback we also look in the exampleNameDict
1795 if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
1797 text = fileToString(fd->absFilePath(),Config_getBool(FILTER_SOURCE_FILES));
1801 warn_doc_error(g_fileName,doctokenizerYYlineno,"included file name %s is ambiguous"
1802 "Possible candidates:\n%s",qPrint(file),
1803 qPrint(showFileDefMatches(Doxygen::exampleNameDict,file))
1808 warn_doc_error(g_fileName,doctokenizerYYlineno,"included file %s is not found. "
1809 "Check your EXAMPLE_PATH",qPrint(file));
1813 //---------------------------------------------------------------------------
1815 DocWord::DocWord(DocNode *parent,const QCString &word) :
1819 //printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
1820 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1822 Doxygen::searchIndex->addWord(word,FALSE);
1826 //---------------------------------------------------------------------------
1828 DocLinkedWord::DocLinkedWord(DocNode *parent,const QCString &word,
1829 const QCString &ref,const QCString &file,
1830 const QCString &anchor,const QCString &tooltip) :
1831 m_word(word), m_ref(ref),
1832 m_file(file), m_relPath(g_relPath), m_anchor(anchor),
1836 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
1837 // word.data(),g_searchUrl.data(),tooltip.data());
1838 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1840 Doxygen::searchIndex->addWord(word,FALSE);
1844 //---------------------------------------------------------------------------
1846 DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
1851 warn_doc_error(g_fileName,doctokenizerYYlineno,"Empty anchor label");
1853 if (newAnchor) // found <a name="label">
1857 else if (id.left(CiteConsts::anchorPrefix.length()) == CiteConsts::anchorPrefix)
1859 CiteInfo *cite = Doxygen::citeDict->find(id.mid(CiteConsts::anchorPrefix.length()));
1862 m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE);
1867 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid cite anchor id `%s'",qPrint(id));
1868 m_anchor = "invalid";
1872 else // found \anchor label
1874 SectionInfo *sec = Doxygen::sectionDict->find(id);
1877 //printf("Found anchor %s\n",id.data());
1878 m_file = sec->fileName;
1879 m_anchor = sec->label;
1880 if (g_sectionDict && g_sectionDict->find(id)==0)
1882 //printf("Inserting in dictionary!\n");
1883 g_sectionDict->append(id,sec);
1888 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid anchor id `%s'",qPrint(id));
1889 m_anchor = "invalid";
1895 //---------------------------------------------------------------------------
1897 DocVerbatim::DocVerbatim(DocNode *parent,const QCString &context,
1898 const QCString &text, Type t,bool isExample,
1899 const QCString &exampleFile,bool isBlock,const QCString &lang)
1900 : m_context(context), m_text(text), m_type(t),
1901 m_isExample(isExample), m_exampleFile(exampleFile),
1902 m_relPath(g_relPath), m_lang(lang), m_isBlock(isBlock)
1908 //---------------------------------------------------------------------------
1910 void DocInclude::parse()
1912 DBG(("DocInclude::parse(file=%s,text=%s)\n",qPrint(m_file),qPrint(m_text)));
1920 readTextFileByName(m_file,m_text);
1921 g_includeFileName = m_file;
1922 g_includeFileText = m_text;
1923 g_includeFileOffset = 0;
1924 g_includeFileLength = m_text.length();
1925 //printf("g_includeFile=<<%s>>\n",g_includeFileText.data());
1930 readTextFileByName(m_file,m_text);
1933 readTextFileByName(m_file,m_text);
1937 readTextFileByName(m_file,m_text);
1938 // check here for the existence of the blockId inside the file, so we
1939 // only generate the warning once.
1941 if (!m_blockId.isEmpty() && (count=m_text.contains(m_blockId.data()))!=2)
1943 warn_doc_error(g_fileName,doctokenizerYYlineno,"block marked with %s for \\snippet should appear twice in file %s, found it %d times\n",
1944 m_blockId.data(),m_file.data(),count);
1947 case DocInclude::SnippetDoc:
1948 case DocInclude::IncludeDoc:
1949 err("Internal inconsistency: found switch SnippetDoc / IncludeDoc in file: %s"
1950 "Please create a bug report\n",__FILE__);
1955 //---------------------------------------------------------------------------
1957 void DocIncOperator::parse()
1959 m_includeFileName = g_includeFileName;
1960 const char *p = g_includeFileText;
1961 uint l = g_includeFileLength;
1962 uint o = g_includeFileOffset;
1963 DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",qPrint(p),o,l));
1965 bool nonEmpty = FALSE;
1974 if (nonEmpty) break; // we have a pattern to match
1975 so=o+1; // no pattern, skip empty line
1977 else if (!isspace((uchar)c)) // no white space char
1983 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1985 m_text = g_includeFileText.mid(so,o-so);
1986 DBG(("DocIncOperator::parse() Line: %s\n",qPrint(m_text)));
1988 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1999 if (nonEmpty) break; // we have a pattern to match
2000 so=o+1; // no pattern, skip empty line
2002 else if (!isspace((uchar)c)) // no white space char
2008 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2010 m_text = g_includeFileText.mid(so,o-so);
2011 DBG(("DocIncOperator::parse() SkipLine: %s\n",qPrint(m_text)));
2014 o++; // skip new line
2016 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
2027 if (nonEmpty) break; // we have a pattern to match
2028 so=o+1; // no pattern, skip empty line
2030 else if (!isspace((uchar)c)) // no white space char
2036 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2040 o++; // skip new line
2042 g_includeFileOffset = so; // set pointer to start of new line
2054 if (nonEmpty) break; // we have a pattern to match
2055 so=o+1; // no pattern, skip empty line
2057 else if (!isspace((uchar)c)) // no white space char
2063 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
2065 m_text = g_includeFileText.mid(bo,o-bo);
2066 DBG(("DocIncOperator::parse() Until: %s\n",qPrint(m_text)));
2069 o++; // skip new line
2071 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
2076 //---------------------------------------------------------------------------
2078 void DocCopy::parse(QList<DocNode> &children)
2082 if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
2084 if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
2086 bool hasParamCommand = g_hasParamCommand;
2087 bool hasReturnCommand = g_hasReturnCommand;
2088 QDict<void> paramsFound = g_paramsFound;
2089 //printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2090 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2092 docParserPushContext(FALSE);
2094 if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
2096 if (def->getOuterScope()!=Doxygen::globalScope)
2098 g_context=def->getOuterScope()->name();
2101 else if (def!=Doxygen::globalScope)
2103 g_context=def->name();
2105 g_styleStack.clear();
2106 g_nodeStack.clear();
2107 g_paramsFound.clear();
2108 g_copyStack.append(def);
2109 // make sure the descriptions end with a newline, so the parser will correctly
2110 // handle them in all cases.
2111 //printf("doc='%s'\n",doc.data());
2112 //printf("brief='%s'\n",brief.data());
2116 internalValidatingParseDoc(m_parent,children,brief);
2118 //printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2119 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2120 hasParamCommand = hasParamCommand || g_hasParamCommand;
2121 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
2122 QDictIterator<void> it(g_paramsFound);
2124 for (;(item=it.current());++it)
2126 paramsFound.insert(it.currentKey(),it.current());
2132 internalValidatingParseDoc(m_parent,children,doc);
2134 //printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2135 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2136 hasParamCommand = hasParamCommand || g_hasParamCommand;
2137 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
2138 QDictIterator<void> it(g_paramsFound);
2140 for (;(item=it.current());++it)
2142 paramsFound.insert(it.currentKey(),it.current());
2145 g_copyStack.remove(def);
2146 ASSERT(g_styleStack.isEmpty());
2147 ASSERT(g_nodeStack.isEmpty());
2148 docParserPopContext(TRUE);
2150 g_hasParamCommand = hasParamCommand;
2151 g_hasReturnCommand = hasReturnCommand;
2152 g_paramsFound = paramsFound;
2154 //printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
2155 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
2157 else // oops, recursion
2159 warn_doc_error(g_fileName,doctokenizerYYlineno,"recursive call chain of \\copydoc commands detected at %d\n",
2160 doctokenizerYYlineno);
2165 warn_doc_error(g_fileName,doctokenizerYYlineno,"target %s of \\copydoc command not found",
2170 //---------------------------------------------------------------------------
2172 DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) :
2173 m_id(id), m_key(key), m_relPath(g_relPath)
2178 bool DocXRefItem::parse()
2180 RefList *refList = Doxygen::xrefLists->find(m_key);
2183 // either not a built-in list or the list is enabled
2184 (m_key!="todo" || Config_getBool(GENERATE_TODOLIST)) &&
2185 (m_key!="test" || Config_getBool(GENERATE_TESTLIST)) &&
2186 (m_key!="bug" || Config_getBool(GENERATE_BUGLIST)) &&
2187 (m_key!="deprecated" || Config_getBool(GENERATE_DEPRECATEDLIST))
2191 RefItem *item = refList->getRefItem(m_id);
2195 if (g_memberDef && g_memberDef->name().at(0)=='@')
2197 m_file = "@"; // can't cross reference anonymous enum
2202 m_file = refList->fileName();
2203 m_anchor = item->listAnchor;
2205 m_title = refList->sectionTitle();
2206 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
2207 // m_file.data(),m_anchor.data(),m_title.data());
2209 if (!item->text.isEmpty())
2211 docParserPushContext();
2212 internalValidatingParseDoc(this,m_children,item->text);
2213 docParserPopContext();
2221 //---------------------------------------------------------------------------
2223 DocFormula::DocFormula(DocNode *parent,int id) :
2224 m_relPath(g_relPath)
2228 formCmd.sprintf("\\form#%d",id);
2229 Formula *formula=Doxygen::formulaNameDict->find(formCmd);
2232 m_id = formula->getId();
2233 m_name.sprintf("form_%d",m_id);
2234 m_text = formula->getFormulaText();
2236 else // wrong \form#<n> command
2238 warn_doc_error(g_fileName,doctokenizerYYlineno,"Wrong formula id %d",id);
2243 //---------------------------------------------------------------------------
2245 //int DocLanguage::parse()
2248 // DBG(("DocLanguage::parse() start\n"));
2249 // g_nodeStack.push(this);
2251 // // parse one or more paragraphs
2252 // bool isFirst=TRUE;
2256 // par = new DocPara(this);
2257 // if (isFirst) { par->markFirst(); isFirst=FALSE; }
2258 // m_children.append(par);
2259 // retval=par->parse();
2261 // while (retval==TK_NEWPARA);
2262 // if (par) par->markLast();
2264 // DBG(("DocLanguage::parse() end\n"));
2265 // DocNode *n = g_nodeStack.pop();
2270 //---------------------------------------------------------------------------
2272 void DocSecRefItem::parse()
2274 DBG(("DocSecRefItem::parse() start\n"));
2275 g_nodeStack.push(this);
2277 doctokenizerYYsetStateTitle();
2279 while ((tok=doctokenizerYYlex()))
2281 if (!defaultHandleToken(this,tok,m_children))
2286 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\refitem",
2287 qPrint(g_token->name));
2290 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
2291 qPrint(g_token->name));
2294 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
2300 doctokenizerYYsetStatePara();
2301 handlePendingStyleCommands(this,m_children);
2304 if (!m_target.isEmpty())
2306 sec=Doxygen::sectionDict->find(m_target);
2309 m_file = sec->fileName;
2310 m_anchor = sec->label;
2311 if (g_sectionDict && g_sectionDict->find(m_target)==0)
2313 g_sectionDict->append(m_target,sec);
2318 warn_doc_error(g_fileName,doctokenizerYYlineno,"reference to unknown section %s",
2324 warn_doc_error(g_fileName,doctokenizerYYlineno,"reference to empty target");
2327 DBG(("DocSecRefItem::parse() end\n"));
2328 DocNode *n = g_nodeStack.pop();
2332 //---------------------------------------------------------------------------
2334 void DocSecRefList::parse()
2336 DBG(("DocSecRefList::parse() start\n"));
2337 g_nodeStack.push(this);
2339 int tok=doctokenizerYYlex();
2341 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
2345 if (tok==TK_COMMAND)
2347 switch (Mappers::cmdMapper->map(g_token->name))
2349 case CMD_SECREFITEM:
2351 int tok=doctokenizerYYlex();
2352 if (tok!=TK_WHITESPACE)
2354 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\refitem command");
2357 tok=doctokenizerYYlex();
2358 if (tok!=TK_WORD && tok!=TK_LNKWORD)
2360 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of \\refitem",
2365 DocSecRefItem *item = new DocSecRefItem(this,g_token->name);
2366 m_children.append(item);
2370 case CMD_ENDSECREFLIST:
2373 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\secreflist",
2374 qPrint(g_token->name));
2378 else if (tok==TK_WHITESPACE)
2380 // ignore whitespace
2384 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s inside section reference list",
2388 tok=doctokenizerYYlex();
2392 DBG(("DocSecRefList::parse() end\n"));
2393 DocNode *n = g_nodeStack.pop();
2397 //---------------------------------------------------------------------------
2399 DocInternalRef::DocInternalRef(DocNode *parent,const QCString &ref)
2400 : m_relPath(g_relPath)
2403 int i=ref.find('#');
2406 m_anchor = ref.right(ref.length()-i-1);
2407 m_file = ref.left(i);
2415 void DocInternalRef::parse()
2417 g_nodeStack.push(this);
2418 DBG(("DocInternalRef::parse() start\n"));
2421 while ((tok=doctokenizerYYlex()))
2423 if (!defaultHandleToken(this,tok,m_children))
2428 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\ref",
2429 qPrint(g_token->name));
2432 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
2433 qPrint(g_token->name));
2436 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
2443 handlePendingStyleCommands(this,m_children);
2444 DBG(("DocInternalRef::parse() end\n"));
2445 DocNode *n=g_nodeStack.pop();
2449 //---------------------------------------------------------------------------
2451 DocRef::DocRef(DocNode *parent,const QCString &target,const QCString &context) :
2452 m_refType(Unknown), m_isSubPage(FALSE)
2455 Definition *compound = 0;
2457 //printf("DocRef::DocRef(target=%s,context=%s)\n",target.data(),context.data());
2458 ASSERT(!target.isEmpty());
2459 SrcLangExt lang = getLanguageFromFileName(target);
2460 m_relPath = g_relPath;
2461 SectionInfo *sec = Doxygen::sectionDict->find(target);
2462 if (sec==0 && lang==SrcLangExt_Markdown) // lookup as markdown file
2464 sec = Doxygen::sectionDict->find(markdownFileNameToId(target));
2466 if (sec) // ref to section or anchor
2469 if (sec->type==SectionInfo::Page)
2471 pd = Doxygen::pageSDict->find(target);
2473 m_text = sec->title;
2474 if (m_text.isEmpty()) m_text = sec->label;
2477 m_file = stripKnownExtensions(sec->fileName);
2478 if (sec->type==SectionInfo::Anchor)
2482 else if (sec->type==SectionInfo::Table)
2488 m_refType = Section;
2490 m_isSubPage = pd && pd->hasParentPage();
2491 if (sec->type!=SectionInfo::Page || m_isSubPage) m_anchor = sec->label;
2492 //printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d type=%d\n",
2493 // m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor,sec->type);
2496 else if (resolveLink(context,target,TRUE,&compound,anchor))
2498 bool isFile = compound ?
2499 (compound->definitionType()==Definition::TypeFile ||
2500 compound->definitionType()==Definition::TypePage ? TRUE : FALSE) :
2502 m_text = linkToText(compound?compound->getLanguage():SrcLangExt_Unknown,target,isFile);
2504 if (compound && compound->isLinkable()) // ref to compound
2506 if (anchor.isEmpty() && /* compound link */
2507 compound->definitionType()==Definition::TypeGroup && /* is group */
2508 ((GroupDef *)compound)->groupTitle() /* with title */
2511 m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link
2513 else if (compound->definitionType()==Definition::TypeMember &&
2514 ((MemberDef*)compound)->isObjCMethod())
2516 // Objective C Method
2517 MemberDef *member = (MemberDef*)compound;
2518 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
2519 m_text = member->objCMethodName(localLink,g_inSeeBlock);
2522 m_file = compound->getOutputFileBase();
2523 m_ref = compound->getReference();
2524 //printf("isFile=%d compound=%s (%d)\n",isFile,compound->name().data(),
2525 // compound->definitionType());
2528 else if (compound && compound->definitionType()==Definition::TypeFile &&
2529 ((FileDef*)compound)->generateSourceFile()
2530 ) // undocumented file that has source code we can link to
2532 m_file = compound->getSourceFileBase();
2533 m_ref = compound->getReference();
2538 warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to `%s' for \\ref command",
2542 static void flattenParagraphs(DocNode *root,QList<DocNode> &children)
2544 QListIterator<DocNode> li(children);
2545 QList<DocNode> newChildren;
2547 for (li.toFirst();(dn=li.current());++li)
2549 if (dn->kind()==DocNode::Kind_Para)
2551 DocPara *para = (DocPara*)dn;
2552 QList<DocNode> ¶Children = para->children();
2553 paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node
2554 QListIterator<DocNode> li2(paraChildren);
2556 for (li2.toFirst();(dn2=li2.current());++li2)
2558 newChildren.append(dn2); // add them to new node
2563 QListIterator<DocNode> li3(newChildren);
2564 for (li3.toFirst();(dn=li3.current());++li3)
2566 children.append(dn);
2567 dn->setParent(root);
2571 void DocRef::parse()
2573 g_nodeStack.push(this);
2574 DBG(("DocRef::parse() start\n"));
2577 while ((tok=doctokenizerYYlex()))
2579 if (!defaultHandleToken(this,tok,m_children))
2584 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\ref",
2585 qPrint(g_token->name));
2588 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
2589 qPrint(g_token->name));
2594 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
2601 if (m_children.isEmpty() && !m_text.isEmpty())
2603 g_insideHtmlLink=TRUE;
2604 docParserPushContext();
2605 internalValidatingParseDoc(this,m_children,m_text);
2606 docParserPopContext();
2607 g_insideHtmlLink=FALSE;
2608 flattenParagraphs(this,m_children);
2611 handlePendingStyleCommands(this,m_children);
2613 DocNode *n=g_nodeStack.pop();
2617 //---------------------------------------------------------------------------
2619 DocCite::DocCite(DocNode *parent,const QCString &target,const QCString &) //context)
2621 static uint numBibFiles = Config_getList(CITE_BIB_FILES).count();
2623 //printf("DocCite::DocCite(target=%s)\n",target.data());
2624 ASSERT(!target.isEmpty());
2625 m_relPath = g_relPath;
2626 CiteInfo *cite = Doxygen::citeDict->find(target);
2627 //printf("cite=%p text='%s' numBibFiles=%d\n",cite,cite?cite->text.data():"<null>",numBibFiles);
2628 if (numBibFiles>0 && cite && !cite->text.isEmpty()) // ref to citation
2630 m_text = cite->text;
2632 m_anchor = CiteConsts::anchorPrefix+cite->label;
2633 m_file = convertNameToFile(CiteConsts::fileName,FALSE,TRUE);
2634 //printf("CITE ==> m_text=%s,m_ref=%s,m_file=%s,m_anchor=%s\n",
2635 // m_text.data(),m_ref.data(),m_file.data(),m_anchor.data());
2641 warn_doc_error(g_fileName,doctokenizerYYlineno,"\\cite command found but no bib files specified via CITE_BIB_FILES!");
2645 warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve reference to `%s' for \\cite command",
2650 warn_doc_error(g_fileName,doctokenizerYYlineno,"\\cite command to '%s' does not have an associated number",
2655 //---------------------------------------------------------------------------
2657 DocLink::DocLink(DocNode *parent,const QCString &target)
2660 Definition *compound = 0;
2663 m_relPath = g_relPath;
2664 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
2666 m_refText = m_refText.right(m_refText.length()-1);
2668 if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock,
2672 if (compound && compound->isLinkable())
2674 m_file = compound->getOutputFileBase();
2675 m_ref = compound->getReference();
2677 else if (compound && compound->definitionType()==Definition::TypeFile &&
2678 ((FileDef*)compound)->generateSourceFile()
2679 ) // undocumented file that has source code we can link to
2681 m_file = compound->getSourceFileBase();
2682 m_ref = compound->getReference();
2687 // bogus link target
2688 warn_doc_error(g_fileName,doctokenizerYYlineno,"unable to resolve link to `%s' for \\link command",
2693 QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
2696 g_nodeStack.push(this);
2697 DBG(("DocLink::parse() start\n"));
2700 while ((tok=doctokenizerYYlex()))
2702 if (!defaultHandleToken(this,tok,m_children,FALSE))
2707 switch (Mappers::cmdMapper->map(g_token->name))
2712 warn_doc_error(g_fileName,doctokenizerYYlineno,"{@link.. ended with @endlink command");
2716 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\link",
2717 qPrint(g_token->name));
2722 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
2723 qPrint(g_token->name));
2726 if (g_token->name!="see" || !isXmlLink)
2728 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected xml/html command %s found",
2729 qPrint(g_token->name));
2734 if (isJavaLink) // special case to detect closing }
2736 QCString w = g_token->name;
2742 else if ((p=w.find('}'))!=-1)
2745 m_children.append(new DocWord(this,w.left(p)));
2746 if ((uint)p<l-1) // something left after the } (for instance a .)
2748 result=w.right(l-p-1);
2753 m_children.append(new DocWord(this,g_token->name));
2756 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
2764 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
2769 if (m_children.isEmpty()) // no link text
2771 m_children.append(new DocWord(this,m_refText));
2774 handlePendingStyleCommands(this,m_children);
2775 DBG(("DocLink::parse() end\n"));
2776 DocNode *n=g_nodeStack.pop();
2782 //---------------------------------------------------------------------------
2784 DocDotFile::DocDotFile(DocNode *parent,const QCString &name,const QCString &context) :
2785 m_name(name), m_relPath(g_relPath), m_context(context)
2790 void DocDotFile::parse()
2792 defaultHandleTitleAndSize(CMD_DOTFILE,this,m_children,m_width,m_height);
2795 FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig);
2796 if (fd==0 && m_name.right(4)!=".dot") // try with .dot extension as well
2798 fd = findFileDef(Doxygen::dotFileNameDict,m_name+".dot",ambig);
2802 m_file = fd->absFilePath();
2806 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dot file name %s is ambiguous.\n"
2807 "Possible candidates:\n%s",qPrint(m_name),
2808 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2813 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dot file %s is not found "
2814 "in any of the paths specified via DOTFILE_DIRS!",qPrint(m_name));
2818 DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &context) :
2819 m_name(name), m_relPath(g_relPath), m_context(context)
2824 void DocMscFile::parse()
2826 defaultHandleTitleAndSize(CMD_MSCFILE,this,m_children,m_width,m_height);
2829 FileDef *fd = findFileDef(Doxygen::mscFileNameDict,m_name,ambig);
2830 if (fd==0 && m_name.right(4)!=".msc") // try with .msc extension as well
2832 fd = findFileDef(Doxygen::mscFileNameDict,m_name+".msc",ambig);
2836 m_file = fd->absFilePath();
2840 warn_doc_error(g_fileName,doctokenizerYYlineno,"included msc file name %s is ambiguous.\n"
2841 "Possible candidates:\n%s",qPrint(m_name),
2842 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2847 warn_doc_error(g_fileName,doctokenizerYYlineno,"included msc file %s is not found "
2848 "in any of the paths specified via MSCFILE_DIRS!",qPrint(m_name));
2852 //---------------------------------------------------------------------------
2854 DocDiaFile::DocDiaFile(DocNode *parent,const QCString &name,const QCString &context) :
2855 m_name(name), m_relPath(g_relPath), m_context(context)
2860 void DocDiaFile::parse()
2862 defaultHandleTitleAndSize(CMD_DIAFILE,this,m_children,m_width,m_height);
2865 FileDef *fd = findFileDef(Doxygen::diaFileNameDict,m_name,ambig);
2866 if (fd==0 && m_name.right(4)!=".dia") // try with .dia extension as well
2868 fd = findFileDef(Doxygen::diaFileNameDict,m_name+".dia",ambig);
2872 m_file = fd->absFilePath();
2876 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dia file name %s is ambiguous.\n"
2877 "Possible candidates:\n%s",qPrint(m_name),
2878 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2883 warn_doc_error(g_fileName,doctokenizerYYlineno,"included dia file %s is not found "
2884 "in any of the paths specified via DIAFILE_DIRS!",qPrint(m_name));
2888 //---------------------------------------------------------------------------
2890 DocVhdlFlow::DocVhdlFlow(DocNode *parent)
2895 void DocVhdlFlow::parse()
2897 g_nodeStack.push(this);
2898 DBG(("DocVhdlFlow::parse() start\n"));
2900 doctokenizerYYsetStateTitle();
2902 while ((tok=doctokenizerYYlex()))
2904 if (!defaultHandleToken(this,tok,m_children))
2909 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a \\vhdlflow",
2910 qPrint(g_token->name));
2913 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
2914 qPrint(g_token->name));
2917 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
2923 tok=doctokenizerYYlex();
2925 doctokenizerYYsetStatePara();
2926 handlePendingStyleCommands(this,m_children);
2928 DBG(("DocVhdlFlow::parse() end\n"));
2929 DocNode *n=g_nodeStack.pop();
2931 VhdlDocGen::createFlowChart(g_memberDef);
2935 //---------------------------------------------------------------------------
2937 DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QCString &name,
2938 Type t,const QCString &url) :
2939 m_attribs(attribs), m_name(name),
2940 m_type(t), m_relPath(g_relPath),
2946 void DocImage::parse()
2948 defaultHandleTitleAndSize(CMD_IMAGE,this,m_children,m_width,m_height);
2952 //---------------------------------------------------------------------------
2954 int DocHtmlHeader::parse()
2956 int retval=RetVal_OK;
2957 g_nodeStack.push(this);
2958 DBG(("DocHtmlHeader::parse() start\n"));
2961 while ((tok=doctokenizerYYlex()))
2963 if (!defaultHandleToken(this,tok,m_children))
2968 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <h%d> tag",
2969 qPrint(g_token->name),m_level);
2973 int tagId=Mappers::htmlTagMapper->map(g_token->name);
2974 if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
2978 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h1>",
2983 else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag
2987 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h2>",
2992 else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag
2996 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h3>",
3001 else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag
3005 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h4>",
3010 else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag
3014 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h5>",
3019 else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag
3023 warn_doc_error(g_fileName,doctokenizerYYlineno,"<h%d> ended with </h6>",
3028 else if (tagId==HTML_A)
3030 if (!g_token->endTag)
3032 handleAHref(this,m_children,g_token->attribs);
3035 else if (tagId==HTML_BR)
3037 DocLineBreak *lb = new DocLineBreak(this);
3038 m_children.append(lb);
3042 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <h%d> context",
3043 g_token->endTag?"/":"",qPrint(g_token->name),m_level);
3049 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
3050 qPrint(g_token->name));
3053 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
3061 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3062 " <h%d> tag\n",m_level);
3065 handlePendingStyleCommands(this,m_children);
3066 DBG(("DocHtmlHeader::parse() end\n"));
3067 DocNode *n=g_nodeStack.pop();
3072 //---------------------------------------------------------------------------
3074 int DocHRef::parse()
3076 int retval=RetVal_OK;
3077 g_nodeStack.push(this);
3078 DBG(("DocHRef::parse() start\n"));
3081 while ((tok=doctokenizerYYlex()))
3083 if (!defaultHandleToken(this,tok,m_children))
3088 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <a>..</a> block",
3089 qPrint(g_token->name));
3092 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
3093 qPrint(g_token->name));
3098 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3099 if (tagId==HTML_A && g_token->endTag) // found </a> tag
3105 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <a href=...> context",
3106 g_token->endTag?"/":"",qPrint(g_token->name),doctokenizerYYlineno);
3111 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
3112 tokToString(tok),doctokenizerYYlineno);
3119 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3120 " <a href=...> tag",doctokenizerYYlineno);
3123 handlePendingStyleCommands(this,m_children);
3124 DBG(("DocHRef::parse() end\n"));
3125 DocNode *n=g_nodeStack.pop();
3130 //---------------------------------------------------------------------------
3132 int DocInternal::parse(int level)
3134 int retval=RetVal_OK;
3135 g_nodeStack.push(this);
3136 DBG(("DocInternal::parse() start\n"));
3138 // first parse any number of paragraphs
3143 DocPara *par = new DocPara(this);
3144 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3145 retval=par->parse();
3146 if (!par->isEmpty())
3148 m_children.append(par);
3155 if (retval==TK_LISTITEM)
3157 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found",doctokenizerYYlineno);
3159 } while (retval!=0 &&
3160 retval!=RetVal_Section &&
3161 retval!=RetVal_Subsection &&
3162 retval!=RetVal_Subsubsection &&
3163 retval!=RetVal_Paragraph &&
3164 retval!=RetVal_EndInternal
3166 if (lastPar) lastPar->markLast();
3168 // then parse any number of level-n sections
3169 while ((level==1 && retval==RetVal_Section) ||
3170 (level==2 && retval==RetVal_Subsection) ||
3171 (level==3 && retval==RetVal_Subsubsection) ||
3172 (level==4 && retval==RetVal_Paragraph)
3175 DocSection *s=new DocSection(this,
3176 QMIN(level+Doxygen::subpageNestingLevel,5),g_token->sectionId);
3177 m_children.append(s);
3178 retval = s->parse();
3181 if (retval==RetVal_Internal)
3183 warn_doc_error(g_fileName,doctokenizerYYlineno,"\\internal command found inside internal section");
3186 DBG(("DocInternal::parse() end: retval=%x\n",retval));
3187 DocNode *n=g_nodeStack.pop();
3192 //---------------------------------------------------------------------------
3194 int DocIndexEntry::parse()
3196 int retval=RetVal_OK;
3197 g_nodeStack.push(this);
3198 DBG(("DocIndexEntry::parse() start\n"));
3199 int tok=doctokenizerYYlex();
3200 if (tok!=TK_WHITESPACE)
3202 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after \\addindex command");
3205 doctokenizerYYsetStateTitle();
3207 while ((tok=doctokenizerYYlex()))
3216 m_entry+=g_token->name;
3220 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name);
3223 case DocSymbol::Sym_BSlash: m_entry+='\\'; break;
3224 case DocSymbol::Sym_At: m_entry+='@'; break;
3225 case DocSymbol::Sym_Less: m_entry+='<'; break;
3226 case DocSymbol::Sym_Greater: m_entry+='>'; break;
3227 case DocSymbol::Sym_Amp: m_entry+='&'; break;
3228 case DocSymbol::Sym_Dollar: m_entry+='$'; break;
3229 case DocSymbol::Sym_Hash: m_entry+='#'; break;
3230 case DocSymbol::Sym_Percent: m_entry+='%'; break;
3231 case DocSymbol::Sym_apos: m_entry+='\''; break;
3232 case DocSymbol::Sym_Quot: m_entry+='"'; break;
3233 case DocSymbol::Sym_lsquo: m_entry+='`'; break;
3234 case DocSymbol::Sym_rsquo: m_entry+='\''; break;
3235 case DocSymbol::Sym_ldquo: m_entry+="``"; break;
3236 case DocSymbol::Sym_rdquo: m_entry+="''"; break;
3237 case DocSymbol::Sym_ndash: m_entry+="--"; break;
3238 case DocSymbol::Sym_mdash: m_entry+="---"; break;
3240 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected symbol found as argument of \\addindex");
3246 switch (Mappers::cmdMapper->map(g_token->name))
3248 case CMD_BSLASH: m_entry+='\\'; break;
3249 case CMD_AT: m_entry+='@'; break;
3250 case CMD_LESS: m_entry+='<'; break;
3251 case CMD_GREATER: m_entry+='>'; break;
3252 case CMD_AMP: m_entry+='&'; break;
3253 case CMD_DOLLAR: m_entry+='$'; break;
3254 case CMD_HASH: m_entry+='#'; break;
3255 case CMD_DCOLON: m_entry+="::"; break;
3256 case CMD_PERCENT: m_entry+='%'; break;
3257 case CMD_NDASH: m_entry+="--"; break;
3258 case CMD_MDASH: m_entry+="---"; break;
3259 case CMD_QUOTE: m_entry+='"'; break;
3260 case CMD_PUNT: m_entry+='.'; break;
3261 case CMD_PLUS: m_entry+='+'; break;
3262 case CMD_MINUS: m_entry+='-'; break;
3264 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command %s found as argument of \\addindex",
3265 qPrint(g_token->name));
3270 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
3275 doctokenizerYYsetStatePara();
3276 m_entry = m_entry.stripWhiteSpace();
3278 DBG(("DocIndexEntry::parse() end retval=%x\n",retval));
3279 DocNode *n=g_nodeStack.pop();
3284 //---------------------------------------------------------------------------
3286 DocHtmlCaption::DocHtmlCaption(DocNode *parent,const HtmlAttribList &attribs)
3288 m_hasCaptionId = FALSE;
3289 HtmlAttribListIterator li(attribs);
3291 for (li.toFirst();(opt=li.current());++li)
3293 if (opt->name=="id") // interpret id attribute as an anchor
3295 SectionInfo *sec = Doxygen::sectionDict->find(opt->value);
3298 //printf("Found anchor %s\n",id.data());
3299 m_file = sec->fileName;
3300 m_anchor = sec->label;
3301 m_hasCaptionId = TRUE;
3302 if (g_sectionDict && g_sectionDict->find(opt->value)==0)
3304 //printf("Inserting in dictionary!\n");
3305 g_sectionDict->append(opt->value,sec);
3310 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid caption id `%s'",qPrint(opt->value));
3313 else // copy attribute
3315 m_attribs.append(new HtmlAttrib(*opt));
3321 int DocHtmlCaption::parse()
3324 g_nodeStack.push(this);
3325 DBG(("DocHtmlCaption::parse() start\n"));
3327 while ((tok=doctokenizerYYlex()))
3329 if (!defaultHandleToken(this,tok,m_children))
3334 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <caption> tag",
3335 qPrint(g_token->name));
3338 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
3339 qPrint(g_token->name));
3343 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3344 if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
3351 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <caption> context",
3352 g_token->endTag?"/":"",qPrint(g_token->name));
3357 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
3365 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3366 " <caption> tag",doctokenizerYYlineno);
3369 handlePendingStyleCommands(this,m_children);
3370 DBG(("DocHtmlCaption::parse() end\n"));
3371 DocNode *n=g_nodeStack.pop();
3376 //---------------------------------------------------------------------------
3378 int DocHtmlCell::parse()
3380 int retval=RetVal_OK;
3381 g_nodeStack.push(this);
3382 DBG(("DocHtmlCell::parse() start\n"));
3384 // parse one or more paragraphs
3389 par = new DocPara(this);
3390 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3391 m_children.append(par);
3392 retval=par->parse();
3393 if (retval==TK_HTMLTAG)
3395 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3396 if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
3398 retval=TK_NEWPARA; // ignore the tag
3400 else if (tagId==HTML_TH && g_token->endTag) // found </th> tag
3402 retval=TK_NEWPARA; // ignore the tag
3406 while (retval==TK_NEWPARA);
3407 if (par) par->markLast();
3409 DBG(("DocHtmlCell::parse() end\n"));
3410 DocNode *n=g_nodeStack.pop();
3415 int DocHtmlCell::parseXml()
3417 int retval=RetVal_OK;
3418 g_nodeStack.push(this);
3419 DBG(("DocHtmlCell::parseXml() start\n"));
3421 // parse one or more paragraphs
3426 par = new DocPara(this);
3427 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3428 m_children.append(par);
3429 retval=par->parse();
3430 if (retval==TK_HTMLTAG)
3432 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3433 if (tagId==XML_ITEM && g_token->endTag) // found </item> tag
3435 retval=TK_NEWPARA; // ignore the tag
3437 else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag
3439 retval=TK_NEWPARA; // ignore the tag
3443 while (retval==TK_NEWPARA);
3444 if (par) par->markLast();
3446 DBG(("DocHtmlCell::parseXml() end\n"));
3447 DocNode *n=g_nodeStack.pop();
3452 int DocHtmlCell::rowSpan() const
3455 HtmlAttribList attrs = attribs();
3457 for (i=0; i<attrs.count(); ++i)
3459 if (attrs.at(i)->name.lower()=="rowspan")
3461 retval = attrs.at(i)->value.toInt();
3468 int DocHtmlCell::colSpan() const
3471 HtmlAttribList attrs = attribs();
3473 for (i=0; i<attrs.count(); ++i)
3475 if (attrs.at(i)->name.lower()=="colspan")
3477 retval = QMAX(1,attrs.at(i)->value.toInt());
3484 DocHtmlCell::Alignment DocHtmlCell::alignment() const
3486 HtmlAttribList attrs = attribs();
3488 for (i=0; i<attrs.count(); ++i)
3490 if (attrs.at(i)->name.lower()=="align")
3492 if (attrs.at(i)->value.lower()=="center")
3494 else if (attrs.at(i)->value.lower()=="right")
3503 //---------------------------------------------------------------------------
3505 int DocHtmlRow::parse()
3507 int retval=RetVal_OK;
3508 g_nodeStack.push(this);
3509 DBG(("DocHtmlRow::parse() start\n"));
3511 bool isHeading=FALSE;
3513 DocHtmlCell *cell=0;
3516 int tok=doctokenizerYYlex();
3518 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3519 // should find a html tag now
3520 if (tok==TK_HTMLTAG)
3522 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3523 if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
3526 else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag
3530 else // found some other tag
3532 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <td> or <th> tag but "
3533 "found <%s> instead!",qPrint(g_token->name));
3534 doctokenizerYYpushBackHtmlTag(g_token->name);
3538 else if (tok==0) // premature end of comment
3540 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
3541 " for a html description title");
3544 else // token other than html token
3546 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <td> or <th> tag but found %s token instead!",
3551 // parse one or more cells
3554 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3555 cell->markFirst(isFirst);
3557 m_children.append(cell);
3558 retval=cell->parse();
3559 isHeading = retval==RetVal_TableHCell;
3561 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3562 if (cell) cell->markLast(TRUE);
3565 DBG(("DocHtmlRow::parse() end\n"));
3566 DocNode *n=g_nodeStack.pop();
3571 int DocHtmlRow::parseXml(bool isHeading)
3573 int retval=RetVal_OK;
3574 g_nodeStack.push(this);
3575 DBG(("DocHtmlRow::parseXml() start\n"));
3578 DocHtmlCell *cell=0;
3581 int tok=doctokenizerYYlex();
3583 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3584 // should find a html tag now
3585 if (tok==TK_HTMLTAG)
3587 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3588 if (tagId==XML_TERM && !g_token->endTag) // found <term> tag
3591 else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag
3594 else // found some other tag
3596 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <term> or <description> tag but "
3597 "found <%s> instead!",qPrint(g_token->name));
3598 doctokenizerYYpushBackHtmlTag(g_token->name);
3602 else if (tok==0) // premature end of comment
3604 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
3605 " for a html description title");
3608 else // token other than html token
3610 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <td> or <th> tag but found %s token instead!",
3617 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3618 cell->markFirst(isFirst);
3620 m_children.append(cell);
3621 retval=cell->parseXml();
3623 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3624 if (cell) cell->markLast(TRUE);
3627 DBG(("DocHtmlRow::parseXml() end\n"));
3628 DocNode *n=g_nodeStack.pop();
3633 //---------------------------------------------------------------------------
3635 int DocHtmlTable::parse()
3637 int retval=RetVal_OK;
3638 g_nodeStack.push(this);
3639 DBG(("DocHtmlTable::parse() start\n"));
3643 int tok=doctokenizerYYlex();
3645 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3646 // should find a html tag now
3647 if (tok==TK_HTMLTAG)
3649 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3650 if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
3652 // no caption, just rows
3653 retval=RetVal_TableRow;
3655 else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag
3659 warn_doc_error(g_fileName,doctokenizerYYlineno,"table already has a caption, found another one");
3663 m_caption = new DocHtmlCaption(this,g_token->attribs);
3664 retval=m_caption->parse();
3666 if (retval==RetVal_OK) // caption was parsed ok
3672 else // found wrong token
3674 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <tr> or <caption> tag but "
3675 "found <%s%s> instead!", g_token->endTag ? "/" : "", qPrint(g_token->name));
3678 else if (tok==0) // premature end of comment
3680 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
3681 " for a <tr> or <caption> tag");
3683 else // token other than html token
3685 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <tr> tag but found %s token instead!",
3689 // parse one or more rows
3690 while (retval==RetVal_TableRow)
3692 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3693 m_children.append(tr);
3699 DBG(("DocHtmlTable::parse() end\n"));
3700 DocNode *n=g_nodeStack.pop();
3702 return retval==RetVal_EndTable ? RetVal_OK : retval;
3705 int DocHtmlTable::parseXml()
3707 int retval=RetVal_OK;
3708 g_nodeStack.push(this);
3709 DBG(("DocHtmlTable::parseXml() start\n"));
3712 int tok=doctokenizerYYlex();
3714 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3715 // should find a html tag now
3717 bool isHeader=FALSE;
3718 if (tok==TK_HTMLTAG)
3720 tagId=Mappers::htmlTagMapper->map(g_token->name);
3721 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
3723 retval=RetVal_TableRow;
3725 if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag
3727 retval=RetVal_TableRow;
3732 // parse one or more rows
3733 while (retval==RetVal_TableRow)
3735 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3736 m_children.append(tr);
3737 retval=tr->parseXml(isHeader);
3743 DBG(("DocHtmlTable::parseXml() end\n"));
3744 DocNode *n=g_nodeStack.pop();
3746 tagId=Mappers::htmlTagMapper->map(g_token->name);
3747 return tagId==XML_LIST && g_token->endTag ? RetVal_OK : retval;
3750 /** Helper class to compute the grid for an HTML style table */
3751 struct ActiveRowSpan
3753 ActiveRowSpan(int rows,int col) : rowsLeft(rows), column(col) {}
3758 /** List of ActiveRowSpan classes. */
3759 typedef QList<ActiveRowSpan> RowSpanList;
3761 /** determines the location of all cells in a grid, resolving row and
3762 column spans. For each the total number of visible cells is computed,
3763 and the total number of visible columns over all rows is stored.
3765 void DocHtmlTable::computeTableGrid()
3767 //printf("computeTableGrid()\n");
3768 RowSpanList rowSpans;
3769 rowSpans.setAutoDelete(TRUE);
3772 QListIterator<DocNode> li(children());
3774 for (li.toFirst();(rowNode=li.current());++li)
3778 if (rowNode->kind()==DocNode::Kind_HtmlRow)
3781 DocHtmlRow *row = (DocHtmlRow*)rowNode;
3782 QListIterator<DocNode> rli(row->children());
3784 for (rli.toFirst();(cellNode=rli.current());++rli)
3786 if (cellNode->kind()==DocNode::Kind_HtmlCell)
3788 DocHtmlCell *cell = (DocHtmlCell*)cellNode;
3789 int rs = cell->rowSpan();
3790 int cs = cell->colSpan();
3792 for (i=0;i<rowSpans.count();i++)
3794 if (rowSpans.at(i)->rowsLeft>0 &&
3795 rowSpans.at(i)->column==colIdx)
3797 colIdx=rowSpans.at(i)->column+1;
3801 if (rs>0) rowSpans.append(new ActiveRowSpan(rs,colIdx));
3802 //printf("found cell at (%d,%d)\n",rowIdx,colIdx);
3803 cell->setRowIndex(rowIdx);
3804 cell->setColumnIndex(colIdx);
3809 for (i=0;i<rowSpans.count();i++)
3811 if (rowSpans.at(i)->rowsLeft>0) rowSpans.at(i)->rowsLeft--;
3813 row->setVisibleCells(cells);
3814 row->setRowIndex(rowIdx);
3817 if (colIdx-1>maxCols) maxCols=colIdx-1;
3819 m_numCols = maxCols;
3822 void DocHtmlTable::accept(DocVisitor *v)
3825 // for HTML output we put the caption first
3826 //if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v);
3827 // doxygen 1.8.11: always put the caption first
3828 if (m_caption) m_caption->accept(v);
3829 QListIterator<DocNode> cli(m_children);
3831 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
3832 // for other output formats we put the caption last
3833 //if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v);
3837 //---------------------------------------------------------------------------
3839 int DocHtmlDescTitle::parse()
3842 g_nodeStack.push(this);
3843 DBG(("DocHtmlDescTitle::parse() start\n"));
3846 while ((tok=doctokenizerYYlex()))
3848 if (!defaultHandleToken(this,tok,m_children))
3854 QCString cmdName=g_token->name;
3855 bool isJavaLink=FALSE;
3856 switch (Mappers::cmdMapper->map(cmdName))
3860 int tok=doctokenizerYYlex();
3861 if (tok!=TK_WHITESPACE)
3863 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
3864 qPrint(g_token->name));
3868 doctokenizerYYsetStateRef();
3869 tok=doctokenizerYYlex(); // get the reference id
3872 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
3873 tokToString(tok),qPrint(cmdName));
3877 DocRef *ref = new DocRef(this,g_token->name,g_context);
3878 m_children.append(ref);
3881 doctokenizerYYsetStatePara();
3890 int tok=doctokenizerYYlex();
3891 if (tok!=TK_WHITESPACE)
3893 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
3898 doctokenizerYYsetStateLink();
3899 tok=doctokenizerYYlex();
3902 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
3903 tokToString(tok),qPrint(cmdName));
3907 doctokenizerYYsetStatePara();
3908 DocLink *lnk = new DocLink(this,g_token->name);
3909 m_children.append(lnk);
3910 QCString leftOver = lnk->parse(isJavaLink);
3911 if (!leftOver.isEmpty())
3913 m_children.append(new DocWord(this,leftOver));
3921 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a <dt> tag",
3922 qPrint(g_token->name));
3927 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
3928 qPrint(g_token->name));
3932 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3933 if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
3935 retval = RetVal_DescData;
3938 else if (tagId==HTML_DT && g_token->endTag)
3940 // ignore </dt> tag.
3942 else if (tagId==HTML_DT)
3944 // missing <dt> tag.
3945 retval = RetVal_DescTitle;
3948 else if (tagId==HTML_DL && g_token->endTag)
3950 retval=RetVal_EndDesc;
3953 else if (tagId==HTML_A)
3955 if (!g_token->endTag)
3957 handleAHref(this,m_children,g_token->attribs);
3962 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected html tag <%s%s> found within <dt> context",
3963 g_token->endTag?"/":"",qPrint(g_token->name));
3968 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
3976 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end of comment while inside"
3980 handlePendingStyleCommands(this,m_children);
3981 DBG(("DocHtmlDescTitle::parse() end\n"));
3982 DocNode *n=g_nodeStack.pop();
3987 //---------------------------------------------------------------------------
3989 int DocHtmlDescData::parse()
3991 m_attribs = g_token->attribs;
3993 g_nodeStack.push(this);
3994 DBG(("DocHtmlDescData::parse() start\n"));
4000 par = new DocPara(this);
4001 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4002 m_children.append(par);
4003 retval=par->parse();
4005 while (retval==TK_NEWPARA);
4006 if (par) par->markLast();
4008 DBG(("DocHtmlDescData::parse() end\n"));
4009 DocNode *n=g_nodeStack.pop();
4014 //---------------------------------------------------------------------------
4016 int DocHtmlDescList::parse()
4018 int retval=RetVal_OK;
4019 g_nodeStack.push(this);
4020 DBG(("DocHtmlDescList::parse() start\n"));
4023 int tok=doctokenizerYYlex();
4025 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4026 // should find a html tag now
4027 if (tok==TK_HTMLTAG)
4029 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4030 if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
4034 else // found some other tag
4036 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <dt> tag but "
4037 "found <%s> instead!",qPrint(g_token->name));
4038 doctokenizerYYpushBackHtmlTag(g_token->name);
4042 else if (tok==0) // premature end of comment
4044 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
4045 " for a html description title");
4048 else // token other than html token
4050 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <dt> tag but found %s token instead!",
4057 DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs);
4058 m_children.append(dt);
4059 DocHtmlDescData *dd=new DocHtmlDescData(this);
4060 m_children.append(dd);
4062 if (retval==RetVal_DescData)
4066 else if (retval!=RetVal_DescTitle)
4071 } while (retval==RetVal_DescTitle);
4075 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while inside <dl> block");
4080 DocNode *n=g_nodeStack.pop();
4082 DBG(("DocHtmlDescList::parse() end\n"));
4083 return retval==RetVal_EndDesc ? RetVal_OK : retval;
4086 //---------------------------------------------------------------------------
4088 int DocHtmlListItem::parse()
4090 DBG(("DocHtmlListItem::parse() start\n"));
4092 g_nodeStack.push(this);
4094 // parse one or more paragraphs
4099 par = new DocPara(this);
4100 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4101 m_children.append(par);
4102 retval=par->parse();
4104 while (retval==TK_NEWPARA);
4105 if (par) par->markLast();
4107 DocNode *n=g_nodeStack.pop();
4109 DBG(("DocHtmlListItem::parse() end retval=%x\n",retval));
4113 int DocHtmlListItem::parseXml()
4115 DBG(("DocHtmlListItem::parseXml() start\n"));
4117 g_nodeStack.push(this);
4119 // parse one or more paragraphs
4124 par = new DocPara(this);
4125 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4126 m_children.append(par);
4127 retval=par->parse();
4128 if (retval==0) break;
4130 //printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
4131 // retval,qPrint(g_token->name),g_token->endTag);
4132 if (retval==RetVal_ListItem)
4137 while (retval!=RetVal_CloseXml);
4139 if (par) par->markLast();
4141 DocNode *n=g_nodeStack.pop();
4143 DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
4147 //---------------------------------------------------------------------------
4149 int DocHtmlList::parse()
4151 DBG(("DocHtmlList::parse() start\n"));
4152 int retval=RetVal_OK;
4154 g_nodeStack.push(this);
4157 int tok=doctokenizerYYlex();
4158 // skip whitespace and paragraph breaks
4159 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4160 // should find a html tag now
4161 if (tok==TK_HTMLTAG)
4163 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4164 if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
4166 // ok, we can go on.
4168 else if (((m_type==Unordered && tagId==HTML_UL) ||
4169 (m_type==Ordered && tagId==HTML_OL)
4170 ) && g_token->endTag
4171 ) // found empty list
4173 // add dummy item to obtain valid HTML
4174 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4175 warn_doc_error(g_fileName,doctokenizerYYlineno,"empty list!");
4176 retval = RetVal_EndList;
4179 else // found some other tag
4181 // add dummy item to obtain valid HTML
4182 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4183 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <li> tag but "
4184 "found <%s%s> instead!",g_token->endTag?"/":"",qPrint(g_token->name));
4185 doctokenizerYYpushBackHtmlTag(g_token->name);
4189 else if (tok==0) // premature end of comment
4191 // add dummy item to obtain valid HTML
4192 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4193 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
4194 " for a html list item");
4197 else // token other than html token
4199 // add dummy item to obtain valid HTML
4200 m_children.append(new DocHtmlListItem(this,HtmlAttribList(),1));
4201 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <li> tag but found %s token instead!",
4208 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
4209 m_children.append(li);
4211 } while (retval==RetVal_ListItem);
4215 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while inside <%cl> block",
4216 m_type==Unordered ? 'u' : 'o');
4220 DBG(("DocHtmlList::parse() end retval=%x\n",retval));
4221 DocNode *n=g_nodeStack.pop();
4223 return retval==RetVal_EndList ? RetVal_OK : retval;
4226 int DocHtmlList::parseXml()
4228 DBG(("DocHtmlList::parseXml() start\n"));
4229 int retval=RetVal_OK;
4231 g_nodeStack.push(this);
4234 int tok=doctokenizerYYlex();
4235 // skip whitespace and paragraph breaks
4236 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
4237 // should find a html tag now
4238 if (tok==TK_HTMLTAG)
4240 int tagId=Mappers::htmlTagMapper->map(g_token->name);
4241 //printf("g_token->name=%s g_token->endTag=%d\n",qPrint(g_token->name),g_token->endTag);
4242 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
4244 // ok, we can go on.
4246 else // found some other tag
4248 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <item> tag but "
4249 "found <%s> instead!",qPrint(g_token->name));
4250 doctokenizerYYpushBackHtmlTag(g_token->name);
4254 else if (tok==0) // premature end of comment
4256 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while looking"
4257 " for a html list item");
4260 else // token other than html token
4262 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected <item> tag but found %s token instead!",
4269 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
4270 m_children.append(li);
4271 retval=li->parseXml();
4272 if (retval==0) break;
4273 //printf("retval=%x g_token->name=%s\n",retval,qPrint(g_token->name));
4274 } while (retval==RetVal_ListItem);
4278 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment while inside <list type=\"%s\"> block",
4279 m_type==Unordered ? "bullet" : "number");
4283 DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
4284 DocNode *n=g_nodeStack.pop();
4286 return retval==RetVal_EndList ||
4287 (retval==RetVal_CloseXml || g_token->name=="list") ?
4291 //--------------------------------------------------------------------------
4293 int DocHtmlBlockQuote::parse()
4295 DBG(("DocHtmlBlockQuote::parse() start\n"));
4297 g_nodeStack.push(this);
4299 // parse one or more paragraphs
4304 par = new DocPara(this);
4305 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4306 m_children.append(par);
4307 retval=par->parse();
4309 while (retval==TK_NEWPARA);
4310 if (par) par->markLast();
4312 DocNode *n=g_nodeStack.pop();
4314 DBG(("DocHtmlBlockQuote::parse() end retval=%x\n",retval));
4315 return (retval==RetVal_EndBlockQuote) ? RetVal_OK : retval;
4318 //---------------------------------------------------------------------------
4320 int DocParBlock::parse()
4322 DBG(("DocParBlock::parse() start\n"));
4324 g_nodeStack.push(this);
4326 // parse one or more paragraphs
4331 par = new DocPara(this);
4332 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4333 m_children.append(par);
4334 retval=par->parse();
4336 while (retval==TK_NEWPARA);
4337 if (par) par->markLast();
4339 DocNode *n=g_nodeStack.pop();
4341 DBG(("DocParBlock::parse() end retval=%x\n",retval));
4342 return (retval==RetVal_EndBlockQuote) ? RetVal_OK : retval;
4345 //---------------------------------------------------------------------------
4347 int DocSimpleListItem::parse()
4349 g_nodeStack.push(this);
4350 int rv=m_paragraph->parse();
4351 m_paragraph->markFirst();
4352 m_paragraph->markLast();
4353 DocNode *n=g_nodeStack.pop();
4358 //--------------------------------------------------------------------------
4360 int DocSimpleList::parse()
4362 g_nodeStack.push(this);
4366 DocSimpleListItem *li=new DocSimpleListItem(this);
4367 m_children.append(li);
4369 } while (rv==RetVal_ListItem);
4370 DocNode *n=g_nodeStack.pop();
4372 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4375 //--------------------------------------------------------------------------
4377 DocAutoListItem::DocAutoListItem(DocNode *parent,int indent,int num)
4378 : m_indent(indent), m_itemNum(num)
4383 int DocAutoListItem::parse()
4385 int retval = RetVal_OK;
4386 g_nodeStack.push(this);
4388 // first parse any number of paragraphs
4393 DocPara *par = new DocPara(this);
4394 if (isFirst) { par->markFirst(); isFirst=FALSE; }
4395 retval=par->parse();
4396 if (!par->isEmpty())
4398 m_children.append(par);
4399 if (lastPar) lastPar->markLast(FALSE);
4406 // next paragraph should be more indented than the - marker to belong
4408 } while (retval==TK_NEWPARA && g_token->indent>m_indent);
4409 if (lastPar) lastPar->markLast();
4411 DocNode *n=g_nodeStack.pop();
4413 //printf("DocAutoListItem: retval=%d indent=%d\n",retval,g_token->indent);
4417 //--------------------------------------------------------------------------
4419 DocAutoList::DocAutoList(DocNode *parent,int indent,bool isEnumList,
4421 m_indent(indent), m_isEnumList(isEnumList),
4427 int DocAutoList::parse()
4429 int retval = RetVal_OK;
4431 g_nodeStack.push(this);
4432 doctokenizerYYstartAutoList();
4433 // first item or sub list => create new list
4436 if (g_token->id!=-1) // explicitly numbered list
4438 num=g_token->id; // override num with real number given
4440 DocAutoListItem *li = new DocAutoListItem(this,m_indent,num++);
4441 m_children.append(li);
4443 //printf("DocAutoList::parse(): retval=0x%x g_token->indent=%d m_indent=%d "
4444 // "m_isEnumList=%d g_token->isEnumList=%d g_token->name=%s\n",
4445 // retval,g_token->indent,m_indent,m_isEnumList,g_token->isEnumList,
4446 // g_token->name.data());
4447 //printf("num=%d g_token->id=%d\n",num,g_token->id);
4449 while (retval==TK_LISTITEM && // new list item
4450 m_indent==g_token->indent && // at same indent level
4451 m_isEnumList==g_token->isEnumList && // of the same kind
4452 (g_token->id==-1 || g_token->id>=num) // increasing number (or no number)
4455 doctokenizerYYendAutoList();
4456 DocNode *n=g_nodeStack.pop();
4461 //--------------------------------------------------------------------------
4463 void DocTitle::parse()
4465 DBG(("DocTitle::parse() start\n"));
4466 g_nodeStack.push(this);
4467 doctokenizerYYsetStateTitle();
4469 while ((tok=doctokenizerYYlex()))
4471 if (!defaultHandleToken(this,tok,m_children))
4476 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal command %s as part of a title section",
4477 qPrint(g_token->name));
4480 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
4481 qPrint(g_token->name));
4484 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
4490 doctokenizerYYsetStatePara();
4491 handlePendingStyleCommands(this,m_children);
4492 DBG(("DocTitle::parse() end\n"));
4493 DocNode *n = g_nodeStack.pop();
4497 void DocTitle::parseFromString(const QCString &text)
4499 m_children.append(new DocWord(this,text));
4502 //--------------------------------------------------------------------------
4504 DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) :
4511 DocSimpleSect::~DocSimpleSect()
4516 void DocSimpleSect::accept(DocVisitor *v)
4519 if (m_title) m_title->accept(v);
4520 QListIterator<DocNode> cli(m_children);
4522 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
4526 int DocSimpleSect::parse(bool userTitle,bool needsSeparator)
4528 DBG(("DocSimpleSect::parse() start\n"));
4529 g_nodeStack.push(this);
4531 // handle case for user defined title
4534 m_title = new DocTitle(this);
4538 // add new paragraph as child
4539 DocPara *par = new DocPara(this);
4540 if (m_children.isEmpty())
4546 ASSERT(m_children.getLast()->kind()==DocNode::Kind_Para);
4547 ((DocPara *)m_children.getLast())->markLast(FALSE);
4550 if (needsSeparator) m_children.append(new DocSimpleSectSep(this));
4551 m_children.append(par);
4553 // parse the contents of the paragraph
4554 int retval = par->parse();
4556 DBG(("DocSimpleSect::parse() end retval=%d\n",retval));
4557 DocNode *n=g_nodeStack.pop();
4559 return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec
4562 int DocSimpleSect::parseRcs()
4564 DBG(("DocSimpleSect::parseRcs() start\n"));
4565 g_nodeStack.push(this);
4567 m_title = new DocTitle(this);
4568 m_title->parseFromString(g_token->name);
4570 QCString text = g_token->text;
4571 docParserPushContext(); // this will create a new g_token
4572 internalValidatingParseDoc(this,m_children,text);
4573 docParserPopContext(); // this will restore the old g_token
4575 DBG(("DocSimpleSect::parseRcs()\n"));
4576 DocNode *n=g_nodeStack.pop();
4581 int DocSimpleSect::parseXml()
4583 DBG(("DocSimpleSect::parse() start\n"));
4584 g_nodeStack.push(this);
4586 int retval = RetVal_OK;
4589 // add new paragraph as child
4590 DocPara *par = new DocPara(this);
4591 if (m_children.isEmpty())
4597 ASSERT(m_children.getLast()->kind()==DocNode::Kind_Para);
4598 ((DocPara *)m_children.getLast())->markLast(FALSE);
4601 m_children.append(par);
4603 // parse the contents of the paragraph
4604 retval = par->parse();
4605 if (retval == 0) break;
4606 if (retval == RetVal_CloseXml)
4613 DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
4614 DocNode *n=g_nodeStack.pop();
4619 void DocSimpleSect::appendLinkWord(const QCString &word)
4622 if (m_children.isEmpty() || m_children.getLast()->kind()!=DocNode::Kind_Para)
4624 p = new DocPara(this);
4625 m_children.append(p);
4629 p = (DocPara *)m_children.getLast();
4631 // Comma-seperate <seealso> links.
4632 p->injectToken(TK_WORD,",");
4633 p->injectToken(TK_WHITESPACE," ");
4637 p->injectToken(TK_LNKWORD,word);
4641 QCString DocSimpleSect::typeString() const
4645 case Unknown: break;
4646 case See: return "see";
4647 case Return: return "return";
4648 case Author: // fall through
4649 case Authors: return "author";
4650 case Version: return "version";
4651 case Since: return "since";
4652 case Date: return "date";
4653 case Note: return "note";
4654 case Warning: return "warning";
4655 case Pre: return "pre";
4656 case Post: return "post";
4657 case Copyright: return "copyright";
4658 case Invar: return "invariant";
4659 case Remark: return "remark";
4660 case Attention: return "attention";
4661 case User: return "user";
4662 case Rcs: return "rcs";
4667 //--------------------------------------------------------------------------
4669 int DocParamList::parse(const QCString &cmdName)
4671 int retval=RetVal_OK;
4672 DBG(("DocParamList::parse() start\n"));
4673 g_nodeStack.push(this);
4675 QCString saveCmdName = cmdName;
4677 int tok=doctokenizerYYlex();
4678 if (tok!=TK_WHITESPACE)
4680 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
4685 doctokenizerYYsetStateParam();
4686 tok=doctokenizerYYlex();
4687 while (tok==TK_WORD) /* there is a parameter name */
4689 if (m_type==DocParamSect::Param)
4691 int typeSeparator = g_token->name.find('#'); // explicit type position
4692 if (typeSeparator!=-1)
4694 handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator));
4695 g_token->name = g_token->name.mid(typeSeparator+1);
4696 g_hasParamCommand=TRUE;
4697 checkArgumentName(g_token->name,TRUE);
4698 ((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE;
4702 g_hasParamCommand=TRUE;
4703 checkArgumentName(g_token->name,TRUE);
4706 else if (m_type==DocParamSect::RetVal)
4708 g_hasReturnCommand=TRUE;
4709 checkArgumentName(g_token->name,FALSE);
4711 //m_params.append(g_token->name);
4712 handleLinkedWord(this,m_params);
4713 tok=doctokenizerYYlex();
4715 doctokenizerYYsetStatePara();
4716 if (tok==0) /* premature end of comment block */
4718 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
4719 "argument of command %s",qPrint(cmdName));
4723 if (tok!=TK_WHITESPACE) /* premature end of comment block */
4725 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token in comment block while parsing the "
4726 "argument of command %s",qPrint(saveCmdName));
4731 par = new DocPara(this);
4732 m_paragraphs.append(par);
4733 retval = par->parse();
4738 DBG(("DocParamList::parse() end retval=%d\n",retval));
4739 DocNode *n=g_nodeStack.pop();
4744 int DocParamList::parseXml(const QCString ¶mName)
4746 int retval=RetVal_OK;
4747 DBG(("DocParamList::parseXml() start\n"));
4748 g_nodeStack.push(this);
4750 g_token->name = paramName;
4751 if (m_type==DocParamSect::Param)
4753 g_hasParamCommand=TRUE;
4754 checkArgumentName(g_token->name,TRUE);
4756 else if (m_type==DocParamSect::RetVal)
4758 g_hasReturnCommand=TRUE;
4759 checkArgumentName(g_token->name,FALSE);
4762 handleLinkedWord(this,m_params);
4766 DocPara *par = new DocPara(this);
4767 retval = par->parse();
4768 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
4769 // after </para> and before </param>
4774 else // append the paragraph to the list
4776 if (m_paragraphs.isEmpty())
4782 m_paragraphs.getLast()->markLast(FALSE);
4785 m_paragraphs.append(par);
4788 if (retval == 0) break;
4790 } while (retval==RetVal_CloseXml &&
4791 Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
4792 Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM &&
4793 Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
4796 if (retval==0) /* premature end of comment block */
4798 warn_doc_error(g_fileName,doctokenizerYYlineno,"unterminated param or exception tag");
4806 DBG(("DocParamList::parse() end retval=%d\n",retval));
4807 DocNode *n=g_nodeStack.pop();
4812 //--------------------------------------------------------------------------
4814 int DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
4816 int retval=RetVal_OK;
4817 DBG(("DocParamSect::parse() start\n"));
4818 g_nodeStack.push(this);
4822 m_hasInOutSpecifier=TRUE;
4825 DocParamList *pl = new DocParamList(this,m_type,d);
4826 if (m_children.isEmpty())
4833 ASSERT(m_children.getLast()->kind()==DocNode::Kind_ParamList);
4834 ((DocParamList *)m_children.getLast())->markLast(FALSE);
4837 m_children.append(pl);
4840 retval = pl->parseXml(cmdName);
4844 retval = pl->parse(cmdName);
4846 if (retval==RetVal_EndParBlock)
4851 DBG(("DocParamSect::parse() end retval=%d\n",retval));
4852 DocNode *n=g_nodeStack.pop();
4857 //--------------------------------------------------------------------------
4859 int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
4861 DocSimpleSect *ss=0;
4862 bool needsSeparator = FALSE;
4863 if (!m_children.isEmpty() && // previous element
4864 m_children.getLast()->kind()==Kind_SimpleSect && // was a simple sect
4865 ((DocSimpleSect *)m_children.getLast())->type()==t && // of same type
4866 t!=DocSimpleSect::User) // but not user defined
4868 // append to previous section
4869 ss=(DocSimpleSect *)m_children.getLast();
4870 needsSeparator = TRUE;
4872 else // start new section
4874 ss=new DocSimpleSect(this,t);
4875 m_children.append(ss);
4880 return ss->parseXml();
4884 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
4886 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4889 int DocPara::handleParamSection(const QCString &cmdName,
4890 DocParamSect::Type t,
4891 bool xmlContext=FALSE,
4892 int direction=DocParamSect::Unspecified)
4895 if (!m_children.isEmpty() && // previous element
4896 m_children.getLast()->kind()==Kind_ParamSect && // was a param sect
4897 ((DocParamSect *)m_children.getLast())->type()==t) // of same type
4899 // append to previous section
4900 ps=(DocParamSect *)m_children.getLast();
4902 else // start new section
4904 ps=new DocParamSect(this,t);
4905 m_children.append(ps);
4907 int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
4908 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4911 void DocPara::handleCite()
4913 // get the argument of the cite command.
4914 int tok=doctokenizerYYlex();
4915 if (tok!=TK_WHITESPACE)
4917 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
4921 doctokenizerYYsetStateCite();
4922 tok=doctokenizerYYlex();
4925 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
4926 "argument of command %s\n", qPrint("cite"));
4929 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
4931 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
4932 tokToString(tok),qPrint("cite"));
4935 g_token->sectionId = g_token->name;
4936 DocCite *cite = new DocCite(this,g_token->name,g_context);
4937 m_children.append(cite);
4940 doctokenizerYYsetStatePara();
4943 int DocPara::handleXRefItem()
4945 int retval=doctokenizerYYlex();
4946 ASSERT(retval==TK_WHITESPACE);
4947 doctokenizerYYsetStateXRefItem();
4948 retval=doctokenizerYYlex();
4949 if (retval==RetVal_OK)
4951 DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name);
4954 m_children.append(ref);
4961 doctokenizerYYsetStatePara();
4965 void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t)
4967 DBG(("handleIncludeOperator(%s)\n",qPrint(cmdName)));
4968 int tok=doctokenizerYYlex();
4969 if (tok!=TK_WHITESPACE)
4971 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
4975 doctokenizerYYsetStatePattern();
4976 tok=doctokenizerYYlex();
4977 doctokenizerYYsetStatePara();
4980 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
4981 "argument of command %s", qPrint(cmdName));
4984 else if (tok!=TK_WORD)
4986 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
4987 tokToString(tok),qPrint(cmdName));
4990 DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
4991 QListIterator<DocNode> it(m_children);
4992 DocNode *n1 = it.toLast();
4994 DocNode *n2 = n1!=0 ? it.current() : 0;
4995 bool isFirst = n1==0 || // no last node
4996 (n1->kind()!=DocNode::Kind_IncOperator &&
4997 n1->kind()!=DocNode::Kind_WhiteSpace
4998 ) || // last node is not operator or whitespace
4999 (n1->kind()==DocNode::Kind_WhiteSpace &&
5000 n2!=0 && n2->kind()!=DocNode::Kind_IncOperator
5001 ); // previous not is not operator
5002 op->markFirst(isFirst);
5004 if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator)
5006 ((DocIncOperator *)n1)->markLast(FALSE);
5008 else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace &&
5009 n2!=0 && n2->kind()==DocNode::Kind_IncOperator
5012 ((DocIncOperator *)n2)->markLast(FALSE);
5014 m_children.append(op);
5018 void DocPara::handleImage(const QCString &cmdName)
5020 int tok=doctokenizerYYlex();
5021 if (tok!=TK_WHITESPACE)
5023 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5027 tok=doctokenizerYYlex();
5028 if (tok!=TK_WORD && tok!=TK_LNKWORD)
5030 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5031 tokToString(tok),qPrint(cmdName));
5034 tok=doctokenizerYYlex();
5035 if (tok!=TK_WHITESPACE)
5037 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5042 QCString imgType = g_token->name.lower();
5043 if (imgType=="html") t=DocImage::Html;
5044 else if (imgType=="latex") t=DocImage::Latex;
5045 else if (imgType=="docbook") t=DocImage::DocBook;
5046 else if (imgType=="rtf") t=DocImage::Rtf;
5049 warn_doc_error(g_fileName,doctokenizerYYlineno,"image type %s specified as the first argument of "
5051 qPrint(imgType),qPrint(cmdName));
5054 doctokenizerYYsetStateFile();
5055 tok=doctokenizerYYlex();
5056 doctokenizerYYsetStatePara();
5059 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5060 tokToString(tok),qPrint(cmdName));
5063 HtmlAttribList attrList;
5064 DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t);
5065 m_children.append(img);
5070 void DocPara::handleFile(const QCString &cmdName)
5072 int tok=doctokenizerYYlex();
5073 if (tok!=TK_WHITESPACE)
5075 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5079 doctokenizerYYsetStateFile();
5080 tok=doctokenizerYYlex();
5081 doctokenizerYYsetStatePara();
5084 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5085 tokToString(tok),qPrint(cmdName));
5088 QCString name = g_token->name;
5089 T *df = new T(this,name,g_context);
5090 m_children.append(df);
5094 void DocPara::handleVhdlFlow()
5096 DocVhdlFlow *vf = new DocVhdlFlow(this);
5097 m_children.append(vf);
5101 void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
5103 int tok=doctokenizerYYlex();
5104 if (tok!=TK_WHITESPACE)
5106 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5110 doctokenizerYYsetStateLink();
5111 tok=doctokenizerYYlex();
5114 warn_doc_error(g_fileName,doctokenizerYYlineno,"%s as the argument of %s",
5115 tokToString(tok),qPrint(cmdName));
5118 doctokenizerYYsetStatePara();
5119 DocLink *lnk = new DocLink(this,g_token->name);
5120 m_children.append(lnk);
5121 QCString leftOver = lnk->parse(isJavaLink);
5122 if (!leftOver.isEmpty())
5124 m_children.append(new DocWord(this,leftOver));
5128 void DocPara::handleRef(const QCString &cmdName)
5130 DBG(("handleRef(%s)\n",qPrint(cmdName)));
5131 int tok=doctokenizerYYlex();
5132 if (tok!=TK_WHITESPACE)
5134 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5138 doctokenizerYYsetStateRef();
5139 tok=doctokenizerYYlex(); // get the reference id
5143 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5144 tokToString(tok),qPrint(cmdName));
5147 ref = new DocRef(this,g_token->name,g_context);
5148 m_children.append(ref);
5151 doctokenizerYYsetStatePara();
5154 void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
5156 DBG(("handleInclude(%s)\n",qPrint(cmdName)));
5157 int tok=doctokenizerYYlex();
5158 if (tok!=TK_WHITESPACE)
5160 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5164 doctokenizerYYsetStateFile();
5165 tok=doctokenizerYYlex();
5166 doctokenizerYYsetStatePara();
5169 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
5170 "argument of command %s",qPrint(cmdName));
5173 else if (tok!=TK_WORD)
5175 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5176 tokToString(tok),qPrint(cmdName));
5179 QCString fileName = g_token->name;
5181 if (t==DocInclude::Snippet || t==DocInclude::SnipWithLines || t==DocInclude::SnippetDoc)
5183 if (fileName == "this") fileName=g_fileName;
5184 doctokenizerYYsetStateSnippet();
5185 tok=doctokenizerYYlex();
5186 doctokenizerYYsetStatePara();
5189 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected block identifier, but found token %s instead while parsing the %s command",
5190 tokToString(tok),qPrint(cmdName));
5193 blockId = "["+g_token->name+"]";
5196 // This is the only place to handle the \includedoc and \snippetdoc commands,
5197 // as the content is included here as if it is really here.
5198 if (t==DocInclude::IncludeDoc || t==DocInclude::SnippetDoc)
5202 readTextFileByName(fileName,inc_text);
5203 if (t==DocInclude::SnippetDoc)
5205 inc_line = lineBlock(inc_text, blockId);
5206 inc_text = extractBlock(inc_text, blockId);
5208 docParserPushContext();
5209 g_fileName = fileName;
5210 doctokenizerYYlineno=inc_line;
5211 internalValidatingParseDoc(this,m_children,inc_text);
5212 docParserPopContext();
5216 DocInclude *inc = new DocInclude(this,fileName,g_context,t,g_isExample,g_exampleName,blockId);
5217 m_children.append(inc);
5222 void DocPara::handleSection(const QCString &cmdName)
5224 // get the argument of the section command.
5225 int tok=doctokenizerYYlex();
5226 if (tok!=TK_WHITESPACE)
5228 warn_doc_error(g_fileName,doctokenizerYYlineno,"expected whitespace after %s command",
5232 tok=doctokenizerYYlex();
5235 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected end of comment block while parsing the "
5236 "argument of command %s\n", qPrint(cmdName));
5239 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
5241 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected token %s as the argument of %s",
5242 tokToString(tok),qPrint(cmdName));
5245 g_token->sectionId = g_token->name;
5246 doctokenizerYYsetStateSkipTitle();
5247 doctokenizerYYlex();
5248 doctokenizerYYsetStatePara();
5251 int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
5253 DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level);
5254 m_children.append(header);
5255 int retval = header->parse();
5256 return (retval==RetVal_OK) ? TK_NEWPARA : retval;
5259 // For XML tags whose content is stored in attributes rather than
5260 // contained within the element, we need a way to inject the attribute
5261 // text into the current paragraph.
5262 bool DocPara::injectToken(int tok,const QCString &tokText)
5264 g_token->name = tokText;
5265 return defaultHandleToken(this,tok,m_children);
5268 int DocPara::handleStartCode()
5270 int retval = doctokenizerYYlex();
5271 QCString lang = g_token->name;
5272 if (!lang.isEmpty() && lang.at(0)!='.')
5278 g_token->verb = substitute(substitute(g_token->verb,"<","<"),">",">");
5280 // search for the first non-whitespace line, index is stored in li
5281 int i=0,li=0,l=g_token->verb.length();
5282 while (i<l && (g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n'))
5284 if (g_token->verb.at(i)=='\n') li=i+1;
5287 m_children.append(new DocVerbatim(this,g_context,stripIndentation(g_token->verb.mid(li)),DocVerbatim::Code,g_isExample,g_exampleName,FALSE,lang));
5288 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"code section ended without end marker");
5289 doctokenizerYYsetStatePara();
5293 void DocPara::handleInheritDoc()
5295 if (g_memberDef) // inheriting docs from a member
5297 MemberDef *reMd = g_memberDef->reimplements();
5298 if (reMd) // member from which was inherited.
5300 MemberDef *thisMd = g_memberDef;
5301 //printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data());
5302 docParserPushContext();
5303 g_scope=reMd->getOuterScope();
5304 if (g_scope!=Doxygen::globalScope)
5306 g_context=g_scope->name();
5309 g_styleStack.clear();
5310 g_nodeStack.clear();
5311 g_copyStack.append(reMd);
5312 internalValidatingParseDoc(this,m_children,reMd->briefDescription());
5313 internalValidatingParseDoc(this,m_children,reMd->documentation());
5314 g_copyStack.remove(reMd);
5315 docParserPopContext(TRUE);
5316 g_memberDef = thisMd;
5322 int DocPara::handleCommand(const QCString &cmdName)
5324 DBG(("handleCommand(%s)\n",qPrint(cmdName)));
5325 int retval = RetVal_OK;
5326 int cmdId = Mappers::cmdMapper->map(cmdName);
5330 warn_doc_error(g_fileName,doctokenizerYYlineno,"Found unknown command `\\%s'",qPrint(cmdName));
5333 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
5334 retval=handleStyleArgument(this,m_children,cmdName);
5335 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
5336 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5339 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
5340 retval=handleStyleArgument(this,m_children,cmdName);
5341 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
5342 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5345 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
5346 retval=handleStyleArgument(this,m_children,cmdName);
5347 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
5348 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5351 m_children.append(new DocSymbol(this,DocSymbol::Sym_BSlash));
5354 m_children.append(new DocSymbol(this,DocSymbol::Sym_At));
5357 m_children.append(new DocSymbol(this,DocSymbol::Sym_Less));
5360 m_children.append(new DocSymbol(this,DocSymbol::Sym_Greater));
5363 m_children.append(new DocSymbol(this,DocSymbol::Sym_Amp));
5366 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dollar));
5369 m_children.append(new DocSymbol(this,DocSymbol::Sym_Hash));
5372 m_children.append(new DocSymbol(this,DocSymbol::Sym_Pipe));
5375 m_children.append(new DocSymbol(this,DocSymbol::Sym_DoubleColon));
5378 m_children.append(new DocSymbol(this,DocSymbol::Sym_Percent));
5381 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5382 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5385 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5386 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5387 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5390 m_children.append(new DocSymbol(this,DocSymbol::Sym_Quot));
5393 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dot));
5396 m_children.append(new DocSymbol(this,DocSymbol::Sym_Plus));
5399 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
5403 retval = handleSimpleSection(DocSimpleSect::See);
5407 retval = handleSimpleSection(DocSimpleSect::Return);
5408 g_hasReturnCommand=TRUE;
5411 retval = handleSimpleSection(DocSimpleSect::Author);
5414 retval = handleSimpleSection(DocSimpleSect::Authors);
5417 retval = handleSimpleSection(DocSimpleSect::Version);
5420 retval = handleSimpleSection(DocSimpleSect::Since);
5423 retval = handleSimpleSection(DocSimpleSect::Date);
5426 retval = handleSimpleSection(DocSimpleSect::Note);
5429 retval = handleSimpleSection(DocSimpleSect::Warning);
5432 retval = handleSimpleSection(DocSimpleSect::Pre);
5435 retval = handleSimpleSection(DocSimpleSect::Post);
5438 retval = handleSimpleSection(DocSimpleSect::Copyright);
5441 retval = handleSimpleSection(DocSimpleSect::Invar);
5444 retval = handleSimpleSection(DocSimpleSect::Remark);
5447 retval = handleSimpleSection(DocSimpleSect::Attention);
5450 retval = handleSimpleSection(DocSimpleSect::User);
5454 DocSimpleList *sl=new DocSimpleList(this);
5455 m_children.append(sl);
5456 retval = sl->parse();
5461 handleSection(cmdName);
5462 retval = RetVal_Section;
5465 case CMD_SUBSECTION:
5467 handleSection(cmdName);
5468 retval = RetVal_Subsection;
5471 case CMD_SUBSUBSECTION:
5473 handleSection(cmdName);
5474 retval = RetVal_Subsubsection;
5479 handleSection(cmdName);
5480 retval = RetVal_Paragraph;
5485 doctokenizerYYsetStateCode();
5486 retval = handleStartCode();
5491 doctokenizerYYsetStateHtmlOnly();
5492 retval = doctokenizerYYlex();
5493 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName,g_token->name=="block"));
5494 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"htmlonly section ended without end marker");
5495 doctokenizerYYsetStatePara();
5500 doctokenizerYYsetStateManOnly();
5501 retval = doctokenizerYYlex();
5502 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
5503 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"manonly section ended without end marker");
5504 doctokenizerYYsetStatePara();
5509 doctokenizerYYsetStateRtfOnly();
5510 retval = doctokenizerYYlex();
5511 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::RtfOnly,g_isExample,g_exampleName));
5512 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"rtfonly section ended without end marker");
5513 doctokenizerYYsetStatePara();
5518 doctokenizerYYsetStateLatexOnly();
5519 retval = doctokenizerYYlex();
5520 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
5521 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"latexonly section ended without end marker");
5522 doctokenizerYYsetStatePara();
5527 doctokenizerYYsetStateXmlOnly();
5528 retval = doctokenizerYYlex();
5529 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
5530 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"xmlonly section ended without end marker");
5531 doctokenizerYYsetStatePara();
5536 doctokenizerYYsetStateDbOnly();
5537 retval = doctokenizerYYlex();
5538 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::DocbookOnly,g_isExample,g_exampleName));
5539 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"docbookonly section ended without end marker",doctokenizerYYlineno);
5540 doctokenizerYYsetStatePara();
5545 doctokenizerYYsetStateVerbatim();
5546 retval = doctokenizerYYlex();
5547 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName));
5548 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"verbatim section ended without end marker");
5549 doctokenizerYYsetStatePara();
5554 DocVerbatim *dv = new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName);
5555 doctokenizerYYsetStatePara();
5556 QCString width,height;
5557 defaultHandleTitleAndSize(CMD_DOT,dv,dv->children(),width,height);
5558 doctokenizerYYsetStateDot();
5559 retval = doctokenizerYYlex();
5560 dv->setText(g_token->verb);
5561 dv->setWidth(width);
5562 dv->setHeight(height);
5563 m_children.append(dv);
5564 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"dot section ended without end marker");
5565 doctokenizerYYsetStatePara();
5570 DocVerbatim *dv = new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName);
5571 doctokenizerYYsetStatePara();
5572 QCString width,height;
5573 defaultHandleTitleAndSize(CMD_MSC,dv,dv->children(),width,height);
5574 doctokenizerYYsetStateMsc();
5575 retval = doctokenizerYYlex();
5576 dv->setText(g_token->verb);
5577 dv->setWidth(width);
5578 dv->setHeight(height);
5579 m_children.append(dv);
5580 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"msc section ended without end marker");
5581 doctokenizerYYsetStatePara();
5586 static QCString jarPath = Config_getString(PLANTUML_JAR_PATH);
5587 doctokenizerYYsetStatePlantUMLOpt();
5588 retval = doctokenizerYYlex();
5589 QCString plantFile(g_token->sectionId);
5590 DocVerbatim *dv = new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::PlantUML,FALSE,plantFile);
5591 doctokenizerYYsetStatePara();
5592 QCString width,height;
5593 defaultHandleTitleAndSize(CMD_STARTUML,dv,dv->children(),width,height);
5594 doctokenizerYYsetStatePlantUML();
5595 retval = doctokenizerYYlex();
5596 dv->setText(g_token->verb);
5597 dv->setWidth(width);
5598 dv->setHeight(height);
5599 if (jarPath.isEmpty())
5601 warn_doc_error(g_fileName,doctokenizerYYlineno,"ignoring \\startuml command because PLANTUML_JAR_PATH is not set");
5606 m_children.append(dv);
5608 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"startuml section ended without end marker");
5609 doctokenizerYYsetStatePara();
5612 case CMD_ENDPARBLOCK:
5613 retval=RetVal_EndParBlock;
5616 case CMD_ENDHTMLONLY:
5617 case CMD_ENDMANONLY:
5618 case CMD_ENDRTFONLY:
5619 case CMD_ENDLATEXONLY:
5620 case CMD_ENDXMLONLY:
5623 case CMD_ENDVERBATIM:
5627 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5630 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
5633 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir);
5636 retval = handleParamSection(cmdName,DocParamSect::RetVal);
5639 retval = handleParamSection(cmdName,DocParamSect::Exception);
5642 retval = handleXRefItem();
5646 DocLineBreak *lb = new DocLineBreak(this);
5647 m_children.append(lb);
5652 DocAnchor *anchor = handleAnchor(this);
5655 m_children.append(anchor);
5661 DocIndexEntry *ie = new DocIndexEntry(this,
5662 g_scope!=Doxygen::globalScope?g_scope:0,
5664 m_children.append(ie);
5665 retval = ie->parse();
5669 retval = RetVal_Internal;
5671 case CMD_ENDINTERNAL:
5672 retval = RetVal_EndInternal;
5676 DocParBlock *block = new DocParBlock(this);
5677 m_children.append(block);
5678 retval = block->parse();
5681 case CMD_COPYDOC: // fall through
5682 case CMD_COPYBRIEF: // fall through
5683 case CMD_COPYDETAILS:
5684 //retval = RetVal_CopyDoc;
5685 // these commands should already be resolved by processCopyDoc()
5688 handleInclude(cmdName,DocInclude::Include);
5690 case CMD_INCWITHLINES:
5691 handleInclude(cmdName,DocInclude::IncWithLines);
5693 case CMD_DONTINCLUDE:
5694 handleInclude(cmdName,DocInclude::DontInclude);
5696 case CMD_HTMLINCLUDE:
5697 handleInclude(cmdName,DocInclude::HtmlInclude);
5699 case CMD_LATEXINCLUDE:
5700 handleInclude(cmdName,DocInclude::LatexInclude);
5702 case CMD_VERBINCLUDE:
5703 handleInclude(cmdName,DocInclude::VerbInclude);
5706 handleInclude(cmdName,DocInclude::Snippet);
5708 case CMD_SNIPWITHLINES:
5709 handleInclude(cmdName,DocInclude::SnipWithLines);
5711 case CMD_INCLUDEDOC:
5712 handleInclude(cmdName,DocInclude::IncludeDoc);
5714 case CMD_SNIPPETDOC:
5715 handleInclude(cmdName,DocInclude::SnippetDoc);
5718 handleIncludeOperator(cmdName,DocIncOperator::Skip);
5721 handleIncludeOperator(cmdName,DocIncOperator::Until);
5724 handleIncludeOperator(cmdName,DocIncOperator::SkipLine);
5727 handleIncludeOperator(cmdName,DocIncOperator::Line);
5730 handleImage(cmdName);
5733 handleFile<DocDotFile>(cmdName);
5739 handleFile<DocMscFile>(cmdName);
5742 handleFile<DocDiaFile>(cmdName);
5745 handleLink(cmdName,FALSE);
5748 handleLink(cmdName,TRUE);
5753 case CMD_REF: // fall through
5757 case CMD_SECREFLIST:
5759 DocSecRefList *list = new DocSecRefList(this);
5760 m_children.append(list);
5764 case CMD_SECREFITEM:
5765 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5767 case CMD_ENDSECREFLIST:
5768 warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5772 DocFormula *form=new DocFormula(this,g_token->id);
5773 m_children.append(form);
5776 //case CMD_LANGSWITCH:
5777 // retval = handleLanguageSwitch();
5779 case CMD_INTERNALREF:
5780 //warn_doc_error(g_fileName,doctokenizerYYlineno,"unexpected command %s",qPrint(g_token->name));
5782 DocInternalRef *ref = handleInternalRef(this);
5785 m_children.append(ref);
5788 doctokenizerYYsetStatePara();
5791 case CMD_INHERITDOC:
5795 // we should not get here!
5799 INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec ||
5800 retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA ||
5801 retval==RetVal_Section || retval==RetVal_EndList ||
5802 retval==RetVal_Internal || retval==RetVal_SwitchLang ||
5803 retval==RetVal_EndInternal
5805 DBG(("handleCommand(%s) end retval=%x\n",qPrint(cmdName),retval));
5809 static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
5810 const char *attrName,
5814 HtmlAttribListIterator li(tagHtmlAttribs);
5816 for (li.toFirst();(opt=li.current());++li)
5818 if (opt->name==attrName)
5820 *result = opt->value;
5827 int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
5829 DBG(("handleHtmlStartTag(%s,%d)\n",qPrint(tagName),tagHtmlAttribs.count()));
5830 int retval=RetVal_OK;
5831 int tagId = Mappers::htmlTagMapper->map(tagName);
5832 if (g_token->emptyTag && !(tagId&XML_CmdMask) &&
5833 tagId!=HTML_UNKNOWN && tagId!=HTML_IMG && tagId!=HTML_BR)
5835 warn_doc_error(g_fileName,doctokenizerYYlineno,"HTML tags may not use the 'empty tag' XHTML syntax.");
5841 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered);
5842 m_children.append(list);
5843 retval=list->parse();
5848 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered);
5849 m_children.append(list);
5850 retval=list->parse();
5854 if (!insideUL(this) && !insideOL(this))
5856 warn_doc_error(g_fileName,doctokenizerYYlineno,"lonely <li> tag found");
5860 retval=RetVal_ListItem;
5864 handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
5867 if (/*getLanguageFromFileName(g_fileName)==SrcLangExt_CSharp ||*/ g_xmlComment)
5868 // for C# source or inside a <summary> or <remark> section we
5869 // treat <code> as an XML tag (so similar to @code)
5871 doctokenizerYYsetStateXmlCode();
5872 retval = handleStartCode();
5874 else // normal HTML markup
5876 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
5880 handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
5883 handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs);
5886 handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs);
5889 handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs);
5892 handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs);
5895 handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs);
5898 handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs);
5901 handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
5902 setInsidePreformatted(TRUE);
5903 doctokenizerYYsetInsidePre(TRUE);
5910 DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs);
5911 m_children.append(list);
5912 retval=list->parse();
5916 retval = RetVal_DescTitle;
5919 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag <dd> found");
5923 DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
5924 m_children.append(table);
5925 retval=table->parse();
5929 retval = RetVal_TableRow;
5932 retval = RetVal_TableCell;
5935 retval = RetVal_TableHCell;
5938 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag <caption> found");
5942 DocLineBreak *lb = new DocLineBreak(this);
5943 m_children.append(lb);
5948 DocHorRuler *hr = new DocHorRuler(this);
5949 m_children.append(hr);
5953 retval=handleAHref(this,m_children,tagHtmlAttribs);
5956 retval=handleHtmlHeader(tagHtmlAttribs,1);
5959 retval=handleHtmlHeader(tagHtmlAttribs,2);
5962 retval=handleHtmlHeader(tagHtmlAttribs,3);
5965 retval=handleHtmlHeader(tagHtmlAttribs,4);
5968 retval=handleHtmlHeader(tagHtmlAttribs,5);
5971 retval=handleHtmlHeader(tagHtmlAttribs,6);
5975 handleImg(this,m_children,tagHtmlAttribs);
5978 case HTML_BLOCKQUOTE:
5980 DocHtmlBlockQuote *block = new DocHtmlBlockQuote(this,tagHtmlAttribs);
5981 m_children.append(block);
5982 retval = block->parse();
5993 if (!m_children.isEmpty())
5995 retval = TK_NEWPARA;
5998 case XML_DESCRIPTION:
5999 if (insideTable(this))
6001 retval=RetVal_TableCell;
6005 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
6012 if (findAttribute(tagHtmlAttribs,"name",¶mName))
6014 if (paramName.isEmpty())
6016 if (Config_getBool(WARN_NO_PARAMDOC))
6018 warn_doc_error(g_fileName,doctokenizerYYlineno,"empty 'name' attribute for <param%s> tag.",tagId==XML_PARAM?"":"type");
6023 retval = handleParamSection(paramName,
6024 tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam,
6030 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'name' attribute from <param%s> tag.",tagId==XML_PARAM?"":"type");
6035 case XML_TYPEPARAMREF:
6038 if (findAttribute(tagHtmlAttribs,"name",¶mName))
6040 //printf("paramName=%s\n",paramName.data());
6041 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
6042 m_children.append(new DocWord(this,paramName));
6043 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
6044 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
6048 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type");
6055 QCString exceptName;
6056 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
6058 unescapeCRef(exceptName);
6059 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
6063 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'cref' attribute from <exception> tag.");
6068 case XML_LISTHEADER:
6069 if (insideTable(this))
6071 retval=RetVal_TableRow;
6073 else if (insideUL(this) || insideOL(this))
6075 retval=RetVal_ListItem;
6079 warn_doc_error(g_fileName,doctokenizerYYlineno,"lonely <item> tag found");
6084 retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
6085 g_hasReturnCommand=TRUE;
6088 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
6089 if (insideTable(this))
6091 retval=RetVal_TableCell;
6095 // I'm not sure if <see> is the same as <seealso> or if it
6096 // should you link a member without producing a section. The
6097 // C# specification is extremely vague about this (but what else
6098 // can we expect from Microsoft...)
6101 //printf("XML_SEE: empty tag=%d\n",g_token->emptyTag);
6102 if (findAttribute(tagHtmlAttribs,"cref",&cref))
6105 if (g_token->emptyTag) // <see cref="..."/> style
6107 bool inSeeBlock = g_inSeeBlock;
6108 g_token->name = cref;
6109 g_inSeeBlock = TRUE;
6110 handleLinkedWord(this,m_children,TRUE);
6111 g_inSeeBlock = inSeeBlock;
6113 else // <see cref="...">...</see> style
6115 //DocRef *ref = new DocRef(this,cref);
6116 //m_children.append(ref);
6118 doctokenizerYYsetStatePara();
6119 DocLink *lnk = new DocLink(this,cref);
6120 m_children.append(lnk);
6121 QCString leftOver = lnk->parse(FALSE,TRUE);
6122 if (!leftOver.isEmpty())
6124 m_children.append(new DocWord(this,leftOver));
6128 else if (findAttribute(tagHtmlAttribs,"langword",&cref)) // <see langword="..."/> or <see langworld="..."></see>
6130 doctokenizerYYsetStatePara();
6131 DocLink *lnk = new DocLink(this,cref);
6132 m_children.append(lnk);
6133 QCString leftOver = lnk->parse(FALSE,TRUE);
6134 if (!leftOver.isEmpty())
6136 m_children.append(new DocWord(this,leftOver));
6141 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'cref' or 'langword' attribute from <see> tag.");
6149 if (findAttribute(tagHtmlAttribs,"cref",&cref))
6152 // Look for an existing "see" section
6153 DocSimpleSect *ss=0;
6154 QListIterator<DocNode> cli(m_children);
6156 for (cli.toFirst();(n=cli.current());++cli)
6158 if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
6160 ss = (DocSimpleSect *)n;
6164 if (!ss) // start new section
6166 ss=new DocSimpleSect(this,DocSimpleSect::See);
6167 m_children.append(ss);
6170 ss->appendLinkWord(cref);
6175 warn_doc_error(g_fileName,doctokenizerYYlineno,"Missing 'cref' attribute from <seealso> tag.");
6182 findAttribute(tagHtmlAttribs,"type",&type);
6183 DocHtmlList::Type listType = DocHtmlList::Unordered;
6184 HtmlAttribList emptyList;
6187 listType=DocHtmlList::Ordered;
6191 DocHtmlTable *table = new DocHtmlTable(this,emptyList);
6192 m_children.append(table);
6193 retval=table->parseXml();
6197 DocHtmlList *list = new DocHtmlList(this,emptyList,listType);
6198 m_children.append(list);
6199 retval=list->parseXml();
6204 case XML_PERMISSION:
6205 // These tags are defined in .Net but are currently unsupported
6209 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported xml/html tag <%s> found", qPrint(tagName));
6210 m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
6212 case XML_INHERITDOC:
6216 // we should not get here!
6223 int DocPara::handleHtmlEndTag(const QCString &tagName)
6225 DBG(("handleHtmlEndTag(%s)\n",qPrint(tagName)));
6226 int tagId = Mappers::htmlTagMapper->map(tagName);
6227 int retval=RetVal_OK;
6231 if (!insideUL(this))
6233 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </ul> tag without matching <ul>");
6237 retval=RetVal_EndList;
6241 if (!insideOL(this))
6243 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </ol> tag without matching <ol>");
6247 retval=RetVal_EndList;
6251 if (!insideLI(this))
6253 warn_doc_error(g_fileName,doctokenizerYYlineno,"found </li> tag without matching <li>");
6257 // ignore </li> tags
6260 case HTML_BLOCKQUOTE:
6261 retval=RetVal_EndBlockQuote;
6264 // if (!insidePRE(this))
6266 // warn_doc_error(g_fileName,doctokenizerYYlineno,"found </pre> tag without matching <pre>");
6270 // retval=RetVal_EndPre;
6274 handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
6277 handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
6280 handleStyleLeave(this,m_children,DocStyleChange::Italic,"em");
6283 handleStyleLeave(this,m_children,DocStyleChange::Div,"div");
6286 handleStyleLeave(this,m_children,DocStyleChange::Span,"span");
6289 handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub");
6292 handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup");
6295 handleStyleLeave(this,m_children,DocStyleChange::Center,"center");
6298 handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
6301 handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
6302 setInsidePreformatted(FALSE);
6303 doctokenizerYYsetInsidePre(FALSE);
6309 retval=RetVal_EndDesc;
6318 retval=RetVal_EndTable;
6330 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </caption> found");
6333 warn_doc_error(g_fileName,doctokenizerYYlineno,"Illegal </br> tag found\n");
6336 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h1> found");
6339 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h2> found");
6342 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h3> found");
6345 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h4> found");
6348 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h5> found");
6351 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </h6> found");
6354 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </img> found");
6357 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </hr> found");
6360 //warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected tag </a> found");
6361 // ignore </a> tag (can be part of <a name=...></a>
6365 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
6379 case XML_INHERITDOC:
6380 retval = RetVal_CloseXml;
6383 handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
6386 case XML_LISTHEADER:
6388 case XML_PERMISSION:
6389 case XML_DESCRIPTION:
6391 case XML_TYPEPARAMREF:
6392 // These tags are defined in .Net but are currently unsupported
6395 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported xml/html tag </%s> found", qPrint(tagName));
6396 m_children.append(new DocWord(this,"</"+tagName+">"));
6399 // we should not get here!
6400 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",qPrint(tagName));
6407 int DocPara::parse()
6409 DBG(("DocPara::parse() start\n"));
6410 g_nodeStack.push(this);
6411 // handle style commands "inherited" from the previous paragraph
6412 handleInitialStyleCommands(this,m_children);
6415 while ((tok=doctokenizerYYlex())) // get the next token
6418 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
6419 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
6420 tok==TK_COMMAND || tok==TK_HTMLTAG
6423 DBG((" name=%s",qPrint(g_token->name)));
6429 m_children.append(new DocWord(this,g_token->name));
6432 handleLinkedWord(this,m_children);
6435 m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr));
6439 // prevent leading whitespace and collapse multiple whitespace areas
6441 if (insidePRE(this) || // all whitespace is relevant
6443 // remove leading whitespace
6444 !m_children.isEmpty() &&
6445 // and whitespace after certain constructs
6446 (k=m_children.getLast()->kind())!=DocNode::Kind_HtmlDescList &&
6447 k!=DocNode::Kind_HtmlTable &&
6448 k!=DocNode::Kind_HtmlList &&
6449 k!=DocNode::Kind_SimpleSect &&
6450 k!=DocNode::Kind_AutoList &&
6451 k!=DocNode::Kind_SimpleList &&
6452 /*k!=DocNode::Kind_Verbatim &&*/
6453 k!=DocNode::Kind_HtmlHeader &&
6454 k!=DocNode::Kind_HtmlBlockQuote &&
6455 k!=DocNode::Kind_ParamSect &&
6456 k!=DocNode::Kind_XRefItem
6460 m_children.append(new DocWhiteSpace(this,g_token->chars));
6466 DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind()));
6467 DocNode *n=parent();
6468 while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent();
6469 if (n) // we found an auto list up in the hierarchy
6471 DocAutoList *al = (DocAutoList *)n;
6472 DBG(("previous list item at %d\n",al->indent()));
6473 if (al->indent()>=g_token->indent)
6474 // new item at the same or lower indent level
6481 // determine list depth
6486 if (n->kind() == DocNode::Kind_AutoList &&
6487 ((DocAutoList*)n)->isEnumList()) depth++;
6491 // first item or sub list => create new list
6495 al = new DocAutoList(this,g_token->indent,
6496 g_token->isEnumList,depth);
6497 m_children.append(al);
6498 retval = al->parse();
6499 } while (retval==TK_LISTITEM && // new list
6500 al->indent()==g_token->indent // at same indent level
6503 // check the return value
6504 if (retval==RetVal_SimpleSec) // auto list ended due to simple section command
6506 // Reparse the token that ended the section at this level,
6507 // so a new simple section will be started at this level.
6508 // This is the same as unputting the last read token and continuing.
6509 g_token->name = g_token->simpleSectName;
6510 if (g_token->name.left(4)=="rcs:") // RCS section
6512 g_token->name = g_token->name.mid(4);
6513 g_token->text = g_token->simpleSectText;
6516 else // other section
6520 DBG(("reparsing command %s\n",qPrint(g_token->name)));
6523 else if (retval==TK_ENDLIST)
6525 if (al->indent()>g_token->indent) // end list
6529 else // continue with current paragraph
6533 else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF
6540 DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno));
6541 if (parent()->kind()==DocNode::Kind_AutoListItem)
6543 ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList);
6544 DocAutoList *al = (DocAutoList *)parent()->parent();
6545 if (al->indent()>=g_token->indent)
6547 // end of list marker ends this paragraph
6553 warn_doc_error(g_fileName,doctokenizerYYlineno,"End of list marker found "
6554 "has invalid indent level");
6559 warn_doc_error(g_fileName,doctokenizerYYlineno,"End of list marker found without any preceding "
6565 // see if we have to start a simple section
6566 int cmd = Mappers::cmdMapper->map(g_token->name);
6567 DocNode *n=parent();
6569 n->kind()!=DocNode::Kind_SimpleSect &&
6570 n->kind()!=DocNode::Kind_ParamSect
6575 if (cmd&SIMPLESECT_BIT)
6577 if (n) // already in a simple section
6579 // simple section cannot start in this paragraph, need
6580 // to unwind the stack and remember the command.
6581 g_token->simpleSectName = g_token->name.copy();
6582 retval=RetVal_SimpleSec;
6586 // see if we are in a simple list
6588 while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent();
6593 retval=RetVal_ListItem;
6598 // handle the command
6599 retval=handleCommand(g_token->name);
6600 DBG(("handleCommand returns %x\n",retval));
6602 // check the return value
6603 if (retval==RetVal_SimpleSec)
6605 // Reparse the token that ended the section at this level,
6606 // so a new simple section will be started at this level.
6607 // This is the same as unputting the last read token and continuing.
6608 g_token->name = g_token->simpleSectName;
6609 if (g_token->name.left(4)=="rcs:") // RCS section
6611 g_token->name = g_token->name.mid(4);
6612 g_token->text = g_token->simpleSectText;
6615 else // other section
6619 DBG(("reparsing command %s\n",qPrint(g_token->name)));
6622 else if (retval==RetVal_OK)
6624 // the command ended normally, keep scanning for new tokens.
6627 else if (retval>0 && retval<RetVal_OK)
6629 // the command ended with a new command, reparse this token
6633 else // end of file, end of paragraph, start or end of section
6634 // or some auto list marker
6642 if (!g_token->endTag) // found a start tag
6644 retval = handleHtmlStartTag(g_token->name,g_token->attribs);
6646 else // found an end tag
6648 retval = handleHtmlEndTag(g_token->name);
6650 if (retval==RetVal_OK)
6652 // the command ended normally, keep scanner for new tokens.
6663 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name);
6664 if (s!=DocSymbol::Sym_Unknown)
6666 m_children.append(new DocSymbol(this,s));
6670 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
6671 qPrint(g_token->name));
6680 DocNode *n=parent();
6682 n->kind()!=DocNode::Kind_SimpleSect &&
6683 n->kind()!=DocNode::Kind_ParamSect
6688 if (n) // already in a simple section
6690 // simple section cannot start in this paragraph, need
6691 // to unwind the stack and remember the command.
6692 g_token->simpleSectName = "rcs:"+g_token->name;
6693 g_token->simpleSectText = g_token->text;
6694 retval=RetVal_SimpleSec;
6698 // see if we are in a simple list
6699 DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs);
6700 m_children.append(ss);
6705 warn_doc_error(g_fileName,doctokenizerYYlineno,
6706 "Found unexpected token (id=%x)\n",tok);
6712 handlePendingStyleCommands(this,m_children);
6713 DocNode *n = g_nodeStack.pop();
6715 DBG(("DocPara::parse() end retval=%x\n",retval));
6716 INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM ||
6717 retval==TK_ENDLIST || retval>RetVal_OK
6723 //--------------------------------------------------------------------------
6725 int DocSection::parse()
6727 DBG(("DocSection::parse() start %s level=%d\n",qPrint(g_token->sectionId),m_level));
6728 int retval=RetVal_OK;
6729 g_nodeStack.push(this);
6732 if (!m_id.isEmpty())
6734 sec=Doxygen::sectionDict->find(m_id);
6737 m_file = sec->fileName;
6738 m_anchor = sec->label;
6739 m_title = sec->title;
6740 if (m_title.isEmpty()) m_title = sec->label;
6741 if (g_sectionDict && g_sectionDict->find(m_id)==0)
6743 g_sectionDict->append(m_id,sec);
6748 // first parse any number of paragraphs
6753 DocPara *par = new DocPara(this);
6754 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6755 retval=par->parse();
6756 if (!par->isEmpty())
6758 m_children.append(par);
6765 if (retval==TK_LISTITEM)
6767 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
6769 if (retval==RetVal_Internal)
6771 DocInternal *in = new DocInternal(this);
6772 m_children.append(in);
6773 retval = in->parse(m_level+1);
6774 if (retval==RetVal_EndInternal)
6779 } while (retval!=0 &&
6780 retval!=RetVal_Section &&
6781 retval!=RetVal_Subsection &&
6782 retval!=RetVal_Subsubsection &&
6783 retval!=RetVal_Paragraph &&
6784 retval!=RetVal_EndInternal
6787 if (lastPar) lastPar->markLast();
6789 //printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel);
6791 if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1)
6793 // then parse any number of nested sections
6794 while (retval==RetVal_Subsection) // more sections follow
6796 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6797 DocSection *s=new DocSection(this,
6798 QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6799 m_children.append(s);
6800 retval = s->parse();
6803 else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2)
6805 // then parse any number of nested sections
6806 while (retval==RetVal_Subsubsection) // more sections follow
6808 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6809 DocSection *s=new DocSection(this,
6810 QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6811 m_children.append(s);
6812 retval = s->parse();
6815 else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3))
6817 // then parse any number of nested sections
6818 while (retval==RetVal_Paragraph) // more sections follow
6820 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6821 DocSection *s=new DocSection(this,
6822 QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6823 m_children.append(s);
6824 retval = s->parse();
6827 else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) ||
6828 (m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph)
6831 int level = (retval==RetVal_Subsubsection) ? 3 : 4;
6832 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected %s "
6833 "command found inside %s!",
6834 sectionLevelToName[level],sectionLevelToName[m_level]);
6835 retval=0; // stop parsing
6841 INTERNAL_ASSERT(retval==0 ||
6842 retval==RetVal_Section ||
6843 retval==RetVal_Subsection ||
6844 retval==RetVal_Subsubsection ||
6845 retval==RetVal_Paragraph ||
6846 retval==RetVal_Internal ||
6847 retval==RetVal_EndInternal
6850 DBG(("DocSection::parse() end: retval=%x\n",retval));
6851 DocNode *n = g_nodeStack.pop();
6856 //--------------------------------------------------------------------------
6858 void DocText::parse()
6860 DBG(("DocText::parse() start\n"));
6861 g_nodeStack.push(this);
6862 doctokenizerYYsetStateText();
6865 while ((tok=doctokenizerYYlex())) // get the next token
6870 m_children.append(new DocWord(this,g_token->name));
6873 m_children.append(new DocWhiteSpace(this,g_token->chars));
6877 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name);
6878 if (s!=DocSymbol::Sym_Unknown)
6880 m_children.append(new DocSymbol(this,s));
6884 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unsupported symbol %s found",
6885 qPrint(g_token->name));
6890 switch (Mappers::cmdMapper->map(g_token->name))
6893 m_children.append(new DocSymbol(this,DocSymbol::Sym_BSlash));
6896 m_children.append(new DocSymbol(this,DocSymbol::Sym_At));
6899 m_children.append(new DocSymbol(this,DocSymbol::Sym_Less));
6902 m_children.append(new DocSymbol(this,DocSymbol::Sym_Greater));
6905 m_children.append(new DocSymbol(this,DocSymbol::Sym_Amp));
6908 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dollar));
6911 m_children.append(new DocSymbol(this,DocSymbol::Sym_Hash));
6914 m_children.append(new DocSymbol(this,DocSymbol::Sym_DoubleColon));
6917 m_children.append(new DocSymbol(this,DocSymbol::Sym_Percent));
6920 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
6921 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
6924 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
6925 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
6926 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
6929 m_children.append(new DocSymbol(this,DocSymbol::Sym_Quot));
6932 m_children.append(new DocSymbol(this,DocSymbol::Sym_Dot));
6935 m_children.append(new DocSymbol(this,DocSymbol::Sym_Plus));
6938 m_children.append(new DocSymbol(this,DocSymbol::Sym_Minus));
6941 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected command `%s' found",
6942 qPrint(g_token->name));
6947 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected token %s",
6953 handleUnclosedStyleCommands();
6955 DocNode *n = g_nodeStack.pop();
6957 DBG(("DocText::parse() end\n"));
6961 //--------------------------------------------------------------------------
6963 void DocRoot::parse()
6965 DBG(("DocRoot::parse() start\n"));
6966 g_nodeStack.push(this);
6967 doctokenizerYYsetStatePara();
6970 // first parse any number of paragraphs
6975 DocPara *par = new DocPara(this);
6976 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6977 retval=par->parse();
6978 if (!par->isEmpty())
6980 m_children.append(par);
6987 if (retval==TK_LISTITEM)
6989 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid list item found");
6991 else if (retval==RetVal_Subsection)
6993 warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsection command outside of section context!");
6995 else if (retval==RetVal_Subsubsection)
6997 warn_doc_error(g_fileName,doctokenizerYYlineno,"found subsubsection command outside of subsection context!");
6999 else if (retval==RetVal_Paragraph)
7001 warn_doc_error(g_fileName,doctokenizerYYlineno,"found paragraph command outside of subsubsection context!");
7003 if (retval==RetVal_Internal)
7005 DocInternal *in = new DocInternal(this);
7006 m_children.append(in);
7007 retval = in->parse(1);
7009 } while (retval!=0 && retval!=RetVal_Section);
7010 if (lastPar) lastPar->markLast();
7012 //printf("DocRoot::parse() retval=%d %d\n",retval,RetVal_Section);
7013 // then parse any number of level1 sections
7014 while (retval==RetVal_Section)
7016 SectionInfo *sec=Doxygen::sectionDict->find(g_token->sectionId);
7019 DocSection *s=new DocSection(this,
7020 QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
7021 m_children.append(s);
7022 retval = s->parse();
7026 warn_doc_error(g_fileName,doctokenizerYYlineno,"Invalid section id `%s'; ignoring section",qPrint(g_token->sectionId));
7031 handleUnclosedStyleCommands();
7033 DocNode *n = g_nodeStack.pop();
7035 DBG(("DocRoot::parse() end\n"));
7038 static QCString extractCopyDocId(const char *data, uint &j, uint len)
7043 bool insideDQuote=FALSE;
7044 bool insideSQuote=FALSE;
7046 while (j<len && !found)
7048 if (!insideSQuote && !insideDQuote)
7052 case '(': round++; break;
7053 case ')': round--; break;
7054 case '"': insideDQuote=TRUE; break;
7055 case '\'': insideSQuote=TRUE; break;
7056 case ' ': // fall through
7057 case '\t': // fall through
7063 else if (insideSQuote) // look for single quote end
7065 if (data[j]=='\'' && (j==0 || data[j]!='\\'))
7070 else if (insideDQuote) // look for double quote end
7072 if (data[j]=='"' && (j==0 || data[j]!='\\'))
7079 if (qstrncmp(data+j," const",6)==0)
7083 else if (qstrncmp(data+j," volatile",9)==0)
7089 if (e>s) memcpy(id.rawData(),data+s,e-s);
7091 //printf("extractCopyDocId='%s' input='%s'\n",id.data(),&data[s]);
7095 // macro to check if the input starts with a specific command.
7096 // note that data[i] should point to the start of the command (\ or @ character)
7097 // and the sizeof(str) returns the size of str including the '\0' terminator;
7098 // a fact we abuse to skip over the start of the command character.
7099 #define CHECK_FOR_COMMAND(str,action) \
7100 do if ((i+sizeof(str)<len) && qstrncmp(data+i+1,str,sizeof(str)-1)==0) \
7101 { j=i+sizeof(str); action; } while(0)
7103 static uint isCopyBriefOrDetailsCmd(const char *data, uint i,uint len,bool &brief)
7106 if (i==0 || (data[i-1]!='@' && data[i-1]!='\\')) // not an escaped command
7108 CHECK_FOR_COMMAND("copybrief",brief=TRUE); // @copybrief or \copybrief
7109 CHECK_FOR_COMMAND("copydetails",brief=FALSE); // @copydetails or \copydetails
7114 static uint isVerbatimSection(const char *data,uint i,uint len,QCString &endMarker)
7117 if (i==0 || (data[i-1]!='@' && data[i-1]!='\\')) // not an escaped command
7119 CHECK_FOR_COMMAND("dot",endMarker="enddot");
7120 CHECK_FOR_COMMAND("code",endMarker="endcode");
7121 CHECK_FOR_COMMAND("msc",endMarker="endmsc");
7122 CHECK_FOR_COMMAND("verbatim",endMarker="endverbatim");
7123 CHECK_FOR_COMMAND("latexonly",endMarker="endlatexonly");
7124 CHECK_FOR_COMMAND("htmlonly",endMarker="endhtmlonly");
7125 CHECK_FOR_COMMAND("xmlonly",endMarker="endxmlonly");
7126 CHECK_FOR_COMMAND("rtfonly",endMarker="endrtfonly");
7127 CHECK_FOR_COMMAND("manonly",endMarker="endmanonly");
7128 CHECK_FOR_COMMAND("docbookonly",endMarker="enddocbookonly");
7129 CHECK_FOR_COMMAND("startuml",endMarker="enduml");
7131 //printf("isVerbatimSection(%s)=%d)\n",QCString(&data[i]).left(10).data(),j);
7135 static uint skipToEndMarker(const char *data,uint i,uint len,const QCString &endMarker)
7139 if ((data[i]=='@' || data[i]=='\\') && // start of command character
7140 (i==0 || (data[i-1]!='@' && data[i-1]!='\\'))) // that is not escaped
7142 if (i+endMarker.length()+1<=len && qstrncmp(data+i+1,endMarker,endMarker.length())==0)
7144 return i+endMarker.length()+1;
7149 // oops no endmarker found...
7150 return i<len ? i+1 : len;
7153 static QCString processCopyDoc(const char *data,uint &len)
7155 //printf("processCopyDoc start '%s'\n",data);
7161 if (c=='@' || c=='\\') // look for a command
7164 uint j=isCopyBriefOrDetailsCmd(data,i,len,isBrief);
7168 while (j<len && (data[j]==' ' || data[j]=='\t')) j++;
7169 // extract the argument
7170 QCString id = extractCopyDocId(data,j,len);
7173 //printf("resolving docs='%s'\n",id.data());
7174 if (findDocsForMemberOrCompound(id,&doc,&brief,&def))
7176 //printf("found it def=%p brief='%s' doc='%s' isBrief=%d\n",def,brief.data(),doc.data(),isBrief);
7177 if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
7179 g_copyStack.append(def);
7182 uint l=brief.length();
7183 buf.addStr(processCopyDoc(brief,l));
7187 uint l=doc.length();
7188 buf.addStr(processCopyDoc(doc,l));
7190 g_copyStack.remove(def);
7194 warn_doc_error(g_fileName,doctokenizerYYlineno,
7195 "Found recursive @copy%s or @copydoc relation for argument '%s'.\n",
7196 isBrief?"brief":"details",id.data());
7201 warn_doc_error(g_fileName,doctokenizerYYlineno,
7202 "@copy%s or @copydoc target '%s' not found", isBrief?"brief":"details",
7205 // skip over command
7211 uint k = isVerbatimSection(data,i,len,endMarker);
7215 i=skipToEndMarker(data,k,len,endMarker);
7216 buf.addStr(data+orgPos,i-orgPos);
7225 else // not a command, just copy
7236 //--------------------------------------------------------------------------
7238 DocRoot *validatingParseDoc(const char *fileName,int startLine,
7239 Definition *ctx,MemberDef *md,
7240 const char *input,bool indexWords,
7241 bool isExample, const char *exampleName,
7242 bool singleLine, bool linkFromIndex)
7244 //printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>",
7245 // md?md->name().data():"<none>",
7247 //printf("========== validating %s at line %d\n",fileName,startLine);
7248 //printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input);
7249 //g_token = new TokenInfo;
7251 // store parser state so we can re-enter this function if needed
7252 //bool fortranOpt = Config_getBool(OPTIMIZE_FOR_FORTRAN);
7253 docParserPushContext();
7255 if (ctx && ctx!=Doxygen::globalScope &&
7256 (ctx->definitionType()==Definition::TypeClass ||
7257 ctx->definitionType()==Definition::TypeNamespace
7261 g_context = ctx->name();
7263 else if (ctx && ctx->definitionType()==Definition::TypePage)
7265 Definition *scope = ((PageDef*)ctx)->getPageScope();
7266 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
7268 else if (ctx && ctx->definitionType()==Definition::TypeGroup)
7270 Definition *scope = ((GroupDef*)ctx)->getGroupScope();
7271 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
7279 if (indexWords && Doxygen::searchIndex)
7283 g_searchUrl=md->getOutputFileBase();
7284 Doxygen::searchIndex->setCurrentDoc(md,md->anchor(),FALSE);
7288 g_searchUrl=ctx->getOutputFileBase();
7289 Doxygen::searchIndex->setCurrentDoc(ctx,ctx->anchor(),FALSE);
7293 if (indexWords && md && Doxygen::searchIndex)
7295 g_searchUrl=md->getOutputFileBase();
7296 Doxygen::searchIndex->setCurrentDoc(
7297 (md->getLanguage()==SrcLangExt_Fortran ?
7298 theTranslator->trSubprogram(TRUE,TRUE):
7299 theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(),
7303 else if (indexWords && ctx && Doxygen::searchIndex)
7305 g_searchUrl=ctx->getOutputFileBase();
7306 QCString name = ctx->qualifiedName();
7308 SrcLangExt lang = ctx->getLanguage();
7309 QCString sep = getLanguageSpecificSeparator(lang);
7312 name = substitute(name,"::",sep);
7315 switch (ctx->definitionType())
7317 case Definition::TypePage:
7319 PageDef *pd = (PageDef *)ctx;
7320 if (!pd->title().isEmpty())
7322 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title();
7326 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name();
7330 case Definition::TypeClass:
7332 ClassDef *cd = (ClassDef *)ctx;
7333 name.prepend(cd->compoundTypeString()+" ");
7336 case Definition::TypeNamespace:
7338 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
7340 name = theTranslator->trPackage(name);
7342 else if (lang==SrcLangExt_Fortran)
7344 name.prepend(theTranslator->trModule(TRUE,TRUE)+" ");
7348 name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" ");
7352 case Definition::TypeGroup:
7354 GroupDef *gd = (GroupDef *)ctx;
7355 if (gd->groupTitle())
7357 name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle();
7361 name.prepend(theTranslator->trGroup(TRUE,TRUE)+" ");
7368 Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl);
7376 g_fileName = fileName;
7377 g_relPath = (!linkFromIndex && ctx) ?
7378 QCString(relativePathToRoot(ctx->getOutputFileBase())) :
7380 //printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data());
7382 g_nodeStack.clear();
7383 g_styleStack.clear();
7384 g_initialStyleStack.clear();
7385 g_inSeeBlock = FALSE;
7386 g_xmlComment = FALSE;
7387 g_insideHtmlLink = FALSE;
7388 g_includeFileText = "";
7389 g_includeFileOffset = 0;
7390 g_includeFileLength = 0;
7391 g_isExample = isExample;
7392 g_exampleName = exampleName;
7393 g_hasParamCommand = FALSE;
7394 g_hasReturnCommand = FALSE;
7395 g_paramsFound.setAutoDelete(FALSE);
7396 g_paramsFound.clear();
7397 g_sectionDict = 0; //sections;
7399 //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
7400 doctokenizerYYlineno=startLine;
7401 uint inpLen=qstrlen(input);
7402 QCString inpStr = processCopyDoc(input,inpLen);
7403 if (inpStr.isEmpty() || inpStr.at(inpStr.length()-1)!='\n')
7407 //printf("processCopyDoc(in='%s' out='%s')\n",input,inpStr.data());
7408 doctokenizerYYinit(inpStr,g_fileName);
7410 // build abstract syntax tree
7411 DocRoot *root = new DocRoot(md!=0,singleLine);
7415 if (Debug::isFlagSet(Debug::PrintTree))
7417 // pretty print the result
7418 PrintDocVisitor *v = new PrintDocVisitor;
7423 checkUndocumentedParams();
7424 detectNoDocumentedParams();
7426 // TODO: These should be called at the end of the program.
7427 //doctokenizerYYcleanup();
7428 //Mappers::cmdMapper->freeInstance();
7429 //Mappers::htmlTagMapper->freeInstance();
7431 // restore original parser state
7432 docParserPopContext();
7434 //printf(">>>>>> end validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>",
7435 // md?md->name().data():"<none>");
7440 DocText *validatingParseText(const char *input)
7442 // store parser state so we can re-enter this function if needed
7443 docParserPushContext();
7445 //printf("------------ input ---------\n%s\n"
7446 // "------------ end input -----\n",input);
7447 //g_token = new TokenInfo;
7449 g_fileName = "<parseText>";
7452 g_nodeStack.clear();
7453 g_styleStack.clear();
7454 g_initialStyleStack.clear();
7455 g_inSeeBlock = FALSE;
7456 g_xmlComment = FALSE;
7457 g_insideHtmlLink = FALSE;
7458 g_includeFileText = "";
7459 g_includeFileOffset = 0;
7460 g_includeFileLength = 0;
7461 g_isExample = FALSE;
7463 g_hasParamCommand = FALSE;
7464 g_hasReturnCommand = FALSE;
7465 g_paramsFound.setAutoDelete(FALSE);
7466 g_paramsFound.clear();
7469 DocText *txt = new DocText;
7473 doctokenizerYYlineno=1;
7474 doctokenizerYYinit(input,g_fileName);
7476 // build abstract syntax tree
7479 if (Debug::isFlagSet(Debug::PrintTree))
7481 // pretty print the result
7482 PrintDocVisitor *v = new PrintDocVisitor;
7488 // restore original parser state
7489 docParserPopContext();
7493 void docFindSections(const char *input,
7496 const char *fileName)
7498 doctokenizerYYFindSections(input,d,mg,fileName);