Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/docparser.cpp

Source at commit 1322 created 12 years 8 months ago.
By meklort, Add doxygen to utils folder
1/******************************************************************************
2 *
3 *
4 *
5 *
6 * Copyright (C) 1997-2011 by Dimitri van Heesch.
7 *
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.
13 *
14 * Documents produced by Doxygen are derivative works derived from the
15 * input used in their production; they are not affected by this license.
16 *
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21
22#include <qfile.h>
23#include <qfileinfo.h>
24#include <qcstring.h>
25#include <qstack.h>
26#include <qdict.h>
27#include <qregexp.h>
28#include <ctype.h>
29
30#include "doxygen.h"
31#include "debug.h"
32#include "util.h"
33#include "pagedef.h"
34
35#include "docparser.h"
36#include "doctokenizer.h"
37#include "cmdmapper.h"
38#include "printdocvisitor.h"
39#include "message.h"
40#include "section.h"
41#include "searchindex.h"
42#include "language.h"
43#include "portable.h"
44
45// debug off
46#define DBG(x) do {} while(0)
47
48// debug to stdout
49//#define DBG(x) printf x
50
51// debug to stderr
52//#define myprintf(x...) fprintf(stderr,x)
53//#define DBG(x) myprintf x
54
55#define INTERNAL_ASSERT(x) do {} while(0)
56//#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__));
57
58//---------------------------------------------------------------------------
59
60static const char *sectionLevelToName[] =
61{
62 "page",
63 "section",
64 "subsection",
65 "subsubsection",
66 "paragraph"
67};
68
69//---------------------------------------------------------------------------
70
71// Parser state: global variables during a call to validatingParseDoc
72static Definition * g_scope;
73static QCString g_context;
74static bool g_inSeeBlock;
75static bool g_insideHtmlLink;
76static QStack<DocNode> g_nodeStack;
77static QStack<DocStyleChange> g_styleStack;
78static QStack<DocStyleChange> g_initialStyleStack;
79static QList<Definition> g_copyStack;
80static QCString g_fileName;
81static QCString g_relPath;
82
83static bool g_hasParamCommand;
84static bool g_hasReturnCommand;
85static QDict<void> g_paramsFound;
86static MemberDef * g_memberDef;
87static bool g_isExample;
88static QCString g_exampleName;
89static SectionDict * g_sectionDict;
90static QCString g_searchUrl;
91
92static QCString g_includeFileText;
93static uint g_includeFileOffset;
94static uint g_includeFileLength;
95
96// parser's context to store all global variables
97struct DocParserContext
98{
99 Definition *scope;
100 QCString context;
101 bool inSeeBlock;
102 bool insideHtmlLink;
103 QStack<DocNode> nodeStack;
104 QStack<DocStyleChange> styleStack;
105 QStack<DocStyleChange> initialStyleStack;
106 QList<Definition> copyStack;
107 QCString fileName;
108 QCString relPath;
109
110 bool hasParamCommand;
111 bool hasReturnCommand;
112 MemberDef * memberDef;
113 QDict<void> paramsFound;
114 bool isExample;
115 QCString exampleName;
116 SectionDict *sectionDict;
117 QCString searchUrl;
118
119 QCString includeFileText;
120 uint includeFileOffset;
121 uint includeFileLength;
122
123 TokenInfo *token;
124};
125
126static QStack<DocParserContext> g_parserStack;
127
128//---------------------------------------------------------------------------
129
130static void docParserPushContext(bool saveParamInfo=TRUE)
131{
132 //QCString indent;
133 //indent.fill(' ',g_parserStack.count()*2+2);
134 //printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count());
135
136 doctokenizerYYpushContext();
137 DocParserContext *ctx = new DocParserContext;
138 ctx->scope = g_scope;
139 ctx->context = g_context;
140 ctx->inSeeBlock = g_inSeeBlock;
141 ctx->insideHtmlLink = g_insideHtmlLink;
142 ctx->nodeStack = g_nodeStack;
143 ctx->styleStack = g_styleStack;
144 ctx->initialStyleStack = g_initialStyleStack;
145 ctx->copyStack = g_copyStack;
146 ctx->fileName = g_fileName;
147 ctx->relPath = g_relPath;
148
149 if (saveParamInfo)
150 {
151 ctx->hasParamCommand = g_hasParamCommand;
152 ctx->hasReturnCommand = g_hasReturnCommand;
153 ctx->paramsFound = g_paramsFound;
154 }
155
156 ctx->memberDef = g_memberDef;
157 ctx->isExample = g_isExample;
158 ctx->exampleName = g_exampleName;
159 ctx->sectionDict = g_sectionDict;
160 ctx->searchUrl = g_searchUrl;
161
162 ctx->includeFileText = g_includeFileText;
163 ctx->includeFileOffset = g_includeFileOffset;
164 ctx->includeFileLength = g_includeFileLength;
165
166 ctx->token = g_token;
167 g_token = new TokenInfo;
168
169 g_parserStack.push(ctx);
170}
171
172static void docParserPopContext(bool keepParamInfo=FALSE)
173{
174 DocParserContext *ctx = g_parserStack.pop();
175 g_scope = ctx->scope;
176 g_context = ctx->context;
177 g_inSeeBlock = ctx->inSeeBlock;
178 g_insideHtmlLink = ctx->insideHtmlLink;
179 g_nodeStack = ctx->nodeStack;
180 g_styleStack = ctx->styleStack;
181 g_initialStyleStack = ctx->initialStyleStack;
182 g_copyStack = ctx->copyStack;
183 g_fileName = ctx->fileName;
184 g_relPath = ctx->relPath;
185
186 if (!keepParamInfo)
187 {
188 g_hasParamCommand = ctx->hasParamCommand;
189 g_hasReturnCommand = ctx->hasReturnCommand;
190 g_paramsFound = ctx->paramsFound;
191 }
192 g_memberDef = ctx->memberDef;
193 g_isExample = ctx->isExample;
194 g_exampleName = ctx->exampleName;
195 g_sectionDict = ctx->sectionDict;
196 g_searchUrl = ctx->searchUrl;
197
198 g_includeFileText = ctx->includeFileText;
199 g_includeFileOffset = ctx->includeFileOffset;
200 g_includeFileLength = ctx->includeFileLength;
201
202 delete g_token;
203 g_token = ctx->token;
204
205 delete ctx;
206 doctokenizerYYpopContext();
207
208 //QCString indent;
209 //indent.fill(' ',g_parserStack.count()*2+2);
210 //printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count());
211}
212
213//---------------------------------------------------------------------------
214
215/*! search for an image in the imageNameDict and if found
216 * copies the image to the output directory (which depends on the \a type
217 * parameter).
218 */
219static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
220{
221 QCString result;
222 bool ambig;
223 FileDef *fd;
224 //printf("Search for %s\n",fileName);
225 if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
226 {
227 QCString inputFile = fd->absFilePath();
228 QFile inImage(inputFile);
229 if (inImage.open(IO_ReadOnly))
230 {
231 result = fileName;
232 int i;
233 if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1)
234 {
235result = result.right(result.length()-i-1);
236 }
237 //printf("fileName=%s result=%s\n",fileName,result.data());
238 QCString outputDir;
239 switch(type)
240 {
241 case DocImage::Html:
242 if (!Config_getBool("GENERATE_HTML")) return result;
243 outputDir = Config_getString("HTML_OUTPUT");
244 break;
245 case DocImage::Latex:
246 if (!Config_getBool("GENERATE_LATEX")) return result;
247 outputDir = Config_getString("LATEX_OUTPUT");
248 break;
249 case DocImage::Rtf:
250 if (!Config_getBool("GENERATE_RTF")) return result;
251 outputDir = Config_getString("RTF_OUTPUT");
252 break;
253 }
254 QCString outputFile = outputDir+"/"+result;
255 if (outputFile!=inputFile) // prevent copying to ourself
256 {
257 QFile outImage(outputFile.data());
258 if (outImage.open(IO_WriteOnly)) // copy the image
259 {
260 char *buffer = new char[inImage.size()];
261 inImage.readBlock(buffer,inImage.size());
262 outImage.writeBlock(buffer,inImage.size());
263 outImage.flush();
264 delete[] buffer;
265 if (type==DocImage::Html) Doxygen::indexList.addImageFile(result);
266 }
267 else
268 {
269 warn_doc_error(g_fileName,doctokenizerYYlineno,
270 "warning: could not write output image %s",qPrint(outputFile));
271 }
272 }
273 }
274 else
275 {
276 warn_doc_error(g_fileName,doctokenizerYYlineno,
277 "warning: could not open image %s",qPrint(fileName));
278 }
279
280 if (type==DocImage::Latex && Config_getBool("USE_PDFLATEX") &&
281fd->name().right(4)==".eps"
282 )
283 { // we have an .eps image in pdflatex mode => convert it to a pdf.
284 QCString outputDir = Config_getString("LATEX_OUTPUT");
285 QCString baseName = fd->name().left(fd->name().length()-4);
286 QCString epstopdfArgs(4096);
287 epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"",
288 outputDir.data(), baseName.data(),
289 outputDir.data(), baseName.data());
290 portable_sysTimerStart();
291 if (portable_system("epstopdf",epstopdfArgs)!=0)
292 {
293err("error: Problems running epstopdf. Check your TeX installation!\n");
294 }
295 portable_sysTimerStop();
296 return baseName;
297 }
298 }
299 else if (ambig)
300 {
301 QCString text;
302 text.sprintf("warning: image file name %s is ambiguous.\n",qPrint(fileName));
303 text+="Possible candidates:\n";
304 text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
305 warn_doc_error(g_fileName,doctokenizerYYlineno,text);
306 }
307 else
308 {
309 result=fileName;
310 if (result.left(5)!="http:" && result.left(6)!="https:")
311 {
312 warn_doc_error(g_fileName,doctokenizerYYlineno,
313 "warning: image file %s is not found in IMAGE_PATH: "
314 "assuming external image.",qPrint(fileName)
315 );
316 }
317 }
318 return result;
319}
320
321/*! Collects the parameters found with \@param or \@retval commands
322 * in a global list g_paramsFound. If \a isParam is set to TRUE
323 * and the parameter is not an actual parameter of the current
324 * member g_memberDef, then a warning is raised (unless warnings
325 * are disabled altogether).
326 */
327static void checkArgumentName(const QCString &name,bool isParam)
328{
329 if (!Config_getBool("WARN_IF_DOC_ERROR")) return;
330 if (g_memberDef==0) return; // not a member
331 LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ?
332 g_memberDef->argumentList() :
333 g_memberDef->declArgumentList();
334 //printf("isDocsForDefinition()=%d\n",g_memberDef->isDocsForDefinition());
335 if (al==0) return; // no argument list
336
337 static QRegExp re("[a-zA-Z0-9_\\x80-\\xFF]+\\.*");
338 int p=0,i=0,l;
339 while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
340 {
341 QCString aName=name.mid(i,l);
342 //printf("aName=`%s'\n",aName.data());
343 ArgumentListIterator ali(*al);
344 Argument *a;
345 bool found=FALSE;
346 for (ali.toFirst();(a=ali.current());++ali)
347 {
348 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
349 argName=argName.stripWhiteSpace();
350 //printf("argName=`%s'\n",argName.data());
351 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
352 if (aName==argName)
353 {
354//printf("adding `%s'\n",aName.data());
355g_paramsFound.insert(aName,(void *)(0x8));
356found=TRUE;
357break;
358 }
359 }
360 if (!found && isParam)
361 {
362 //printf("member type=%d\n",memberDef->memberType());
363 QCString scope=g_memberDef->getScopeString();
364 if (!scope.isEmpty()) scope+="::"; else scope="";
365 QCString inheritedFrom = "";
366 QCString docFile = g_memberDef->docFile();
367 int docLine = g_memberDef->docLine();
368 MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom();
369 if (inheritedMd) // documentation was inherited
370 {
371 inheritedFrom.sprintf(" inherited from member %s at line "
372 "%d in file %s",qPrint(inheritedMd->name()),
373 inheritedMd->docLine(),qPrint(inheritedMd->docFile()));
374 docFile = g_memberDef->getDefFileName();
375 docLine = g_memberDef->getDefLine();
376
377 }
378 QCString alStr = argListToString(al.pointer());
379 warn_doc_error(docFile,docLine,
380 "warning: argument '%s' of command @param "
381 "is not found in the argument list of %s%s%s%s",
382 qPrint(aName), qPrint(scope), qPrint(g_memberDef->name()),
383 qPrint(alStr), qPrint(inheritedFrom));
384 }
385 p=i+l;
386 }
387}
388
389/*! Checks if the parameters that have been specified using \@param are
390 * indeed all paramters.
391 * Must be called after checkArgumentName() has been called for each
392 * argument.
393 */
394static void checkUndocumentedParams()
395{
396 if (g_memberDef && g_hasParamCommand && Config_getBool("WARN_IF_DOC_ERROR"))
397 {
398 LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ?
399 g_memberDef->argumentList() :
400 g_memberDef->declArgumentList();
401 if (al!=0)
402 {
403 ArgumentListIterator ali(*al);
404 Argument *a;
405 bool found=FALSE;
406 for (ali.toFirst();(a=ali.current());++ali)
407 {
408 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
409 argName=argName.stripWhiteSpace();
410 if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
411 if (getLanguageFromFileName(g_memberDef->getDefFileName())==SrcLangExt_Python && argName=="self")
412 {
413 // allow undocumented self parameter for Python
414 }
415 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty())
416 {
417 found = TRUE;
418 break;
419 }
420 }
421 if (found)
422 {
423 bool first=TRUE;
424 QCString errMsg=
425 "warning: The following parameters of "+
426 QCString(g_memberDef->qualifiedName()) +
427 QCString(argListToString(al.pointer())) +
428 " are not documented:\n";
429 for (ali.toFirst();(a=ali.current());++ali)
430 {
431 QCString argName = g_memberDef->isDefine() ? a->type : a->name;
432 argName=argName.stripWhiteSpace();
433 if (getLanguageFromFileName(g_memberDef->getDefFileName())==SrcLangExt_Python && argName=="self")
434 {
435 // allow undocumented self parameter for Python
436 }
437 else if (!argName.isEmpty() && g_paramsFound.find(argName)==0)
438 {
439 if (!first)
440 {
441 errMsg+="\n";
442 }
443 else
444 {
445 first=FALSE;
446 }
447 errMsg+=" parameter '"+argName+"'";
448 }
449 }
450 if (g_memberDef->inheritsDocsFrom())
451 {
452 warn_doc_error(g_memberDef->getDefFileName(),
453 g_memberDef->getDefLine(),
454 substitute(errMsg,"%","%%"));
455 }
456 else
457 {
458 warn_doc_error(g_memberDef->docFile(),
459 g_memberDef->docLine(),
460 substitute(errMsg,"%","%%"));
461 }
462 }
463 }
464 }
465}
466
467/*! Check if a member has documentation for its parameter and or return
468 * type, if applicable. If found this will be stored in the member, this
469 * is needed as a member can have brief and detailed documentation, while
470 * only one of these needs to document the parameters.
471 */
472static void detectNoDocumentedParams()
473{
474 if (g_memberDef && Config_getBool("WARN_NO_PARAMDOC"))
475 {
476 LockingPtr<ArgumentList> al = g_memberDef->argumentList();
477 LockingPtr<ArgumentList> declAl = g_memberDef->declArgumentList();
478 QCString returnType = g_memberDef->typeString();
479 bool isPython = getLanguageFromFileName(g_memberDef->getDefFileName())==SrcLangExt_Python;
480
481 if (!g_memberDef->hasDocumentedParams() &&
482 g_hasParamCommand)
483 {
484 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
485 g_memberDef->setHasDocumentedParams(TRUE);
486 }
487 else if (!g_memberDef->hasDocumentedParams())
488 {
489 bool allDoc=TRUE; // no paramater => all parameters are documented
490 if ( // member has parameters
491 al!=0 && // but the member has a parameter list
492 al->count()>0 // with at least one parameter (that is not void)
493 )
494 {
495 ArgumentListIterator ali(*al);
496 Argument *a;
497
498 // see if all parameters have documentation
499 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
500 {
501 if (!a->name.isEmpty() && a->type!="void" &&
502 !(isPython && a->name=="self")
503 )
504 {
505 allDoc = !a->docs.isEmpty();
506 }
507 //printf("a->type=%s a->name=%s doc=%s\n",
508 // a->type.data(),a->name.data(),a->docs.data());
509 }
510 if (!allDoc && declAl!=0) // try declaration arguments as well
511 {
512 allDoc=TRUE;
513 ArgumentListIterator ali(*declAl);
514 Argument *a;
515 for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
516 {
517 if (!a->name.isEmpty() && a->type!="void" &&
518 !(isPython && a->name=="self")
519 )
520 {
521 allDoc = !a->docs.isEmpty();
522 }
523 //printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data());
524 }
525 }
526 }
527 if (allDoc)
528 {
529 //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
530 g_memberDef->setHasDocumentedParams(TRUE);
531 }
532 }
533 //printf("Member %s hasReturnCommand=%d\n",g_memberDef->name().data(),g_hasReturnCommand);
534 if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found
535 g_hasReturnCommand)
536 {
537 g_memberDef->setHasDocumentedReturnType(TRUE);
538 }
539 else if ( // see if return needs to documented
540 g_memberDef->hasDocumentedReturnType() ||
541 returnType.isEmpty() || // empty return type
542 returnType.find("void")!=-1 || // void return type
543 returnType.find("subroutine")!=-1 || // fortran subroutine
544 g_memberDef->isConstructor() || // a constructor
545 g_memberDef->isDestructor() // or destructor
546 )
547 {
548 g_memberDef->setHasDocumentedReturnType(TRUE);
549 }
550
551 }
552}
553
554
555//---------------------------------------------------------------------------
556
557/*! Strips known html and tex extensions from \a text. */
558static QCString stripKnownExtensions(const char *text)
559{
560 QCString result=text;
561 if (result.right(4)==".tex")
562 {
563 result=result.left(result.length()-4);
564 }
565 else if (result.right(Doxygen::htmlFileExtension.length())==
566 QCString(Doxygen::htmlFileExtension))
567 {
568 result=result.left(result.length()-Doxygen::htmlFileExtension.length());
569 }
570 return result;
571}
572
573
574//---------------------------------------------------------------------------
575
576/*! Returns TRUE iff node n is a child of a preformatted node */
577static bool insidePRE(DocNode *n)
578{
579 while (n)
580 {
581 if (n->isPreformatted()) return TRUE;
582 n=n->parent();
583 }
584 return FALSE;
585}
586
587//---------------------------------------------------------------------------
588
589/*! Returns TRUE iff node n is a child of a html list item node */
590static bool insideLI(DocNode *n)
591{
592 while (n)
593 {
594 if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE;
595 n=n->parent();
596 }
597 return FALSE;
598}
599
600//---------------------------------------------------------------------------
601
602/*! Returns TRUE iff node n is a child of a unordered html list node */
603static bool insideUL(DocNode *n)
604{
605 while (n)
606 {
607 if (n->kind()==DocNode::Kind_HtmlList &&
608 ((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE;
609 n=n->parent();
610 }
611 return FALSE;
612}
613
614//---------------------------------------------------------------------------
615
616/*! Returns TRUE iff node n is a child of a ordered html list node */
617static bool insideOL(DocNode *n)
618{
619 while (n)
620 {
621 if (n->kind()==DocNode::Kind_HtmlList &&
622 ((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE;
623 n=n->parent();
624 }
625 return FALSE;
626}
627
628//---------------------------------------------------------------------------
629
630static bool insideTable(DocNode *n)
631{
632 while (n)
633 {
634 if (n->kind()==DocNode::Kind_HtmlTable) return TRUE;
635 n=n->parent();
636 }
637 return FALSE;
638}
639
640//---------------------------------------------------------------------------
641
642///*! Returns TRUE iff node n is a child of a language node */
643//static bool insideLang(DocNode *n)
644//{
645// while (n)
646// {
647// if (n->kind()==DocNode::Kind_Language) return TRUE;
648// n=n->parent();
649// }
650// return FALSE;
651//}
652
653
654//---------------------------------------------------------------------------
655
656/*! Looks for a documentation block with name commandName in the current
657 * context (g_context). The resulting documentation string is
658 * put in pDoc, the definition in which the documentation was found is
659 * put in pDef.
660 * @retval TRUE if name was found.
661 * @retval FALSE if name was not found.
662 */
663static bool findDocsForMemberOrCompound(const char *commandName,
664 QCString *pDoc,
665 QCString *pBrief,
666 Definition **pDef)
667{
668 //printf("findDocsForMemberOrCompound(%s)\n",commandName);
669 *pDoc="";
670 *pBrief="";
671 *pDef=0;
672 QCString cmdArg=substitute(commandName,"#","::");
673 int l=cmdArg.length();
674 if (l==0) return FALSE;
675
676 int funcStart=cmdArg.find('(');
677 if (funcStart==-1)
678 {
679 funcStart=l;
680 }
681 else
682 {
683 // Check for the case of operator() and the like.
684 // beware of scenarios like operator()((foo)bar)
685 int secondParen = cmdArg.find('(', funcStart+1);
686 int leftParen = cmdArg.find(')', funcStart+1);
687 if (leftParen!=-1 && secondParen!=-1)
688 {
689 if (leftParen<secondParen)
690 {
691 funcStart=secondParen;
692 }
693 }
694 }
695
696 QCString name=removeRedundantWhiteSpace(cmdArg.left(funcStart));
697 QCString args=cmdArg.right(l-funcStart);
698
699 // try if the link is to a member
700 MemberDef *md=0;
701 ClassDef *cd=0;
702 FileDef *fd=0;
703 NamespaceDef *nd=0;
704 GroupDef *gd=0;
705 PageDef *pd=0;
706 bool found = getDefs(
707 g_context.find('.')==-1?g_context.data():"", // `find('.') is a hack to detect files
708 name,
709 args.isEmpty()?0:args.data(),
710 md,cd,fd,nd,gd,FALSE,0,TRUE);
711 //printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data());
712 if (found && md)
713 {
714 *pDoc=md->documentation();
715 *pBrief=md->briefDescription();
716 *pDef=md;
717 return TRUE;
718 }
719
720
721 int scopeOffset=g_context.length();
722 do // for each scope
723 {
724 QCString fullName=cmdArg;
725 if (scopeOffset>0)
726 {
727 fullName.prepend(g_context.left(scopeOffset)+"::");
728 }
729 //printf("Trying fullName=`%s'\n",fullName.data());
730
731 // try class, namespace, group, page, file reference
732 cd = Doxygen::classSDict->find(fullName);
733 if (cd) // class
734 {
735 *pDoc=cd->documentation();
736 *pBrief=cd->briefDescription();
737 *pDef=cd;
738 return TRUE;
739 }
740 nd = Doxygen::namespaceSDict->find(fullName);
741 if (nd) // namespace
742 {
743 *pDoc=nd->documentation();
744 *pBrief=nd->briefDescription();
745 *pDef=nd;
746 return TRUE;
747 }
748 gd = Doxygen::groupSDict->find(cmdArg);
749 if (gd) // group
750 {
751 *pDoc=gd->documentation();
752 *pBrief=gd->briefDescription();
753 *pDef=gd;
754 return TRUE;
755 }
756 pd = Doxygen::pageSDict->find(cmdArg);
757 if (pd) // page
758 {
759 *pDoc=pd->documentation();
760 *pBrief=pd->briefDescription();
761 *pDef=pd;
762 return TRUE;
763 }
764 bool ambig;
765 fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig);
766 if (fd && !ambig) // file
767 {
768 *pDoc=fd->documentation();
769 *pBrief=fd->briefDescription();
770 *pDef=fd;
771 return TRUE;
772 }
773
774 if (scopeOffset==0)
775 {
776 scopeOffset=-1;
777 }
778 else
779 {
780 scopeOffset = g_context.findRev("::",scopeOffset-1);
781 if (scopeOffset==-1) scopeOffset=0;
782 }
783 } while (scopeOffset>=0);
784
785
786 return FALSE;
787}
788//---------------------------------------------------------------------------
789
790// forward declaration
791static bool defaultHandleToken(DocNode *parent,int tok,
792 QList<DocNode> &children,bool
793 handleWord=TRUE);
794
795
796static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
797 const QCString &cmdName)
798{
799 DBG(("handleStyleArgument(%s)\n",qPrint(cmdName)));
800 QCString tokenName = g_token->name;
801 int tok=doctokenizerYYlex();
802 if (tok!=TK_WHITESPACE)
803 {
804 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
805qPrint(cmdName));
806 return tok;
807 }
808 while ((tok=doctokenizerYYlex()) &&
809 tok!=TK_WHITESPACE &&
810 tok!=TK_NEWPARA &&
811 tok!=TK_LISTITEM &&
812 tok!=TK_ENDLIST
813 )
814 {
815 static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
816 if (tok==TK_WORD && g_token->name.length()==1 &&
817 g_token->name.find(specialChar)!=-1)
818 {
819 // special character that ends the markup command
820 return tok;
821 }
822 if (!defaultHandleToken(parent,tok,children))
823 {
824 switch (tok)
825 {
826 case TK_COMMAND:
827 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command \\%s as the argument of a \\%s command",
828 qPrint(g_token->name),qPrint(cmdName));
829 break;
830 case TK_SYMBOL:
831 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found while handling command %s",
832 qPrint(g_token->name),qPrint(cmdName));
833 break;
834 case TK_HTMLTAG:
835 if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
836 { // ignore </li> as the end of a style command
837 continue;
838 }
839 return tok;
840 break;
841 default:
842 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s while handling command %s",
843 tokToString(tok),qPrint(cmdName));
844 break;
845 }
846 break;
847 }
848 }
849 DBG(("handleStyleArgument(%s) end tok=%x\n",qPrint(cmdName),tok));
850 return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
851 ) ? tok : RetVal_OK;
852}
853
854/*! Called when a style change starts. For instance a \<b\> command is
855 * encountered.
856 */
857static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
858 DocStyleChange::Style s,const HtmlAttribList *attribs)
859{
860 DBG(("HandleStyleEnter\n"));
861 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs);
862 children.append(sc);
863 g_styleStack.push(sc);
864}
865
866/*! Called when a style change ends. For instance a \</b\> command is
867 * encountered.
868 */
869static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
870 DocStyleChange::Style s,const char *tagName)
871{
872 DBG(("HandleStyleLeave\n"));
873 if (g_styleStack.isEmpty() || // no style change
874 g_styleStack.top()->style()!=s || // wrong style change
875 g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
876 )
877 {
878 if (g_styleStack.isEmpty())
879 {
880 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> tag without matching <%s>",
881 qPrint(tagName),qPrint(tagName));
882 }
883 else if (g_styleStack.top()->style()!=s)
884 {
885 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> tag while expecting </%s>",
886 qPrint(tagName),qPrint(g_styleStack.top()->styleString()));
887 }
888 else
889 {
890 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </%s> at different nesting level (%d) than expected (%d)",
891 qPrint(tagName),g_nodeStack.count(),g_styleStack.top()->position());
892 }
893 }
894 else // end the section
895 {
896 DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE);
897 children.append(sc);
898 g_styleStack.pop();
899 }
900}
901
902/*! Called at the end of a paragraph to close all open style changes
903 * (e.g. a <b> without a </b>). The closed styles are pushed onto a stack
904 * and entered again at the start of a new paragraph.
905 */
906static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
907{
908 if (!g_styleStack.isEmpty())
909 {
910 DocStyleChange *sc = g_styleStack.top();
911 while (sc && sc->position()>=g_nodeStack.count())
912 { // there are unclosed style modifiers in the paragraph
913 children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
914 g_initialStyleStack.push(sc);
915 g_styleStack.pop();
916 sc = g_styleStack.top();
917 }
918 }
919}
920
921static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
922{
923 DocStyleChange *sc;
924 while ((sc=g_initialStyleStack.pop()))
925 {
926 handleStyleEnter(parent,children,sc->style(),&sc->attribs());
927 }
928}
929
930static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
931{
932 HtmlAttribListIterator li(tagHtmlAttribs);
933 HtmlAttrib *opt;
934 int index=0;
935 int retval = RetVal_OK;
936 for (li.toFirst();(opt=li.current());++li,++index)
937 {
938 if (opt->name=="name") // <a name=label> tag
939 {
940 if (!opt->value.isEmpty())
941 {
942 DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE);
943 children.append(anc);
944 break; // stop looking for other tag attribs
945 }
946 else
947 {
948 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <a> tag with name option but without value!");
949 }
950 }
951 else if (opt->name=="href") // <a href=url>..</a> tag
952 {
953 // copy attributes
954 HtmlAttribList attrList = tagHtmlAttribs;
955 // and remove the href attribute
956 bool result = attrList.remove(index);
957 ASSERT(result);
958 DocHRef *href = new DocHRef(parent,attrList,opt->value);
959 children.append(href);
960 g_insideHtmlLink=TRUE;
961 retval = href->parse();
962 g_insideHtmlLink=FALSE;
963 break;
964 }
965 else // unsupported option for tag a
966 {
967 }
968 }
969 return retval;
970}
971
972const char *DocStyleChange::styleString() const
973{
974 switch (m_style)
975 {
976 case DocStyleChange::Bold: return "b";
977 case DocStyleChange::Italic: return "em";
978 case DocStyleChange::Code: return "code";
979 case DocStyleChange::Center: return "center";
980 case DocStyleChange::Small: return "small";
981 case DocStyleChange::Subscript: return "subscript";
982 case DocStyleChange::Superscript: return "superscript";
983 case DocStyleChange::Preformatted: return "pre";
984 case DocStyleChange::Div: return "div";
985 case DocStyleChange::Span: return "span";
986 }
987 return "<invalid>";
988}
989
990static void handleUnclosedStyleCommands()
991{
992 if (!g_initialStyleStack.isEmpty())
993 {
994 DocStyleChange *sc = g_initialStyleStack.top();
995 g_initialStyleStack.pop();
996 handleUnclosedStyleCommands();
997 warn_doc_error(g_fileName,doctokenizerYYlineno,
998 "warning: end of comment block while expecting "
999 "command </%s>",qPrint(sc->styleString()));
1000 }
1001}
1002
1003static void handleLinkedWord(DocNode *parent,QList<DocNode> &children)
1004{
1005 Definition *compound=0;
1006 MemberDef *member=0;
1007 QCString name = linkToText(g_token->name,TRUE);
1008 int len = g_token->name.length();
1009 ClassDef *cd=0;
1010 bool ambig;
1011 FileDef *fd = findFileDef(Doxygen::inputNameDict,g_fileName,ambig);
1012 //printf("handleLinkedWord(%s) g_context=%s\n",g_token->name.data(),g_context.data());
1013 if (!g_insideHtmlLink &&
1014 (resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member,TRUE,fd,TRUE)
1015 || (!g_context.isEmpty() && // also try with global scope
1016 resolveRef("",g_token->name,g_inSeeBlock,&compound,&member,FALSE,0,TRUE))
1017 )
1018 )
1019 {
1020 //printf("resolveRef %s = %p (linkable?=%d)\n",qPrint(g_token->name),member,member ? member->isLinkable() : FALSE);
1021 if (member && member->isLinkable()) // member link
1022 {
1023 if (member->isObjCMethod())
1024 {
1025 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
1026 name = member->objCMethodName(localLink,g_inSeeBlock);
1027 }
1028 children.append(new
1029 DocLinkedWord(parent,name,
1030 member->getReference(),
1031 member->getOutputFileBase(),
1032 member->anchor(),
1033 member->briefDescriptionAsTooltip()
1034 )
1035 );
1036 }
1037 else if (compound->isLinkable()) // compound link
1038 {
1039 QCString anchor;
1040 if (compound->definitionType()==Definition::TypeFile)
1041 {
1042 name=g_token->name;
1043 }
1044 else if (compound->definitionType()==Definition::TypeGroup)
1045 {
1046 name=((GroupDef*)compound)->groupTitle();
1047 }
1048 else if (compound->definitionType()==Definition::TypeClass)
1049 {
1050 anchor=((ClassDef*)compound)->anchor();
1051 }
1052 children.append(new
1053 DocLinkedWord(parent,name,
1054 compound->getReference(),
1055 compound->getOutputFileBase(),
1056 anchor,
1057 compound->briefDescriptionAsTooltip()
1058 )
1059 );
1060 }
1061 else if (compound->definitionType()==Definition::TypeFile &&
1062 ((FileDef*)compound)->generateSourceFile()
1063 ) // undocumented file that has source code we can link to
1064 {
1065 children.append(new
1066 DocLinkedWord(parent,g_token->name,
1067 compound->getReference(),
1068 compound->getSourceFileBase(),
1069 "",
1070 compound->briefDescriptionAsTooltip()
1071 )
1072 );
1073 }
1074 else // not linkable
1075 {
1076 children.append(new DocWord(parent,name));
1077 }
1078 }
1079 else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':')
1080 {
1081 // special case, where matching Foo: fails to be an Obj-C reference,
1082 // but Foo itself might be linkable.
1083 g_token->name=g_token->name.left(len-1);
1084 handleLinkedWord(parent,children);
1085 children.append(new DocWord(parent,":"));
1086 }
1087 else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p")))
1088 {
1089 // special case 2, where the token name is not a class, but could
1090 // be a Obj-C protocol
1091 children.append(new
1092 DocLinkedWord(parent,name,
1093 cd->getReference(),
1094 cd->getOutputFileBase(),
1095 cd->anchor(),
1096 cd->briefDescriptionAsTooltip()
1097 ));
1098 }
1099 else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-g")))
1100 {
1101 // special case 3, where the token name is not a class, but could
1102 // be a C# generic
1103 children.append(new
1104 DocLinkedWord(parent,name,
1105 cd->getReference(),
1106 cd->getOutputFileBase(),
1107 cd->anchor(),
1108 cd->briefDescriptionAsTooltip()
1109 ));
1110 }
1111 else // normal non-linkable word
1112 {
1113 if (g_token->name.left(1)=="#" || g_token->name.left(2)=="::")
1114 {
1115 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: explicit link request to '%s' could not be resolved",qPrint(name));
1116 children.append(new DocWord(parent,g_token->name));
1117 }
1118 else
1119 {
1120 children.append(new DocWord(parent,name));
1121 }
1122 }
1123}
1124
1125static void handleParameterType(DocNode *parent,QList<DocNode> &children,const QCString &paramTypes)
1126{
1127 QCString name = g_token->name;
1128 int p=0,i;
1129 QCString type;
1130 while ((i=paramTypes.find('|',p))!=-1)
1131 {
1132 g_token->name = paramTypes.mid(p,i-p);
1133 handleLinkedWord(parent,children);
1134 p=i+1;
1135 }
1136 g_token->name = paramTypes.mid(p);
1137 handleLinkedWord(parent,children);
1138 g_token->name = name;
1139}
1140
1141
1142/* Helper function that deals with the most common tokens allowed in
1143 * title like sections.
1144 * @param parent Parent node, owner of the children list passed as
1145 * the third argument.
1146 * @param tok The token to process.
1147 * @param children The list of child nodes to which the node representing
1148 * the token can be added.
1149 * @param handleWord Indicates if word token should be processed
1150 * @retval TRUE The token was handled.
1151 * @retval FALSE The token was not handled.
1152 */
1153static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool
1154 handleWord)
1155{
1156 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
1157 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
1158 tok==TK_COMMAND || tok==TK_HTMLTAG
1159 )
1160 {
1161 DBG((" name=%s",qPrint(g_token->name)));
1162 }
1163 DBG(("\n"));
1164reparsetoken:
1165 QCString tokenName = g_token->name;
1166 switch (tok)
1167 {
1168 case TK_COMMAND:
1169 switch (Mappers::cmdMapper->map(tokenName))
1170 {
1171 case CMD_BSLASH:
1172 children.append(new DocSymbol(parent,DocSymbol::BSlash));
1173 break;
1174 case CMD_AT:
1175 children.append(new DocSymbol(parent,DocSymbol::At));
1176 break;
1177 case CMD_LESS:
1178 children.append(new DocSymbol(parent,DocSymbol::Less));
1179 break;
1180 case CMD_GREATER:
1181 children.append(new DocSymbol(parent,DocSymbol::Greater));
1182 break;
1183 case CMD_AMP:
1184 children.append(new DocSymbol(parent,DocSymbol::Amp));
1185 break;
1186 case CMD_DOLLAR:
1187 children.append(new DocSymbol(parent,DocSymbol::Dollar));
1188 break;
1189 case CMD_HASH:
1190 children.append(new DocSymbol(parent,DocSymbol::Hash));
1191 break;
1192 case CMD_DCOLON:
1193 children.append(new DocSymbol(parent,DocSymbol::DoubleColon));
1194 break;
1195 case CMD_PERCENT:
1196 children.append(new DocSymbol(parent,DocSymbol::Percent));
1197 break;
1198 case CMD_QUOTE:
1199 children.append(new DocSymbol(parent,DocSymbol::Quot));
1200 break;
1201 case CMD_EMPHASIS:
1202 {
1203 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
1204 tok=handleStyleArgument(parent,children,tokenName);
1205 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
1206 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1207 if (tok==TK_NEWPARA) goto handlepara;
1208 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1209 {
1210 DBG(("CMD_EMPHASIS: reparsing command %s\n",qPrint(g_token->name)));
1211 goto reparsetoken;
1212 }
1213 }
1214 break;
1215 case CMD_BOLD:
1216 {
1217 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
1218 tok=handleStyleArgument(parent,children,tokenName);
1219 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
1220 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1221 if (tok==TK_NEWPARA) goto handlepara;
1222 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1223 {
1224 DBG(("CMD_BOLD: reparsing command %s\n",qPrint(g_token->name)));
1225 goto reparsetoken;
1226 }
1227 }
1228 break;
1229 case CMD_CODE:
1230 {
1231 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE));
1232 tok=handleStyleArgument(parent,children,tokenName);
1233 children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE));
1234 if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
1235 if (tok==TK_NEWPARA) goto handlepara;
1236 else if (tok==TK_WORD || tok==TK_HTMLTAG)
1237 {
1238 DBG(("CMD_CODE: reparsing command %s\n",qPrint(g_token->name)));
1239 goto reparsetoken;
1240 }
1241 }
1242 break;
1243 case CMD_HTMLONLY:
1244 {
1245 doctokenizerYYsetStateHtmlOnly();
1246 tok = doctokenizerYYlex();
1247 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
1248 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: htmlonly section ended without end marker");
1249 doctokenizerYYsetStatePara();
1250 }
1251 break;
1252 case CMD_MANONLY:
1253 {
1254 doctokenizerYYsetStateManOnly();
1255 tok = doctokenizerYYlex();
1256 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
1257 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: manonly section ended without end marker");
1258 doctokenizerYYsetStatePara();
1259 }
1260 break;
1261 case CMD_LATEXONLY:
1262 {
1263 doctokenizerYYsetStateLatexOnly();
1264 tok = doctokenizerYYlex();
1265 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
1266 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: latexonly section ended without end marker",doctokenizerYYlineno);
1267 doctokenizerYYsetStatePara();
1268 }
1269 break;
1270 case CMD_XMLONLY:
1271 {
1272 doctokenizerYYsetStateXmlOnly();
1273 tok = doctokenizerYYlex();
1274 children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
1275 if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: xmlonly section ended without end marker",doctokenizerYYlineno);
1276 doctokenizerYYsetStatePara();
1277 }
1278 break;
1279 case CMD_FORMULA:
1280 {
1281 DocFormula *form=new DocFormula(parent,g_token->id);
1282 children.append(form);
1283 }
1284 break;
1285 case CMD_ANCHOR:
1286 {
1287 tok=doctokenizerYYlex();
1288 if (tok!=TK_WHITESPACE)
1289 {
1290 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
1291 qPrint(tokenName));
1292 break;
1293 }
1294 tok=doctokenizerYYlex();
1295 if (tok==0)
1296 {
1297 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
1298 "argument of command %s",qPrint(tokenName));
1299 break;
1300 }
1301 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
1302 {
1303 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
1304 tokToString(tok),qPrint(tokenName));
1305 break;
1306 }
1307 DocAnchor *anchor = new DocAnchor(parent,g_token->name,FALSE);
1308 children.append(anchor);
1309 }
1310 break;
1311 case CMD_INTERNALREF:
1312 {
1313 tok=doctokenizerYYlex();
1314 if (tok!=TK_WHITESPACE)
1315 {
1316 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
1317 qPrint(tokenName));
1318 break;
1319 }
1320 doctokenizerYYsetStateInternalRef();
1321 tok=doctokenizerYYlex(); // get the reference id
1322 DocInternalRef *ref=0;
1323 if (tok!=TK_WORD && tok!=TK_LNKWORD)
1324 {
1325 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
1326 tokToString(tok),qPrint(tokenName));
1327 doctokenizerYYsetStatePara();
1328 break;
1329 }
1330 ref = new DocInternalRef(parent,g_token->name);
1331 children.append(ref);
1332 ref->parse();
1333 doctokenizerYYsetStatePara();
1334 }
1335 break;
1336 default:
1337 return FALSE;
1338 }
1339 break;
1340 case TK_HTMLTAG:
1341 {
1342 switch (Mappers::htmlTagMapper->map(tokenName))
1343 {
1344 case HTML_DIV:
1345 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <div> tag in heading\n");
1346 break;
1347 case HTML_PRE:
1348 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found <pre> tag in heading\n");
1349 break;
1350 case HTML_BOLD:
1351 if (!g_token->endTag)
1352 {
1353 handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs);
1354 }
1355 else
1356 {
1357 handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
1358 }
1359 break;
1360 case HTML_CODE:
1361 case XML_C:
1362 if (!g_token->endTag)
1363 {
1364 handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs);
1365 }
1366 else
1367 {
1368 handleStyleLeave(parent,children,DocStyleChange::Code,tokenName);
1369 }
1370 break;
1371 case HTML_EMPHASIS:
1372 if (!g_token->endTag)
1373 {
1374 handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs);
1375 }
1376 else
1377 {
1378 handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName);
1379 }
1380 break;
1381 case HTML_SUB:
1382 if (!g_token->endTag)
1383 {
1384 handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs);
1385 }
1386 else
1387 {
1388 handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName);
1389 }
1390 break;
1391 case HTML_SUP:
1392 if (!g_token->endTag)
1393 {
1394 handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs);
1395 }
1396 else
1397 {
1398 handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName);
1399 }
1400 break;
1401 case HTML_CENTER:
1402 if (!g_token->endTag)
1403 {
1404 handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs);
1405 }
1406 else
1407 {
1408 handleStyleLeave(parent,children,DocStyleChange::Center,tokenName);
1409 }
1410 break;
1411 case HTML_SMALL:
1412 if (!g_token->endTag)
1413 {
1414 handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs);
1415 }
1416 else
1417 {
1418 handleStyleLeave(parent,children,DocStyleChange::Small,tokenName);
1419 }
1420 break;
1421 default:
1422 return FALSE;
1423 break;
1424 }
1425 }
1426 break;
1427 case TK_SYMBOL:
1428 {
1429 char letter='\0';
1430 DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName,&letter);
1431 if (s!=DocSymbol::Unknown)
1432 {
1433 children.append(new DocSymbol(parent,s,letter));
1434 }
1435 else
1436 {
1437 return FALSE;
1438 }
1439 }
1440 break;
1441 case TK_WHITESPACE:
1442 case TK_NEWPARA:
1443handlepara:
1444 if (insidePRE(parent) || !children.isEmpty())
1445 {
1446 children.append(new DocWhiteSpace(parent,g_token->chars));
1447 }
1448 break;
1449 case TK_LNKWORD:
1450 if (handleWord)
1451 {
1452 handleLinkedWord(parent,children);
1453 }
1454 else
1455 return FALSE;
1456 break;
1457 case TK_WORD:
1458 if (handleWord)
1459 {
1460 children.append(new DocWord(parent,g_token->name));
1461 }
1462 else
1463 return FALSE;
1464 break;
1465 case TK_URL:
1466 if (g_insideHtmlLink)
1467 {
1468 children.append(new DocWord(parent,g_token->name));
1469 }
1470 else
1471 {
1472 children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr));
1473 }
1474 break;
1475 default:
1476 return FALSE;
1477 }
1478 return TRUE;
1479}
1480
1481
1482//---------------------------------------------------------------------------
1483
1484DocSymbol::SymType DocSymbol::decodeSymbol(const QCString &symName,char *letter)
1485{
1486 int l=symName.length();
1487 DBG(("decodeSymbol(%s) l=%d\n",qPrint(symName),l));
1488 if (symName=="&copy;") return DocSymbol::Copy;
1489 else if (symName=="&trade;") return DocSymbol::Tm;
1490 else if (symName=="&tm;") return DocSymbol::Tm; // alias for &trade;
1491 else if (symName=="&reg;") return DocSymbol::Reg;
1492 else if (symName=="&lt;") return DocSymbol::Less;
1493 else if (symName=="&gt;") return DocSymbol::Greater;
1494 else if (symName=="&amp;") return DocSymbol::Amp;
1495 else if (symName=="&apos;") return DocSymbol::Apos;
1496 else if (symName=="&quot;") return DocSymbol::Quot;
1497 else if (symName=="&lsquo;") return DocSymbol::Lsquo;
1498 else if (symName=="&rsquo;") return DocSymbol::Rsquo;
1499 else if (symName=="&ldquo;") return DocSymbol::Ldquo;
1500 else if (symName=="&rdquo;") return DocSymbol::Rdquo;
1501 else if (symName=="&ndash;") return DocSymbol::Ndash;
1502 else if (symName=="&mdash;") return DocSymbol::Mdash;
1503 else if (symName=="&szlig;") return DocSymbol::Szlig;
1504 else if (symName=="&nbsp;") return DocSymbol::Nbsp;
1505 else if (symName=="&AElig;") return DocSymbol::AElig;
1506 else if (symName=="&aelig;") return DocSymbol::Aelig;
1507 else if (l==6 && symName.right(4)=="uml;")
1508 {
1509 *letter=symName.at(1);
1510 return DocSymbol::Uml;
1511 }
1512 else if (l==8 && symName.right(6)=="acute;")
1513 {
1514 *letter=symName.at(1);
1515 return DocSymbol::Acute;
1516 }
1517 else if (l==8 && symName.right(6)=="grave;")
1518 {
1519 *letter=symName.at(1);
1520 return DocSymbol::Grave;
1521 }
1522 else if (l==7 && symName.right(5)=="circ;")
1523 {
1524 *letter=symName.at(1);
1525 return DocSymbol::Circ;
1526 }
1527 else if (l==8 && symName.right(6)=="tilde;")
1528 {
1529 *letter=symName.at(1);
1530 return DocSymbol::Tilde;
1531 }
1532 else if (l==8 && symName.right(6)=="cedil;")
1533 {
1534 *letter=symName.at(1);
1535 return DocSymbol::Cedil;
1536 }
1537 else if (l==7 && symName.right(5)=="ring;")
1538 {
1539 *letter=symName.at(1);
1540 return DocSymbol::Ring;
1541 }
1542 else if (l==8 && symName.right(6)=="slash;")
1543 {
1544 *letter=symName.at(1);
1545 return DocSymbol::Slash;
1546 }
1547 return DocSymbol::Unknown;
1548}
1549
1550//---------------------------------------------------------------------------
1551
1552static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
1553 const QCString &doc)
1554{
1555 int retval = RetVal_OK;
1556
1557 if (doc.isEmpty()) return retval;
1558
1559 doctokenizerYYinit(doc,g_fileName);
1560
1561 // first parse any number of paragraphs
1562 bool isFirst=TRUE;
1563 DocPara *lastPar=0;
1564 if (!children.isEmpty() && children.last()->kind()==DocNode::Kind_Para)
1565 { // last child item was a paragraph
1566 lastPar = (DocPara*)children.last();
1567 isFirst=FALSE;
1568 }
1569 do
1570 {
1571 DocPara *par = new DocPara(parent);
1572 if (isFirst) { par->markFirst(); isFirst=FALSE; }
1573 retval=par->parse();
1574 if (!par->isEmpty())
1575 {
1576 children.append(par);
1577 if (lastPar) lastPar->markLast(FALSE);
1578 lastPar=par;
1579 }
1580 else
1581 {
1582 delete par;
1583 }
1584 } while (retval==TK_NEWPARA);
1585 if (lastPar) lastPar->markLast();
1586
1587 return retval;
1588}
1589
1590//---------------------------------------------------------------------------
1591
1592static void readTextFileByName(const QCString &file,QCString &text)
1593{
1594 QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
1595 char *s=examplePathList.first();
1596 while (s)
1597 {
1598 QCString absFileName = QCString(s)+portable_pathSeparator()+file;
1599 QFileInfo fi(absFileName);
1600 if (fi.exists())
1601 {
1602 text = fileToString(absFileName,Config_getBool("FILTER_SOURCE_FILES"));
1603 return;
1604 }
1605 s=examplePathList.next();
1606 }
1607
1608 // as a fallback we also look in the exampleNameDict
1609 bool ambig;
1610 FileDef *fd;
1611 if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
1612 {
1613 text = fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES"));
1614 }
1615 else if (ambig)
1616 {
1617 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included file name %s is ambiguous"
1618 "Possible candidates:\n%s",qPrint(file),
1619 qPrint(showFileDefMatches(Doxygen::exampleNameDict,file))
1620 );
1621 }
1622 else
1623 {
1624 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included file %s is not found. "
1625 "Check your EXAMPLE_PATH",qPrint(file));
1626 }
1627}
1628
1629//---------------------------------------------------------------------------
1630
1631DocWord::DocWord(DocNode *parent,const QCString &word) :
1632 m_word(word)
1633{
1634 m_parent = parent;
1635 //printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
1636 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1637 {
1638 Doxygen::searchIndex->addWord(word,FALSE);
1639 }
1640}
1641
1642//---------------------------------------------------------------------------
1643
1644DocLinkedWord::DocLinkedWord(DocNode *parent,const QCString &word,
1645 const QCString &ref,const QCString &file,
1646 const QCString &anchor,const QCString &tooltip) :
1647 m_word(word), m_ref(ref),
1648 m_file(file), m_relPath(g_relPath), m_anchor(anchor),
1649 m_tooltip(tooltip)
1650{
1651 m_parent = parent;
1652 //printf("DocLinkedWord: new word %s url=%s tooltip='%s'\n",
1653 // word.data(),g_searchUrl.data(),tooltip.data());
1654 if (Doxygen::searchIndex && !g_searchUrl.isEmpty())
1655 {
1656 Doxygen::searchIndex->addWord(word,FALSE);
1657 }
1658}
1659
1660//---------------------------------------------------------------------------
1661
1662DocAnchor::DocAnchor(DocNode *parent,const QCString &id,bool newAnchor)
1663{
1664 m_parent = parent;
1665 if (id.isEmpty())
1666 {
1667 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Empty anchor label");
1668 }
1669 if (newAnchor) // found <a name="label">
1670 {
1671 m_anchor = id;
1672 }
1673 else // found \anchor label
1674 {
1675 SectionInfo *sec = Doxygen::sectionDict[id];
1676 if (sec)
1677 {
1678 //printf("Found anchor %s\n",id.data());
1679 m_file = sec->fileName;
1680 m_anchor = sec->label;
1681 if (g_sectionDict && g_sectionDict->find(id)==0)
1682 {
1683 //printf("Inserting in dictionary!\n");
1684 g_sectionDict->insert(id,sec);
1685 }
1686 }
1687 else
1688 {
1689 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid anchor id `%s'",qPrint(id));
1690 m_anchor = "invalid";
1691 m_file = "invalid";
1692 }
1693 }
1694}
1695
1696//---------------------------------------------------------------------------
1697
1698DocVerbatim::DocVerbatim(DocNode *parent,const QCString &context,
1699 const QCString &text, Type t,bool isExample,
1700 const QCString &exampleFile)
1701 : m_context(context), m_text(text), m_type(t),
1702 m_isExample(isExample), m_exampleFile(exampleFile), m_relPath(g_relPath)
1703{
1704 m_parent = parent;
1705}
1706
1707
1708//---------------------------------------------------------------------------
1709
1710void DocInclude::parse()
1711{
1712 DBG(("DocInclude::parse(file=%s,text=%s)\n",qPrint(m_file),qPrint(m_text)));
1713 switch(m_type)
1714 {
1715 case IncWithLines:
1716 // fall through
1717 case Include:
1718 // fall through
1719 case DontInclude:
1720 readTextFileByName(m_file,m_text);
1721 g_includeFileText = m_text;
1722 g_includeFileOffset = 0;
1723 g_includeFileLength = m_text.length();
1724 //printf("g_includeFile=<<%s>>\n",g_includeFileText.data());
1725 break;
1726 case VerbInclude:
1727 // fall through
1728 case HtmlInclude:
1729 readTextFileByName(m_file,m_text);
1730 break;
1731 }
1732}
1733
1734//---------------------------------------------------------------------------
1735
1736void DocIncOperator::parse()
1737{
1738 const char *p = g_includeFileText;
1739 uint l = g_includeFileLength;
1740 uint o = g_includeFileOffset;
1741 DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",qPrint(p),o,l));
1742 uint so = o,bo;
1743 bool nonEmpty = FALSE;
1744 switch(type())
1745 {
1746 case Line:
1747 while (o<l)
1748 {
1749 char c = p[o];
1750 if (c=='\n')
1751 {
1752 if (nonEmpty) break; // we have a pattern to match
1753 so=o+1; // no pattern, skip empty line
1754 }
1755 else if (!isspace((uchar)c)) // no white space char
1756 {
1757 nonEmpty=TRUE;
1758 }
1759 o++;
1760 }
1761 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1762 {
1763 m_text = g_includeFileText.mid(so,o-so);
1764 DBG(("DocIncOperator::parse() Line: %s\n",qPrint(m_text)));
1765 }
1766 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1767 break;
1768 case SkipLine:
1769 while (o<l)
1770 {
1771 so=o;
1772 while (o<l)
1773 {
1774 char c = p[o];
1775 if (c=='\n')
1776 {
1777 if (nonEmpty) break; // we have a pattern to match
1778 so=o+1; // no pattern, skip empty line
1779 }
1780 else if (!isspace((uchar)c)) // no white space char
1781 {
1782 nonEmpty=TRUE;
1783 }
1784 o++;
1785 }
1786 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1787 {
1788 m_text = g_includeFileText.mid(so,o-so);
1789 DBG(("DocIncOperator::parse() SkipLine: %s\n",qPrint(m_text)));
1790 break;
1791 }
1792 o++; // skip new line
1793 }
1794 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1795 break;
1796 case Skip:
1797 while (o<l)
1798 {
1799 so=o;
1800 while (o<l)
1801 {
1802 char c = p[o];
1803 if (c=='\n')
1804 {
1805 if (nonEmpty) break; // we have a pattern to match
1806 so=o+1; // no pattern, skip empty line
1807 }
1808 else if (!isspace((uchar)c)) // no white space char
1809 {
1810 nonEmpty=TRUE;
1811 }
1812 o++;
1813 }
1814 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1815 {
1816 break;
1817 }
1818 o++; // skip new line
1819 }
1820 g_includeFileOffset = so; // set pointer to start of new line
1821 break;
1822 case Until:
1823 bo=o;
1824 while (o<l)
1825 {
1826 so=o;
1827 while (o<l)
1828 {
1829 char c = p[o];
1830 if (c=='\n')
1831 {
1832 if (nonEmpty) break; // we have a pattern to match
1833 so=o+1; // no pattern, skip empty line
1834 }
1835 else if (!isspace((uchar)c)) // no white space char
1836 {
1837 nonEmpty=TRUE;
1838 }
1839 o++;
1840 }
1841 if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
1842 {
1843 m_text = g_includeFileText.mid(bo,o-bo);
1844 DBG(("DocIncOperator::parse() Until: %s\n",qPrint(m_text)));
1845 break;
1846 }
1847 o++; // skip new line
1848 }
1849 g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
1850 break;
1851 }
1852}
1853
1854//---------------------------------------------------------------------------
1855
1856void DocCopy::parse()
1857{
1858 QCString doc,brief;
1859 Definition *def;
1860 if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
1861 {
1862 if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
1863 {
1864 bool hasParamCommand = g_hasParamCommand;
1865 bool hasReturnCommand = g_hasReturnCommand;
1866 QDict<void> paramsFound = g_paramsFound;
1867 //printf("..1 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
1868 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
1869
1870 docParserPushContext(FALSE);
1871 g_scope = def;
1872 if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
1873 {
1874 if (def->getOuterScope()!=Doxygen::globalScope)
1875 {
1876 g_context=def->getOuterScope()->name();
1877 }
1878 }
1879 else if (def!=Doxygen::globalScope)
1880 {
1881 g_context=def->name();
1882 }
1883 g_styleStack.clear();
1884 g_nodeStack.clear();
1885 g_paramsFound.clear();
1886 g_copyStack.append(def);
1887 // make sure the descriptions end with a newline, so the parser will correctly
1888 // handle them in all cases.
1889 //printf("doc='%s'\n",doc.data());
1890 //printf("brief='%s'\n",brief.data());
1891 if (m_copyBrief)
1892 {
1893 brief+='\n';
1894 internalValidatingParseDoc(this,m_children,brief);
1895
1896 //printf("..2 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
1897 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
1898 hasParamCommand = hasParamCommand || g_hasParamCommand;
1899 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
1900 QDictIterator<void> it(g_paramsFound);
1901 void *item;
1902 for (;(item=it.current());++it)
1903 {
1904 paramsFound.insert(it.currentKey(),it.current());
1905 }
1906 }
1907 if (m_copyDetails)
1908 {
1909 doc+='\n';
1910 internalValidatingParseDoc(this,m_children,doc);
1911
1912 //printf("..3 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
1913 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
1914 hasParamCommand = hasParamCommand || g_hasParamCommand;
1915 hasReturnCommand = hasReturnCommand || g_hasReturnCommand;
1916 QDictIterator<void> it(g_paramsFound);
1917 void *item;
1918 for (;(item=it.current());++it)
1919 {
1920 paramsFound.insert(it.currentKey(),it.current());
1921 }
1922 }
1923 g_copyStack.remove(def);
1924 ASSERT(g_styleStack.isEmpty());
1925 ASSERT(g_nodeStack.isEmpty());
1926 docParserPopContext(TRUE);
1927
1928 g_hasParamCommand = hasParamCommand;
1929 g_hasReturnCommand = hasReturnCommand;
1930 g_paramsFound = paramsFound;
1931
1932 //printf("..4 hasParamCommand=%d hasReturnCommand=%d paramsFound=%d\n",
1933 // g_hasParamCommand,g_hasReturnCommand,g_paramsFound.count());
1934 }
1935 else // oops, recursion
1936 {
1937 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: recursive call chain of \\copydoc commands detected at %d\n",
1938 doctokenizerYYlineno);
1939 }
1940 }
1941 else
1942 {
1943 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: target %s of \\copydoc command not found",
1944 qPrint(m_link));
1945 }
1946}
1947
1948//---------------------------------------------------------------------------
1949
1950DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) :
1951 m_id(id), m_key(key), m_relPath(g_relPath)
1952{
1953 m_parent = parent;
1954}
1955
1956bool DocXRefItem::parse()
1957{
1958 QCString listName;
1959 RefList *refList = Doxygen::xrefLists->find(m_key);
1960 if (refList &&
1961 (
1962 // either not a built-in list or the list is enabled
1963 (m_key!="todo" || Config_getBool("GENERATE_TODOLIST")) &&
1964 (m_key!="test" || Config_getBool("GENERATE_TESTLIST")) &&
1965 (m_key!="bug" || Config_getBool("GENERATE_BUGLIST")) &&
1966 (m_key!="deprecated" || Config_getBool("GENERATE_DEPRECATEDLIST"))
1967 )
1968 )
1969 {
1970 RefItem *item = refList->getRefItem(m_id);
1971 ASSERT(item!=0);
1972 if (item)
1973 {
1974 if (g_memberDef && g_memberDef->name().at(0)=='@')
1975 {
1976 m_file = "@"; // can't cross reference anonymous enum
1977 m_anchor = "@";
1978 }
1979 else
1980 {
1981 m_file = convertNameToFile(refList->listName(),FALSE,TRUE);
1982 m_anchor = item->listAnchor;
1983 }
1984 m_title = refList->sectionTitle();
1985 //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
1986 // m_file.data(),m_anchor.data(),m_title.data());
1987
1988 if (!item->text.isEmpty())
1989 {
1990 docParserPushContext();
1991 internalValidatingParseDoc(this,m_children,item->text);
1992 docParserPopContext();
1993 }
1994 }
1995 return TRUE;
1996 }
1997 return FALSE;
1998}
1999
2000//---------------------------------------------------------------------------
2001
2002DocFormula::DocFormula(DocNode *parent,int id) :
2003 m_relPath(g_relPath)
2004{
2005 m_parent = parent;
2006 QCString formCmd;
2007 formCmd.sprintf("\\form#%d",id);
2008 Formula *formula=Doxygen::formulaNameDict[formCmd];
2009 if (formula)
2010 {
2011 m_id = formula->getId();
2012 m_name.sprintf("form_%d",m_id);
2013 m_text = formula->getFormulaText();
2014 }
2015}
2016
2017//---------------------------------------------------------------------------
2018
2019//int DocLanguage::parse()
2020//{
2021// int retval;
2022// DBG(("DocLanguage::parse() start\n"));
2023// g_nodeStack.push(this);
2024//
2025// // parse one or more paragraphs
2026// bool isFirst=TRUE;
2027// DocPara *par=0;
2028// do
2029// {
2030// par = new DocPara(this);
2031// if (isFirst) { par->markFirst(); isFirst=FALSE; }
2032// m_children.append(par);
2033// retval=par->parse();
2034// }
2035// while (retval==TK_NEWPARA);
2036// if (par) par->markLast();
2037//
2038// DBG(("DocLanguage::parse() end\n"));
2039// DocNode *n = g_nodeStack.pop();
2040// ASSERT(n==this);
2041// return retval;
2042//}
2043
2044//---------------------------------------------------------------------------
2045
2046void DocSecRefItem::parse()
2047{
2048 DBG(("DocSecRefItem::parse() start\n"));
2049 g_nodeStack.push(this);
2050
2051 doctokenizerYYsetStateTitle();
2052 int tok;
2053 while ((tok=doctokenizerYYlex()))
2054 {
2055 if (!defaultHandleToken(this,tok,m_children))
2056 {
2057 switch (tok)
2058 {
2059 case TK_COMMAND:
2060 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\refitem",
2061 qPrint(g_token->name));
2062 break;
2063 case TK_SYMBOL:
2064 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2065 qPrint(g_token->name));
2066 break;
2067 default:
2068 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2069 tokToString(tok));
2070 break;
2071 }
2072 }
2073 }
2074 doctokenizerYYsetStatePara();
2075 handlePendingStyleCommands(this,m_children);
2076
2077 SectionInfo *sec=0;
2078 if (!m_target.isEmpty())
2079 {
2080 sec=Doxygen::sectionDict[m_target];
2081 if (sec)
2082 {
2083 m_file = sec->fileName;
2084 m_anchor = sec->label;
2085 if (g_sectionDict && g_sectionDict->find(m_target)==0)
2086 {
2087 g_sectionDict->insert(m_target,sec);
2088 }
2089 }
2090 else
2091 {
2092 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: reference to unknown section %s",
2093 qPrint(m_target));
2094 }
2095 }
2096 else
2097 {
2098 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: reference to empty target");
2099 }
2100
2101 DBG(("DocSecRefItem::parse() end\n"));
2102 DocNode *n = g_nodeStack.pop();
2103 ASSERT(n==this);
2104}
2105
2106//---------------------------------------------------------------------------
2107
2108void DocSecRefList::parse()
2109{
2110 DBG(("DocSecRefList::parse() start\n"));
2111 g_nodeStack.push(this);
2112
2113 int tok=doctokenizerYYlex();
2114 // skip white space
2115 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
2116 // handle items
2117 while (tok)
2118 {
2119 if (tok==TK_COMMAND)
2120 {
2121 switch (Mappers::cmdMapper->map(g_token->name))
2122 {
2123 case CMD_SECREFITEM:
2124 {
2125 int tok=doctokenizerYYlex();
2126 if (tok!=TK_WHITESPACE)
2127 {
2128 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after \\refitem command");
2129 break;
2130 }
2131 tok=doctokenizerYYlex();
2132 if (tok!=TK_WORD && tok!=TK_LNKWORD)
2133 {
2134 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of \\refitem",
2135 tokToString(tok));
2136 break;
2137 }
2138
2139 DocSecRefItem *item = new DocSecRefItem(this,g_token->name);
2140 m_children.append(item);
2141 item->parse();
2142 }
2143 break;
2144 case CMD_ENDSECREFLIST:
2145 goto endsecreflist;
2146 default:
2147 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\secreflist",
2148 qPrint(g_token->name));
2149 goto endsecreflist;
2150 }
2151 }
2152 else if (tok==TK_WHITESPACE)
2153 {
2154 // ignore whitespace
2155 }
2156 else
2157 {
2158 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s inside section reference list",
2159 tokToString(tok));
2160 goto endsecreflist;
2161 }
2162 tok=doctokenizerYYlex();
2163 }
2164
2165endsecreflist:
2166 DBG(("DocSecRefList::parse() end\n"));
2167 DocNode *n = g_nodeStack.pop();
2168 ASSERT(n==this);
2169}
2170
2171//---------------------------------------------------------------------------
2172
2173DocInternalRef::DocInternalRef(DocNode *parent,const QCString &ref)
2174 : m_relPath(g_relPath)
2175{
2176 m_parent = parent;
2177 int i=ref.find('#');
2178 if (i!=-1)
2179 {
2180 m_anchor = ref.right(ref.length()-i-1);
2181 m_file = ref.left(i);
2182 }
2183 else
2184 {
2185 m_file = ref;
2186 }
2187}
2188
2189void DocInternalRef::parse()
2190{
2191 g_nodeStack.push(this);
2192 DBG(("DocInternalRef::parse() start\n"));
2193
2194 int tok;
2195 while ((tok=doctokenizerYYlex()))
2196 {
2197 if (!defaultHandleToken(this,tok,m_children))
2198 {
2199 switch (tok)
2200 {
2201 case TK_COMMAND:
2202 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\ref",
2203 qPrint(g_token->name));
2204 break;
2205 case TK_SYMBOL:
2206 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2207 qPrint(g_token->name));
2208 break;
2209 default:
2210 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2211tokToString(tok));
2212 break;
2213 }
2214 }
2215 }
2216
2217 handlePendingStyleCommands(this,m_children);
2218 DBG(("DocInternalRef::parse() end\n"));
2219 DocNode *n=g_nodeStack.pop();
2220 ASSERT(n==this);
2221}
2222
2223//---------------------------------------------------------------------------
2224
2225DocRef::DocRef(DocNode *parent,const QCString &target,const QCString &context) :
2226 m_refToSection(FALSE), m_refToAnchor(FALSE)
2227{
2228 m_parent = parent;
2229 Definition *compound = 0;
2230 QCString anchor;
2231 //printf("DocRef::DocRef(target=%s,context=%s\n",target.data(),context.data());
2232 ASSERT(!target.isEmpty());
2233 m_relPath = g_relPath;
2234 SectionInfo *sec = Doxygen::sectionDict[target];
2235 if (sec) // ref to section or anchor
2236 {
2237 m_text = sec->title;
2238 if (m_text.isEmpty()) m_text = sec->label;
2239
2240 m_ref = sec->ref;
2241 m_file = stripKnownExtensions(sec->fileName);
2242 if (sec->type!=SectionInfo::Page) m_anchor = sec->label;
2243 m_refToAnchor = sec->type==SectionInfo::Anchor;
2244 m_refToSection = sec->type!=SectionInfo::Anchor;
2245 //printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d type=%d\n",
2246 // m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor,sec->type);
2247 return;
2248 }
2249 else if (resolveLink(context,target,TRUE,&compound,anchor))
2250 {
2251 bool isFile = compound ?
2252 (compound->definitionType()==Definition::TypeFile ? TRUE : FALSE) :
2253 FALSE;
2254 m_text = linkToText(target,isFile);
2255 m_anchor = anchor;
2256 if (compound && compound->isLinkable()) // ref to compound
2257 {
2258 if (anchor.isEmpty() && /* compound link */
2259 compound->definitionType()==Definition::TypeGroup && /* is group */
2260 ((GroupDef *)compound)->groupTitle() /* with title */
2261 )
2262 {
2263 m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link
2264 }
2265 else if (compound->definitionType()==Definition::TypeMember &&
2266 ((MemberDef*)compound)->isObjCMethod())
2267 {
2268 // Objective C Method
2269 MemberDef *member = (MemberDef*)compound;
2270 bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
2271 m_text = member->objCMethodName(localLink,g_inSeeBlock);
2272 }
2273
2274 m_file = compound->getOutputFileBase();
2275 m_ref = compound->getReference();
2276 return;
2277 }
2278 else if (compound->definitionType()==Definition::TypeFile &&
2279 ((FileDef*)compound)->generateSourceFile()
2280 ) // undocumented file that has source code we can link to
2281 {
2282 m_file = compound->getSourceFileBase();
2283 m_ref = compound->getReference();
2284 return;
2285 }
2286 }
2287 m_text = linkToText(target,FALSE);
2288 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve reference to `%s' for \\ref command",
2289 qPrint(target));
2290}
2291
2292static void flattenParagraphs(DocNode *root,QList<DocNode> &children)
2293{
2294 QListIterator<DocNode> li(children);
2295 QList<DocNode> newChildren;
2296 DocNode *dn;
2297 for (li.toFirst();(dn=li.current());++li)
2298 {
2299 if (dn->kind()==DocNode::Kind_Para)
2300 {
2301 DocPara *para = (DocPara*)dn;
2302 QList<DocNode> &paraChildren = para->children();
2303 paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node
2304 QListIterator<DocNode> li2(paraChildren);
2305 DocNode *dn2;
2306 for (li2.toFirst();(dn2=li2.current());++li2)
2307 {
2308 newChildren.append(dn2); // add them to new node
2309 }
2310 }
2311 }
2312 children.clear();
2313 QListIterator<DocNode> li3(newChildren);
2314 for (li3.toFirst();(dn=li3.current());++li3)
2315 {
2316 children.append(dn);
2317 dn->setParent(root);
2318 }
2319}
2320
2321void DocRef::parse()
2322{
2323 g_nodeStack.push(this);
2324 DBG(("DocRef::parse() start\n"));
2325
2326 int tok;
2327 while ((tok=doctokenizerYYlex()))
2328 {
2329 if (!defaultHandleToken(this,tok,m_children))
2330 {
2331 switch (tok)
2332 {
2333 case TK_COMMAND:
2334 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\ref",
2335 qPrint(g_token->name));
2336 break;
2337 case TK_SYMBOL:
2338 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2339 qPrint(g_token->name));
2340 break;
2341 case TK_HTMLTAG:
2342 break;
2343 default:
2344 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2345tokToString(tok));
2346 break;
2347 }
2348 }
2349 }
2350
2351 if (m_children.isEmpty() && !m_text.isEmpty())
2352 {
2353 g_insideHtmlLink=TRUE;
2354 docParserPushContext();
2355 internalValidatingParseDoc(this,m_children,m_text);
2356 docParserPopContext();
2357 g_insideHtmlLink=FALSE;
2358 flattenParagraphs(this,m_children);
2359 }
2360
2361 handlePendingStyleCommands(this,m_children);
2362
2363 DocNode *n=g_nodeStack.pop();
2364 ASSERT(n==this);
2365}
2366
2367//---------------------------------------------------------------------------
2368
2369DocLink::DocLink(DocNode *parent,const QCString &target)
2370{
2371 m_parent = parent;
2372 Definition *compound;
2373 //PageInfo *page;
2374 QCString anchor;
2375 m_refText = target;
2376 m_relPath = g_relPath;
2377 if (!m_refText.isEmpty() && m_refText.at(0)=='#')
2378 {
2379 m_refText = m_refText.right(m_refText.length()-1);
2380 }
2381 if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock,
2382 &compound,anchor))
2383 {
2384 m_anchor = anchor;
2385 if (compound && compound->isLinkable())
2386 {
2387 m_file = compound->getOutputFileBase();
2388 m_ref = compound->getReference();
2389 }
2390 else if (compound->definitionType()==Definition::TypeFile &&
2391 ((FileDef*)compound)->generateSourceFile()
2392 ) // undocumented file that has source code we can link to
2393 {
2394 m_file = compound->getSourceFileBase();
2395 m_ref = compound->getReference();
2396 }
2397 return;
2398 }
2399
2400 // bogus link target
2401 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unable to resolve link to `%s' for \\link command",
2402 qPrint(target));
2403}
2404
2405
2406QCString DocLink::parse(bool isJavaLink,bool isXmlLink)
2407{
2408 QCString result;
2409 g_nodeStack.push(this);
2410 DBG(("DocLink::parse() start\n"));
2411
2412 int tok;
2413 while ((tok=doctokenizerYYlex()))
2414 {
2415 if (!defaultHandleToken(this,tok,m_children,FALSE))
2416 {
2417 switch (tok)
2418 {
2419 case TK_COMMAND:
2420 switch (Mappers::cmdMapper->map(g_token->name))
2421 {
2422 case CMD_ENDLINK:
2423 if (isJavaLink)
2424 {
2425 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: {@link.. ended with @endlink command");
2426 }
2427 goto endlink;
2428 default:
2429 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\link",
2430 qPrint(g_token->name));
2431 break;
2432 }
2433 break;
2434 case TK_SYMBOL:
2435 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2436 qPrint(g_token->name));
2437 break;
2438 case TK_HTMLTAG:
2439 if (g_token->name!="see" || !isXmlLink)
2440 {
2441 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected xml/html command %s found",
2442 qPrint(g_token->name));
2443 }
2444 goto endlink;
2445 case TK_LNKWORD:
2446 case TK_WORD:
2447 if (isJavaLink) // special case to detect closing }
2448 {
2449 QCString w = g_token->name;
2450 int p;
2451 if (w=="}")
2452 {
2453 goto endlink;
2454 }
2455 else if ((p=w.find('}'))!=-1)
2456 {
2457 uint l=w.length();
2458 m_children.append(new DocWord(this,w.left(p)));
2459 if ((uint)p<l-1) // something left after the } (for instance a .)
2460 {
2461 result=w.right(l-p-1);
2462 }
2463 goto endlink;
2464 }
2465 }
2466 m_children.append(new DocWord(this,g_token->name));
2467 break;
2468 default:
2469 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2470 tokToString(tok));
2471 break;
2472 }
2473 }
2474 }
2475 if (tok==0)
2476 {
2477 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
2478 " link command\n");
2479 }
2480endlink:
2481
2482 if (m_children.isEmpty()) // no link text
2483 {
2484 m_children.append(new DocWord(this,m_refText));
2485 }
2486
2487 handlePendingStyleCommands(this,m_children);
2488 DBG(("DocLink::parse() end\n"));
2489 DocNode *n=g_nodeStack.pop();
2490 ASSERT(n==this);
2491 return result;
2492}
2493
2494
2495//---------------------------------------------------------------------------
2496
2497DocDotFile::DocDotFile(DocNode *parent,const QCString &name,const QCString &context) :
2498 m_name(name), m_relPath(g_relPath), m_context(context)
2499{
2500 m_parent = parent;
2501}
2502
2503void DocDotFile::parse()
2504{
2505 g_nodeStack.push(this);
2506 DBG(("DocDotFile::parse() start\n"));
2507
2508 doctokenizerYYsetStateTitle();
2509 int tok;
2510 while ((tok=doctokenizerYYlex()))
2511 {
2512 if (!defaultHandleToken(this,tok,m_children))
2513 {
2514 switch (tok)
2515 {
2516 case TK_COMMAND:
2517 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\dotfile",
2518 qPrint(g_token->name));
2519 break;
2520 case TK_SYMBOL:
2521 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2522 qPrint(g_token->name));
2523 break;
2524 default:
2525 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2526tokToString(tok));
2527 break;
2528 }
2529 }
2530 }
2531 tok=doctokenizerYYlex();
2532 while (tok==TK_WORD) // there are values following the title
2533 {
2534 if (g_token->name=="width")
2535 {
2536 m_width=g_token->chars;
2537 }
2538 else if (g_token->name=="height")
2539 {
2540 m_height=g_token->chars;
2541 }
2542 else
2543 {
2544 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title",
2545 qPrint(g_token->name));
2546 }
2547 tok=doctokenizerYYlex();
2548 }
2549 ASSERT(tok==0);
2550 doctokenizerYYsetStatePara();
2551 handlePendingStyleCommands(this,m_children);
2552
2553 bool ambig;
2554 FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig);
2555 if (fd==0 && m_name.right(4)!=".dot") // try with .dot extension as well
2556 {
2557 fd = findFileDef(Doxygen::dotFileNameDict,m_name+".dot",ambig);
2558 }
2559 if (fd)
2560 {
2561 m_file = fd->absFilePath();
2562 }
2563 else if (ambig)
2564 {
2565 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included dot file name %s is ambiguous.\n"
2566 "Possible candidates:\n%s",qPrint(m_name),
2567 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2568 );
2569 }
2570 else
2571 {
2572 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included dot file %s is not found "
2573 "in any of the paths specified via DOTFILE_DIRS!",qPrint(m_name));
2574 }
2575
2576 DBG(("DocDotFile::parse() end\n"));
2577 DocNode *n=g_nodeStack.pop();
2578 ASSERT(n==this);
2579}
2580
2581DocMscFile::DocMscFile(DocNode *parent,const QCString &name,const QCString &context) :
2582 m_name(name), m_relPath(g_relPath), m_context(context)
2583{
2584 m_parent = parent;
2585}
2586
2587void DocMscFile::parse()
2588{
2589 g_nodeStack.push(this);
2590 DBG(("DocMscFile::parse() start\n"));
2591
2592 doctokenizerYYsetStateTitle();
2593 int tok;
2594 while ((tok=doctokenizerYYlex()))
2595 {
2596 if (!defaultHandleToken(this,tok,m_children))
2597 {
2598 switch (tok)
2599 {
2600 case TK_COMMAND:
2601 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\mscfile",
2602 qPrint(g_token->name));
2603 break;
2604 case TK_SYMBOL:
2605 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2606 qPrint(g_token->name));
2607 break;
2608 default:
2609 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2610tokToString(tok));
2611 break;
2612 }
2613 }
2614 }
2615 tok=doctokenizerYYlex();
2616 while (tok==TK_WORD) // there are values following the title
2617 {
2618 if (g_token->name=="width")
2619 {
2620 m_width=g_token->chars;
2621 }
2622 else if (g_token->name=="height")
2623 {
2624 m_height=g_token->chars;
2625 }
2626 else
2627 {
2628 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title",
2629 qPrint(g_token->name));
2630 }
2631 tok=doctokenizerYYlex();
2632 }
2633 ASSERT(tok==0);
2634 doctokenizerYYsetStatePara();
2635 handlePendingStyleCommands(this,m_children);
2636
2637 bool ambig;
2638 FileDef *fd = findFileDef(Doxygen::mscFileNameDict,m_name,ambig);
2639 if (fd==0 && m_name.right(4)!=".msc") // try with .msc extension as well
2640 {
2641 fd = findFileDef(Doxygen::mscFileNameDict,m_name+".msc",ambig);
2642 }
2643 if (fd)
2644 {
2645 m_file = fd->absFilePath();
2646 }
2647 else if (ambig)
2648 {
2649 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included msc file name %s is ambiguous.\n"
2650 "Possible candidates:\n%s",qPrint(m_name),
2651 qPrint(showFileDefMatches(Doxygen::exampleNameDict,m_name))
2652 );
2653 }
2654 else
2655 {
2656 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: included msc file %s is not found "
2657 "in any of the paths specified via MSCFILE_DIRS!",qPrint(m_name));
2658 }
2659
2660 DBG(("DocMscFile::parse() end\n"));
2661 DocNode *n=g_nodeStack.pop();
2662 ASSERT(n==this);
2663}
2664
2665
2666
2667//---------------------------------------------------------------------------
2668
2669DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QCString &name,Type t) :
2670 m_attribs(attribs), m_name(name),
2671 m_type(t), m_relPath(g_relPath)
2672{
2673 m_parent = parent;
2674}
2675
2676void DocImage::parse()
2677{
2678 g_nodeStack.push(this);
2679 DBG(("DocImage::parse() start\n"));
2680
2681 // parse title
2682 doctokenizerYYsetStateTitle();
2683 int tok;
2684 while ((tok=doctokenizerYYlex()))
2685 {
2686 if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height="))
2687 {
2688 // special case: no title, but we do have a size indicator
2689 doctokenizerYYsetStateTitleAttrValue();
2690 // strip =
2691 g_token->name=g_token->name.left(g_token->name.length()-1);
2692 break;
2693 }
2694 if (!defaultHandleToken(this,tok,m_children))
2695 {
2696 switch (tok)
2697 {
2698 case TK_COMMAND:
2699 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a \\image",
2700 qPrint(g_token->name));
2701 break;
2702 case TK_SYMBOL:
2703 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2704 qPrint(g_token->name));
2705 break;
2706 default:
2707 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2708 tokToString(tok));
2709 break;
2710 }
2711 }
2712 }
2713 // parse size attributes
2714 tok=doctokenizerYYlex();
2715 while (tok==TK_WORD) // there are values following the title
2716 {
2717 if (g_token->name=="width")
2718 {
2719 m_width=g_token->chars;
2720 }
2721 else if (g_token->name=="height")
2722 {
2723 m_height=g_token->chars;
2724 }
2725 else
2726 {
2727 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unknown option %s after image title",
2728 qPrint(g_token->name));
2729 }
2730 tok=doctokenizerYYlex();
2731 }
2732 doctokenizerYYsetStatePara();
2733
2734 handlePendingStyleCommands(this,m_children);
2735 DBG(("DocImage::parse() end\n"));
2736 DocNode *n=g_nodeStack.pop();
2737 ASSERT(n==this);
2738}
2739
2740
2741//---------------------------------------------------------------------------
2742
2743int DocHtmlHeader::parse()
2744{
2745 int retval=RetVal_OK;
2746 g_nodeStack.push(this);
2747 DBG(("DocHtmlHeader::parse() start\n"));
2748
2749 int tok;
2750 while ((tok=doctokenizerYYlex()))
2751 {
2752 if (!defaultHandleToken(this,tok,m_children))
2753 {
2754 switch (tok)
2755 {
2756 case TK_COMMAND:
2757 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <h%d> tag",
2758 qPrint(g_token->name),m_level);
2759 break;
2760 case TK_HTMLTAG:
2761 {
2762 int tagId=Mappers::htmlTagMapper->map(g_token->name);
2763 if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
2764 {
2765 if (m_level!=1)
2766 {
2767 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h1>",
2768 m_level);
2769 }
2770 goto endheader;
2771 }
2772 else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag
2773 {
2774 if (m_level!=2)
2775 {
2776 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h2>",
2777 m_level);
2778 }
2779 goto endheader;
2780 }
2781 else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag
2782 {
2783 if (m_level!=3)
2784 {
2785 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h3>",
2786 m_level);
2787 }
2788 goto endheader;
2789 }
2790 else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag
2791 {
2792 if (m_level!=4)
2793 {
2794 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h4>",
2795 m_level);
2796 }
2797 goto endheader;
2798 }
2799 else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag
2800 {
2801 if (m_level!=5)
2802 {
2803 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h5>",
2804 m_level);
2805 }
2806 goto endheader;
2807 }
2808 else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag
2809 {
2810 if (m_level!=6)
2811 {
2812 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: <h%d> ended with </h6>",
2813 m_level);
2814 }
2815 goto endheader;
2816 }
2817 else if (tagId==HTML_A)
2818 {
2819 if (!g_token->endTag)
2820 {
2821 handleAHref(this,m_children,g_token->attribs);
2822 }
2823 }
2824 else if (tagId==HTML_BR)
2825 {
2826 DocLineBreak *lb = new DocLineBreak(this);
2827 m_children.append(lb);
2828 }
2829 else
2830 {
2831 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <h%d> context",
2832 g_token->endTag?"/":"",qPrint(g_token->name),m_level);
2833 }
2834
2835 }
2836 break;
2837 case TK_SYMBOL:
2838 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2839 qPrint(g_token->name));
2840 break;
2841 default:
2842 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2843tokToString(tok));
2844 break;
2845 }
2846 }
2847 }
2848 if (tok==0)
2849 {
2850 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
2851 " <h%d> tag\n",m_level);
2852 }
2853endheader:
2854 handlePendingStyleCommands(this,m_children);
2855 DBG(("DocHtmlHeader::parse() end\n"));
2856 DocNode *n=g_nodeStack.pop();
2857 ASSERT(n==this);
2858 return retval;
2859}
2860
2861//---------------------------------------------------------------------------
2862
2863int DocHRef::parse()
2864{
2865 int retval=RetVal_OK;
2866 g_nodeStack.push(this);
2867 DBG(("DocHRef::parse() start\n"));
2868
2869 int tok;
2870 while ((tok=doctokenizerYYlex()))
2871 {
2872 if (!defaultHandleToken(this,tok,m_children))
2873 {
2874 switch (tok)
2875 {
2876 case TK_COMMAND:
2877 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <a>..</a> block",
2878 qPrint(g_token->name));
2879 break;
2880 case TK_SYMBOL:
2881 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
2882 qPrint(g_token->name));
2883 break;
2884 case TK_HTMLTAG:
2885 {
2886 int tagId=Mappers::htmlTagMapper->map(g_token->name);
2887 if (tagId==HTML_A && g_token->endTag) // found </a> tag
2888 {
2889 goto endhref;
2890 }
2891 else
2892 {
2893 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <a href=...> context",
2894 g_token->endTag?"/":"",qPrint(g_token->name),doctokenizerYYlineno);
2895 }
2896 }
2897 break;
2898 default:
2899 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
2900tokToString(tok),doctokenizerYYlineno);
2901 break;
2902 }
2903 }
2904 }
2905 if (tok==0)
2906 {
2907 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
2908 " <a href=...> tag",doctokenizerYYlineno);
2909 }
2910endhref:
2911 handlePendingStyleCommands(this,m_children);
2912 DBG(("DocHRef::parse() end\n"));
2913 DocNode *n=g_nodeStack.pop();
2914 ASSERT(n==this);
2915 return retval;
2916}
2917
2918//---------------------------------------------------------------------------
2919
2920int DocInternal::parse(int level)
2921{
2922 int retval=RetVal_OK;
2923 g_nodeStack.push(this);
2924 DBG(("DocInternal::parse() start\n"));
2925
2926 // first parse any number of paragraphs
2927 bool isFirst=TRUE;
2928 DocPara *lastPar=0;
2929 do
2930 {
2931 DocPara *par = new DocPara(this);
2932 if (isFirst) { par->markFirst(); isFirst=FALSE; }
2933 retval=par->parse();
2934 if (!par->isEmpty())
2935 {
2936 m_children.append(par);
2937 lastPar=par;
2938 }
2939 else
2940 {
2941 delete par;
2942 }
2943 if (retval==TK_LISTITEM)
2944 {
2945 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found",doctokenizerYYlineno);
2946 }
2947 } while (retval!=0 &&
2948 retval!=RetVal_Section &&
2949 retval!=RetVal_Subsection &&
2950 retval!=RetVal_Subsubsection &&
2951 retval!=RetVal_Paragraph
2952 );
2953 if (lastPar) lastPar->markLast();
2954
2955 // then parse any number of level-n sections
2956 while ((level==1 && retval==RetVal_Section) ||
2957 (level==2 && retval==RetVal_Subsection) ||
2958 (level==3 && retval==RetVal_Subsubsection) ||
2959 (level==4 && retval==RetVal_Paragraph)
2960 )
2961 {
2962 DocSection *s=new DocSection(this,
2963 QMIN(level+Doxygen::subpageNestingLevel,5),g_token->sectionId);
2964 m_children.append(s);
2965 retval = s->parse();
2966 }
2967
2968 if (retval==RetVal_Internal)
2969 {
2970 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: \\internal command found inside internal section");
2971 }
2972
2973 DBG(("DocInternal::parse() end\n"));
2974 DocNode *n=g_nodeStack.pop();
2975 ASSERT(n==this);
2976 return retval;
2977}
2978
2979//---------------------------------------------------------------------------
2980
2981int DocIndexEntry::parse()
2982{
2983 int retval=RetVal_OK;
2984 g_nodeStack.push(this);
2985 DBG(("DocIndexEntry::parse() start\n"));
2986 int tok=doctokenizerYYlex();
2987 if (tok!=TK_WHITESPACE)
2988 {
2989 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after \\addindex command");
2990 goto endindexentry;
2991 }
2992 doctokenizerYYsetStateTitle();
2993 m_entry="";
2994 while ((tok=doctokenizerYYlex()))
2995 {
2996 switch (tok)
2997 {
2998 case TK_WHITESPACE:
2999 m_entry+=" ";
3000 break;
3001 case TK_WORD:
3002 case TK_LNKWORD:
3003 m_entry+=g_token->name;
3004 break;
3005 case TK_SYMBOL:
3006 {
3007 char letter='\0';
3008 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
3009 switch (s)
3010 {
3011 case DocSymbol::BSlash: m_entry+='\\'; break;
3012 case DocSymbol::At: m_entry+='@'; break;
3013 case DocSymbol::Less: m_entry+='<'; break;
3014 case DocSymbol::Greater: m_entry+='>'; break;
3015 case DocSymbol::Amp: m_entry+='&'; break;
3016 case DocSymbol::Dollar: m_entry+='$'; break;
3017 case DocSymbol::Hash: m_entry+='#'; break;
3018 case DocSymbol::Percent: m_entry+='%'; break;
3019 case DocSymbol::Apos: m_entry+='\''; break;
3020 case DocSymbol::Quot: m_entry+='"'; break;
3021 case DocSymbol::Lsquo: m_entry+='`'; break;
3022 case DocSymbol::Rsquo: m_entry+='\''; break;
3023 case DocSymbol::Ldquo: m_entry+="``"; break;
3024 case DocSymbol::Rdquo: m_entry+="''"; break;
3025 case DocSymbol::Ndash: m_entry+="--"; break;
3026 case DocSymbol::Mdash: m_entry+="---"; break;
3027 default:
3028 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected symbol found as argument of \\addindex");
3029 break;
3030 }
3031 }
3032 break;
3033 case TK_COMMAND:
3034 switch (Mappers::cmdMapper->map(g_token->name))
3035 {
3036 case CMD_BSLASH: m_entry+='\\'; break;
3037 case CMD_AT: m_entry+='@'; break;
3038 case CMD_LESS: m_entry+='<'; break;
3039 case CMD_GREATER: m_entry+='>'; break;
3040 case CMD_AMP: m_entry+='&'; break;
3041 case CMD_DOLLAR: m_entry+='$'; break;
3042 case CMD_HASH: m_entry+='#'; break;
3043 case CMD_DCOLON: m_entry+="::"; break;
3044 case CMD_PERCENT: m_entry+='%'; break;
3045 case CMD_QUOTE: m_entry+='"'; break;
3046 default:
3047 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected command %s found as argument of \\addindex",
3048 qPrint(g_token->name));
3049 break;
3050 }
3051 break;
3052 default:
3053 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3054 tokToString(tok));
3055 break;
3056 }
3057 }
3058 if (tok!=0) retval=tok;
3059 doctokenizerYYsetStatePara();
3060 m_entry = m_entry.stripWhiteSpace();
3061endindexentry:
3062 DBG(("DocIndexEntry::parse() end retval=%x\n",retval));
3063 DocNode *n=g_nodeStack.pop();
3064 ASSERT(n==this);
3065 return retval;
3066}
3067
3068//---------------------------------------------------------------------------
3069
3070int DocHtmlCaption::parse()
3071{
3072 int retval=0;
3073 g_nodeStack.push(this);
3074 DBG(("DocHtmlCaption::parse() start\n"));
3075 int tok;
3076 while ((tok=doctokenizerYYlex()))
3077 {
3078 if (!defaultHandleToken(this,tok,m_children))
3079 {
3080 switch (tok)
3081 {
3082 case TK_COMMAND:
3083 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <caption> tag",
3084 qPrint(g_token->name));
3085 break;
3086 case TK_SYMBOL:
3087 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3088 qPrint(g_token->name));
3089 break;
3090 case TK_HTMLTAG:
3091 {
3092 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3093 if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
3094 {
3095 retval = RetVal_OK;
3096 goto endcaption;
3097 }
3098 else
3099 {
3100 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <caption> context",
3101 g_token->endTag?"/":"",qPrint(g_token->name));
3102 }
3103 }
3104 break;
3105 default:
3106 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3107 tokToString(tok));
3108 break;
3109 }
3110 }
3111 }
3112 if (tok==0)
3113 {
3114 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
3115 " <caption> tag",doctokenizerYYlineno);
3116 }
3117endcaption:
3118 handlePendingStyleCommands(this,m_children);
3119 DBG(("DocHtmlCaption::parse() end\n"));
3120 DocNode *n=g_nodeStack.pop();
3121 ASSERT(n==this);
3122 return retval;
3123}
3124
3125//---------------------------------------------------------------------------
3126
3127int DocHtmlCell::parse()
3128{
3129 int retval=RetVal_OK;
3130 g_nodeStack.push(this);
3131 DBG(("DocHtmlCell::parse() start\n"));
3132
3133 // parse one or more paragraphs
3134 bool isFirst=TRUE;
3135 DocPara *par=0;
3136 do
3137 {
3138 par = new DocPara(this);
3139 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3140 m_children.append(par);
3141 retval=par->parse();
3142 if (retval==TK_HTMLTAG)
3143 {
3144 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3145 if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
3146 {
3147 retval=TK_NEWPARA; // ignore the tag
3148 }
3149 else if (tagId==HTML_TH && g_token->endTag) // found </th> tag
3150 {
3151 retval=TK_NEWPARA; // ignore the tag
3152 }
3153 }
3154 }
3155 while (retval==TK_NEWPARA);
3156 if (par) par->markLast();
3157
3158 DBG(("DocHtmlCell::parse() end\n"));
3159 DocNode *n=g_nodeStack.pop();
3160 ASSERT(n==this);
3161 return retval;
3162}
3163
3164int DocHtmlCell::parseXml()
3165{
3166 int retval=RetVal_OK;
3167 g_nodeStack.push(this);
3168 DBG(("DocHtmlCell::parseXml() start\n"));
3169
3170 // parse one or more paragraphs
3171 bool isFirst=TRUE;
3172 DocPara *par=0;
3173 do
3174 {
3175 par = new DocPara(this);
3176 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3177 m_children.append(par);
3178 retval=par->parse();
3179 if (retval==TK_HTMLTAG)
3180 {
3181 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3182 if (tagId==XML_ITEM && g_token->endTag) // found </item> tag
3183 {
3184 retval=TK_NEWPARA; // ignore the tag
3185 }
3186 else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag
3187 {
3188 retval=TK_NEWPARA; // ignore the tag
3189 }
3190 }
3191 }
3192 while (retval==TK_NEWPARA);
3193 if (par) par->markLast();
3194
3195 DBG(("DocHtmlCell::parseXml() end\n"));
3196 DocNode *n=g_nodeStack.pop();
3197 ASSERT(n==this);
3198 return retval;
3199}
3200
3201//---------------------------------------------------------------------------
3202
3203int DocHtmlRow::parse()
3204{
3205 int retval=RetVal_OK;
3206 g_nodeStack.push(this);
3207 DBG(("DocHtmlRow::parse() start\n"));
3208
3209 bool isHeading=FALSE;
3210 bool isFirst=TRUE;
3211 DocHtmlCell *cell=0;
3212
3213 // get next token
3214 int tok=doctokenizerYYlex();
3215 // skip whitespace
3216 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3217 // should find a html tag now
3218 if (tok==TK_HTMLTAG)
3219 {
3220 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3221 if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
3222 {
3223 }
3224 else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag
3225 {
3226 isHeading=TRUE;
3227 }
3228 else // found some other tag
3229 {
3230 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but "
3231 "found <%s> instead!",qPrint(g_token->name));
3232 doctokenizerYYpushBackHtmlTag(g_token->name);
3233 goto endrow;
3234 }
3235 }
3236 else if (tok==0) // premature end of comment
3237 {
3238 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3239 " for a html description title");
3240 goto endrow;
3241 }
3242 else // token other than html token
3243 {
3244 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but found %s token instead!",
3245 tokToString(tok));
3246 goto endrow;
3247 }
3248
3249 // parse one or more cells
3250 do
3251 {
3252 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3253 cell->markFirst(isFirst);
3254 isFirst=FALSE;
3255 m_children.append(cell);
3256 retval=cell->parse();
3257 isHeading = retval==RetVal_TableHCell;
3258 }
3259 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3260 if (cell) cell->markLast(TRUE);
3261
3262endrow:
3263 DBG(("DocHtmlRow::parse() end\n"));
3264 DocNode *n=g_nodeStack.pop();
3265 ASSERT(n==this);
3266 return retval;
3267}
3268
3269int DocHtmlRow::parseXml(bool isHeading)
3270{
3271 int retval=RetVal_OK;
3272 g_nodeStack.push(this);
3273 DBG(("DocHtmlRow::parseXml() start\n"));
3274
3275 bool isFirst=TRUE;
3276 DocHtmlCell *cell=0;
3277
3278 // get next token
3279 int tok=doctokenizerYYlex();
3280 // skip whitespace
3281 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3282 // should find a html tag now
3283 if (tok==TK_HTMLTAG)
3284 {
3285 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3286 if (tagId==XML_TERM && !g_token->endTag) // found <term> tag
3287 {
3288 }
3289 else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag
3290 {
3291 }
3292 else // found some other tag
3293 {
3294 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <term> or <description> tag but "
3295 "found <%s> instead!",qPrint(g_token->name));
3296 doctokenizerYYpushBackHtmlTag(g_token->name);
3297 goto endrow;
3298 }
3299 }
3300 else if (tok==0) // premature end of comment
3301 {
3302 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3303 " for a html description title");
3304 goto endrow;
3305 }
3306 else // token other than html token
3307 {
3308 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <td> or <th> tag but found %s token instead!",
3309 tokToString(tok));
3310 goto endrow;
3311 }
3312
3313 do
3314 {
3315 cell=new DocHtmlCell(this,g_token->attribs,isHeading);
3316 cell->markFirst(isFirst);
3317 isFirst=FALSE;
3318 m_children.append(cell);
3319 retval=cell->parseXml();
3320 }
3321 while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
3322 if (cell) cell->markLast(TRUE);
3323
3324endrow:
3325 DBG(("DocHtmlRow::parseXml() end\n"));
3326 DocNode *n=g_nodeStack.pop();
3327 ASSERT(n==this);
3328 return retval;
3329}
3330
3331//---------------------------------------------------------------------------
3332
3333int DocHtmlTable::parse()
3334{
3335 int retval=RetVal_OK;
3336 g_nodeStack.push(this);
3337 DBG(("DocHtmlTable::parse() start\n"));
3338
3339getrow:
3340 // get next token
3341 int tok=doctokenizerYYlex();
3342 // skip whitespace
3343 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3344 // should find a html tag now
3345 if (tok==TK_HTMLTAG)
3346 {
3347 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3348 if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
3349 {
3350 // no caption, just rows
3351 retval=RetVal_TableRow;
3352 }
3353 else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag
3354 {
3355 if (m_caption)
3356 {
3357 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: table already has a caption, found another one");
3358 }
3359 else
3360 {
3361 m_caption = new DocHtmlCaption(this,g_token->attribs);
3362 retval=m_caption->parse();
3363
3364 if (retval==RetVal_OK) // caption was parsed ok
3365 {
3366 goto getrow;
3367 }
3368 }
3369 }
3370 else // found wrong token
3371 {
3372 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <tr> or <caption> tag but "
3373 "found <%s%s> instead!", g_token->endTag ? "/" : "", qPrint(g_token->name));
3374 }
3375 }
3376 else if (tok==0) // premature end of comment
3377 {
3378 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3379 " for a <tr> or <caption> tag");
3380 }
3381 else // token other than html token
3382 {
3383 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <tr> tag but found %s token instead!",
3384 tokToString(tok));
3385 }
3386
3387 // parse one or more rows
3388 while (retval==RetVal_TableRow)
3389 {
3390 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3391 m_children.append(tr);
3392 retval=tr->parse();
3393 }
3394
3395 DBG(("DocHtmlTable::parse() end\n"));
3396 DocNode *n=g_nodeStack.pop();
3397 ASSERT(n==this);
3398 return retval==RetVal_EndTable ? RetVal_OK : retval;
3399}
3400
3401int DocHtmlTable::parseXml()
3402{
3403 int retval=RetVal_OK;
3404 g_nodeStack.push(this);
3405 DBG(("DocHtmlTable::parseXml() start\n"));
3406
3407 // get next token
3408 int tok=doctokenizerYYlex();
3409 // skip whitespace
3410 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3411 // should find a html tag now
3412 int tagId=0;
3413 bool isHeader=FALSE;
3414 if (tok==TK_HTMLTAG)
3415 {
3416 tagId=Mappers::htmlTagMapper->map(g_token->name);
3417 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
3418 {
3419 retval=RetVal_TableRow;
3420 }
3421 if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag
3422 {
3423 retval=RetVal_TableRow;
3424 isHeader=TRUE;
3425 }
3426 }
3427
3428 // parse one or more rows
3429 while (retval==RetVal_TableRow)
3430 {
3431 DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
3432 m_children.append(tr);
3433 retval=tr->parseXml(isHeader);
3434 isHeader=FALSE;
3435 }
3436
3437 DBG(("DocHtmlTable::parseXml() end\n"));
3438 DocNode *n=g_nodeStack.pop();
3439 ASSERT(n==this);
3440 return retval==RetVal_EndTable ? RetVal_OK : retval;
3441}
3442
3443uint DocHtmlTable::numCols() const
3444{
3445 uint cols=0;
3446 QListIterator<DocNode> cli(m_children);
3447 DocNode *n;
3448 for (cli.toFirst();(n=cli.current());++cli)
3449 {
3450 ASSERT(n->kind()==DocNode::Kind_HtmlRow);
3451 cols=QMAX(cols,((DocHtmlRow *)n)->numCells());
3452 }
3453 return cols;
3454}
3455
3456void DocHtmlTable::accept(DocVisitor *v)
3457{
3458 v->visitPre(this);
3459 // for HTML output we put the caption first
3460 if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v);
3461 QListIterator<DocNode> cli(m_children);
3462 DocNode *n;
3463 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
3464 // for other output formats we put the caption last
3465 if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v);
3466 v->visitPost(this);
3467}
3468
3469//---------------------------------------------------------------------------
3470
3471int DocHtmlDescTitle::parse()
3472{
3473 int retval=0;
3474 g_nodeStack.push(this);
3475 DBG(("DocHtmlDescTitle::parse() start\n"));
3476
3477 int tok;
3478 while ((tok=doctokenizerYYlex()))
3479 {
3480 if (!defaultHandleToken(this,tok,m_children))
3481 {
3482 switch (tok)
3483 {
3484 case TK_COMMAND:
3485 {
3486 QCString cmdName=g_token->name;
3487 bool isJavaLink=FALSE;
3488 switch (Mappers::cmdMapper->map(cmdName))
3489 {
3490 case CMD_REF:
3491 {
3492 int tok=doctokenizerYYlex();
3493 if (tok!=TK_WHITESPACE)
3494 {
3495 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
3496 qPrint(g_token->name));
3497 }
3498 else
3499 {
3500 doctokenizerYYsetStateRef();
3501 tok=doctokenizerYYlex(); // get the reference id
3502 if (tok!=TK_WORD)
3503 {
3504 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
3505 tokToString(tok),qPrint(cmdName));
3506 }
3507 else
3508 {
3509 DocRef *ref = new DocRef(this,g_token->name,g_context);
3510 m_children.append(ref);
3511 ref->parse();
3512 }
3513 doctokenizerYYsetStatePara();
3514 }
3515 }
3516 break;
3517 case CMD_JAVALINK:
3518 isJavaLink=TRUE;
3519 // fall through
3520 case CMD_LINK:
3521 {
3522 int tok=doctokenizerYYlex();
3523 if (tok!=TK_WHITESPACE)
3524 {
3525 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
3526 qPrint(cmdName));
3527 }
3528 else
3529 {
3530 doctokenizerYYsetStateLink();
3531 tok=doctokenizerYYlex();
3532 if (tok!=TK_WORD)
3533 {
3534 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
3535 tokToString(tok),qPrint(cmdName));
3536 }
3537 else
3538 {
3539 doctokenizerYYsetStatePara();
3540 DocLink *lnk = new DocLink(this,g_token->name);
3541 m_children.append(lnk);
3542 QCString leftOver = lnk->parse(isJavaLink);
3543 if (!leftOver.isEmpty())
3544 {
3545 m_children.append(new DocWord(this,leftOver));
3546 }
3547 }
3548 }
3549 }
3550
3551 break;
3552 default:
3553 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a <dt> tag",
3554 qPrint(g_token->name));
3555 }
3556 }
3557 break;
3558 case TK_SYMBOL:
3559 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3560 qPrint(g_token->name));
3561 break;
3562 case TK_HTMLTAG:
3563 {
3564 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3565 if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
3566 {
3567 retval = RetVal_DescData;
3568 goto endtitle;
3569 }
3570 else if (tagId==HTML_DT && g_token->endTag)
3571 {
3572 // ignore </dt> tag.
3573 }
3574 else if (tagId==HTML_DT)
3575 {
3576 // missing <dt> tag.
3577 retval = RetVal_DescTitle;
3578 goto endtitle;
3579 }
3580 else if (tagId==HTML_DL && g_token->endTag)
3581 {
3582 retval=RetVal_EndDesc;
3583 goto endtitle;
3584 }
3585 else
3586 {
3587 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected html tag <%s%s> found within <dt> context",
3588 g_token->endTag?"/":"",qPrint(g_token->name));
3589 }
3590 }
3591 break;
3592 default:
3593 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3594 tokToString(tok));
3595 break;
3596 }
3597 }
3598 }
3599 if (tok==0)
3600 {
3601 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected end of comment while inside"
3602 " <dt> tag");
3603 }
3604endtitle:
3605 handlePendingStyleCommands(this,m_children);
3606 DBG(("DocHtmlDescTitle::parse() end\n"));
3607 DocNode *n=g_nodeStack.pop();
3608 ASSERT(n==this);
3609 return retval;
3610}
3611
3612//---------------------------------------------------------------------------
3613
3614int DocHtmlDescData::parse()
3615{
3616 m_attribs = g_token->attribs;
3617 int retval=0;
3618 g_nodeStack.push(this);
3619 DBG(("DocHtmlDescData::parse() start\n"));
3620
3621 bool isFirst=TRUE;
3622 DocPara *par=0;
3623 do
3624 {
3625 par = new DocPara(this);
3626 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3627 m_children.append(par);
3628 retval=par->parse();
3629 }
3630 while (retval==TK_NEWPARA);
3631 if (par) par->markLast();
3632
3633 DBG(("DocHtmlDescData::parse() end\n"));
3634 DocNode *n=g_nodeStack.pop();
3635 ASSERT(n==this);
3636 return retval;
3637}
3638
3639//---------------------------------------------------------------------------
3640
3641int DocHtmlDescList::parse()
3642{
3643 int retval=RetVal_OK;
3644 g_nodeStack.push(this);
3645 DBG(("DocHtmlDescList::parse() start\n"));
3646
3647 // get next token
3648 int tok=doctokenizerYYlex();
3649 // skip whitespace
3650 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3651 // should find a html tag now
3652 if (tok==TK_HTMLTAG)
3653 {
3654 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3655 if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
3656 {
3657 // continue
3658 }
3659 else // found some other tag
3660 {
3661 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <dt> tag but "
3662 "found <%s> instead!",qPrint(g_token->name));
3663 doctokenizerYYpushBackHtmlTag(g_token->name);
3664 goto enddesclist;
3665 }
3666 }
3667 else if (tok==0) // premature end of comment
3668 {
3669 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3670 " for a html description title");
3671 goto enddesclist;
3672 }
3673 else // token other than html token
3674 {
3675 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <dt> tag but found %s token instead!",
3676 tokToString(tok));
3677 goto enddesclist;
3678 }
3679
3680 do
3681 {
3682 DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs);
3683 m_children.append(dt);
3684 DocHtmlDescData *dd=new DocHtmlDescData(this);
3685 m_children.append(dd);
3686 retval=dt->parse();
3687 if (retval==RetVal_DescData)
3688 {
3689 retval=dd->parse();
3690 }
3691 else if (retval!=RetVal_DescTitle)
3692 {
3693 // error
3694 break;
3695 }
3696 } while (retval==RetVal_DescTitle);
3697
3698 if (retval==0)
3699 {
3700 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <dl> block");
3701 }
3702
3703enddesclist:
3704
3705 DocNode *n=g_nodeStack.pop();
3706 ASSERT(n==this);
3707 DBG(("DocHtmlDescList::parse() end\n"));
3708 return retval==RetVal_EndDesc ? RetVal_OK : retval;
3709}
3710
3711//---------------------------------------------------------------------------
3712
3713int DocHtmlListItem::parse()
3714{
3715 DBG(("DocHtmlListItem::parse() start\n"));
3716 int retval=0;
3717 g_nodeStack.push(this);
3718
3719 // parse one or more paragraphs
3720 bool isFirst=TRUE;
3721 DocPara *par=0;
3722 do
3723 {
3724 par = new DocPara(this);
3725 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3726 m_children.append(par);
3727 retval=par->parse();
3728 }
3729 while (retval==TK_NEWPARA);
3730 if (par) par->markLast();
3731
3732 DocNode *n=g_nodeStack.pop();
3733 ASSERT(n==this);
3734 DBG(("DocHtmlListItem::parse() end retval=%x\n",retval));
3735 return retval;
3736}
3737
3738int DocHtmlListItem::parseXml()
3739{
3740 DBG(("DocHtmlListItem::parseXml() start\n"));
3741 int retval=0;
3742 g_nodeStack.push(this);
3743
3744 // parse one or more paragraphs
3745 bool isFirst=TRUE;
3746 DocPara *par=0;
3747 do
3748 {
3749 par = new DocPara(this);
3750 if (isFirst) { par->markFirst(); isFirst=FALSE; }
3751 m_children.append(par);
3752 retval=par->parse();
3753 if (retval==0) break;
3754
3755 //printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
3756 // retval,qPrint(g_token->name),g_token->endTag);
3757 if (retval==RetVal_ListItem)
3758 {
3759 break;
3760 }
3761 }
3762 while (retval!=RetVal_CloseXml);
3763
3764 if (par) par->markLast();
3765
3766 DocNode *n=g_nodeStack.pop();
3767 ASSERT(n==this);
3768 DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
3769 return retval;
3770}
3771
3772//---------------------------------------------------------------------------
3773
3774int DocHtmlList::parse()
3775{
3776 DBG(("DocHtmlList::parse() start\n"));
3777 int retval=RetVal_OK;
3778 int num=1;
3779 g_nodeStack.push(this);
3780
3781 // get next token
3782 int tok=doctokenizerYYlex();
3783 // skip whitespace and paragraph breaks
3784 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3785 // should find a html tag now
3786 if (tok==TK_HTMLTAG)
3787 {
3788 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3789 if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
3790 {
3791 // ok, we can go on.
3792 }
3793 else // found some other tag
3794 {
3795 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <li> tag but "
3796 "found <%s> instead!",qPrint(g_token->name));
3797 doctokenizerYYpushBackHtmlTag(g_token->name);
3798 goto endlist;
3799 }
3800 }
3801 else if (tok==0) // premature end of comment
3802 {
3803 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3804 " for a html list item");
3805 goto endlist;
3806 }
3807 else // token other than html token
3808 {
3809 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <li> tag but found %s token instead!",
3810 tokToString(tok));
3811 goto endlist;
3812 }
3813
3814 do
3815 {
3816 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
3817 m_children.append(li);
3818 retval=li->parse();
3819 } while (retval==RetVal_ListItem);
3820
3821 if (retval==0)
3822 {
3823 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <%cl> block",
3824 m_type==Unordered ? 'u' : 'o');
3825 }
3826
3827endlist:
3828 DBG(("DocHtmlList::parse() end retval=%x\n",retval));
3829 DocNode *n=g_nodeStack.pop();
3830 ASSERT(n==this);
3831 return retval==RetVal_EndList ? RetVal_OK : retval;
3832}
3833
3834int DocHtmlList::parseXml()
3835{
3836 DBG(("DocHtmlList::parseXml() start\n"));
3837 int retval=RetVal_OK;
3838 int num=1;
3839 g_nodeStack.push(this);
3840
3841 // get next token
3842 int tok=doctokenizerYYlex();
3843 // skip whitespace and paragraph breaks
3844 while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
3845 // should find a html tag now
3846 if (tok==TK_HTMLTAG)
3847 {
3848 int tagId=Mappers::htmlTagMapper->map(g_token->name);
3849 //printf("g_token->name=%s g_token->endTag=%d\n",qPrint(g_token->name),g_token->endTag);
3850 if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
3851 {
3852 // ok, we can go on.
3853 }
3854 else // found some other tag
3855 {
3856 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <item> tag but "
3857 "found <%s> instead!",qPrint(g_token->name));
3858 doctokenizerYYpushBackHtmlTag(g_token->name);
3859 goto endlist;
3860 }
3861 }
3862 else if (tok==0) // premature end of comment
3863 {
3864 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while looking"
3865 " for a html list item");
3866 goto endlist;
3867 }
3868 else // token other than html token
3869 {
3870 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected <item> tag but found %s token instead!",
3871 tokToString(tok));
3872 goto endlist;
3873 }
3874
3875 do
3876 {
3877 DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
3878 m_children.append(li);
3879 retval=li->parseXml();
3880 if (retval==0) break;
3881 //printf("retval=%x g_token->name=%s\n",retval,qPrint(g_token->name));
3882 } while (retval==RetVal_ListItem);
3883
3884 if (retval==0)
3885 {
3886 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment while inside <list type=\"%s\"> block",
3887 m_type==Unordered ? "bullet" : "number");
3888 }
3889
3890endlist:
3891 DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
3892 DocNode *n=g_nodeStack.pop();
3893 ASSERT(n==this);
3894 return retval==RetVal_EndList ||
3895 (retval==RetVal_CloseXml || g_token->name=="list") ?
3896 RetVal_OK : retval;
3897}
3898
3899//---------------------------------------------------------------------------
3900
3901int DocSimpleListItem::parse()
3902{
3903 g_nodeStack.push(this);
3904 int rv=m_paragraph->parse();
3905 m_paragraph->markFirst();
3906 m_paragraph->markLast();
3907 DocNode *n=g_nodeStack.pop();
3908 ASSERT(n==this);
3909 return rv;
3910}
3911
3912//--------------------------------------------------------------------------
3913
3914int DocSimpleList::parse()
3915{
3916 g_nodeStack.push(this);
3917 int rv;
3918 do
3919 {
3920 DocSimpleListItem *li=new DocSimpleListItem(this);
3921 m_children.append(li);
3922 rv=li->parse();
3923 } while (rv==RetVal_ListItem);
3924 DocNode *n=g_nodeStack.pop();
3925 ASSERT(n==this);
3926 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
3927}
3928
3929//--------------------------------------------------------------------------
3930
3931int DocAutoListItem::parse()
3932{
3933 int retval = RetVal_OK;
3934 g_nodeStack.push(this);
3935 retval=m_paragraph->parse();
3936 m_paragraph->markFirst();
3937 m_paragraph->markLast();
3938 DocNode *n=g_nodeStack.pop();
3939 ASSERT(n==this);
3940 return retval;
3941}
3942
3943//--------------------------------------------------------------------------
3944
3945int DocAutoList::parse()
3946{
3947 int retval = RetVal_OK;
3948 int num=1;
3949 g_nodeStack.push(this);
3950 // first item or sub list => create new list
3951 do
3952 {
3953 DocAutoListItem *li = new DocAutoListItem(this,num++);
3954 m_children.append(li);
3955 retval=li->parse();
3956 }
3957 while (retval==TK_LISTITEM && // new list item
3958 m_indent==g_token->indent && // at same indent level
3959 m_isEnumList==g_token->isEnumList // of the same kind
3960 );
3961
3962 DocNode *n=g_nodeStack.pop();
3963 ASSERT(n==this);
3964 return retval;
3965}
3966
3967//--------------------------------------------------------------------------
3968
3969void DocTitle::parse()
3970{
3971 DBG(("DocTitle::parse() start\n"));
3972 g_nodeStack.push(this);
3973 doctokenizerYYsetStateTitle();
3974 int tok;
3975 while ((tok=doctokenizerYYlex()))
3976 {
3977 if (!defaultHandleToken(this,tok,m_children))
3978 {
3979 switch (tok)
3980 {
3981 case TK_COMMAND:
3982 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal command %s as part of a title section",
3983 qPrint(g_token->name));
3984 break;
3985 case TK_SYMBOL:
3986 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
3987 qPrint(g_token->name));
3988 break;
3989 default:
3990 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
3991tokToString(tok));
3992 break;
3993 }
3994 }
3995 }
3996 doctokenizerYYsetStatePara();
3997 handlePendingStyleCommands(this,m_children);
3998 DBG(("DocTitle::parse() end\n"));
3999 DocNode *n = g_nodeStack.pop();
4000 ASSERT(n==this);
4001}
4002
4003void DocTitle::parseFromString(const QCString &text)
4004{
4005 m_children.append(new DocWord(this,text));
4006}
4007
4008//--------------------------------------------------------------------------
4009
4010DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) :
4011 m_type(t)
4012{
4013 m_parent = parent;
4014 m_title=0;
4015}
4016
4017DocSimpleSect::~DocSimpleSect()
4018{
4019 delete m_title;
4020}
4021
4022void DocSimpleSect::accept(DocVisitor *v)
4023{
4024 v->visitPre(this);
4025 if (m_title) m_title->accept(v);
4026 QListIterator<DocNode> cli(m_children);
4027 DocNode *n;
4028 for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
4029 v->visitPost(this);
4030}
4031
4032int DocSimpleSect::parse(bool userTitle,bool needsSeparator)
4033{
4034 DBG(("DocSimpleSect::parse() start\n"));
4035 g_nodeStack.push(this);
4036
4037 // handle case for user defined title
4038 if (userTitle)
4039 {
4040 m_title = new DocTitle(this);
4041 m_title->parse();
4042 }
4043
4044 // add new paragraph as child
4045 DocPara *par = new DocPara(this);
4046 if (m_children.isEmpty())
4047 {
4048 par->markFirst();
4049 }
4050 else
4051 {
4052 ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
4053 ((DocPara *)m_children.last())->markLast(FALSE);
4054 }
4055 par->markLast();
4056 if (needsSeparator) m_children.append(new DocSimpleSectSep(this));
4057 m_children.append(par);
4058
4059 // parse the contents of the paragraph
4060 int retval = par->parse();
4061
4062 DBG(("DocSimpleSect::parse() end retval=%d\n",retval));
4063 DocNode *n=g_nodeStack.pop();
4064 ASSERT(n==this);
4065 return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec
4066}
4067
4068int DocSimpleSect::parseRcs()
4069{
4070 DBG(("DocSimpleSect::parseRcs() start\n"));
4071 g_nodeStack.push(this);
4072
4073 m_title = new DocTitle(this);
4074 m_title->parseFromString(g_token->name);
4075
4076 QCString text = g_token->text;
4077 docParserPushContext(); // this will create a new g_token
4078 internalValidatingParseDoc(this,m_children,text);
4079 docParserPopContext(); // this will restore the old g_token
4080
4081 DBG(("DocSimpleSect::parseRcs()\n"));
4082 DocNode *n=g_nodeStack.pop();
4083 ASSERT(n==this);
4084 return RetVal_OK;
4085}
4086
4087int DocSimpleSect::parseXml()
4088{
4089 DBG(("DocSimpleSect::parse() start\n"));
4090 g_nodeStack.push(this);
4091
4092 int retval = RetVal_OK;
4093 for (;;)
4094 {
4095 // add new paragraph as child
4096 DocPara *par = new DocPara(this);
4097 if (m_children.isEmpty())
4098 {
4099 par->markFirst();
4100 }
4101 else
4102 {
4103 ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
4104 ((DocPara *)m_children.last())->markLast(FALSE);
4105 }
4106 par->markLast();
4107 m_children.append(par);
4108
4109 // parse the contents of the paragraph
4110 retval = par->parse();
4111 if (retval == 0) break;
4112 if (retval == RetVal_CloseXml)
4113 {
4114 retval = RetVal_OK;
4115 break;
4116 }
4117 }
4118
4119 DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
4120 DocNode *n=g_nodeStack.pop();
4121 ASSERT(n==this);
4122 return retval;
4123}
4124
4125void DocSimpleSect::appendLinkWord(const QCString &word)
4126{
4127 DocPara *p;
4128 if (m_children.isEmpty() || m_children.last()->kind()!=DocNode::Kind_Para)
4129 {
4130 p = new DocPara(this);
4131 m_children.append(p);
4132 }
4133 else
4134 {
4135 p = (DocPara *)m_children.last();
4136
4137 // Comma-seperate <seealso> links.
4138 p->injectToken(TK_WORD,",");
4139 p->injectToken(TK_WHITESPACE," ");
4140 }
4141
4142 g_inSeeBlock=TRUE;
4143 p->injectToken(TK_LNKWORD,word);
4144 g_inSeeBlock=FALSE;
4145}
4146
4147QCString DocSimpleSect::typeString() const
4148{
4149 switch (m_type)
4150 {
4151 case Unknown: break;
4152 case See: return "see";
4153 case Return: return "return";
4154 case Author: // fall through
4155 case Authors: return "author";
4156 case Version: return "version";
4157 case Since: return "since";
4158 case Date: return "date";
4159 case Note: return "note";
4160 case Warning: return "warning";
4161 case Pre: return "pre";
4162 case Post: return "post";
4163 case Invar: return "invariant";
4164 case Remark: return "remark";
4165 case Attention: return "attention";
4166 case User: return "user";
4167 case Rcs: return "rcs";
4168 }
4169 return "unknown";
4170}
4171
4172//--------------------------------------------------------------------------
4173
4174int DocParamList::parse(const QCString &cmdName)
4175{
4176 int retval=RetVal_OK;
4177 DBG(("DocParamList::parse() start\n"));
4178 g_nodeStack.push(this);
4179 DocPara *par=0;
4180
4181 int tok=doctokenizerYYlex();
4182 if (tok!=TK_WHITESPACE)
4183 {
4184 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4185 qPrint(cmdName));
4186 }
4187 doctokenizerYYsetStateParam();
4188 tok=doctokenizerYYlex();
4189 while (tok==TK_WORD) /* there is a parameter name */
4190 {
4191 if (m_type==DocParamSect::Param)
4192 {
4193 int typeSeparator = g_token->name.find('#'); // explicit type position
4194 if (typeSeparator!=-1)
4195 {
4196 handleParameterType(this,m_paramTypes,g_token->name.left(typeSeparator));
4197 g_token->name = g_token->name.mid(typeSeparator+1);
4198 g_hasParamCommand=TRUE;
4199 checkArgumentName(g_token->name,TRUE);
4200 ((DocParamSect*)parent())->m_hasTypeSpecifier=TRUE;
4201 }
4202 else
4203 {
4204 g_hasParamCommand=TRUE;
4205 checkArgumentName(g_token->name,TRUE);
4206 }
4207 }
4208 else if (m_type==DocParamSect::RetVal)
4209 {
4210 g_hasReturnCommand=TRUE;
4211 checkArgumentName(g_token->name,FALSE);
4212 }
4213 //m_params.append(g_token->name);
4214 handleLinkedWord(this,m_params);
4215 tok=doctokenizerYYlex();
4216 }
4217 doctokenizerYYsetStatePara();
4218 if (tok==0) /* premature end of comment block */
4219 {
4220 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4221 "argument of command %s",qPrint(cmdName));
4222 retval=0;
4223 goto endparamlist;
4224 }
4225 ASSERT(tok==TK_WHITESPACE);
4226
4227 par = new DocPara(this);
4228 m_paragraphs.append(par);
4229 retval = par->parse();
4230 par->markFirst();
4231 par->markLast();
4232
4233endparamlist:
4234 DBG(("DocParamList::parse() end retval=%d\n",retval));
4235 DocNode *n=g_nodeStack.pop();
4236 ASSERT(n==this);
4237 return retval;
4238}
4239
4240int DocParamList::parseXml(const QCString &paramName)
4241{
4242 int retval=RetVal_OK;
4243 DBG(("DocParamList::parseXml() start\n"));
4244 g_nodeStack.push(this);
4245
4246 g_token->name = paramName;
4247 if (m_type==DocParamSect::Param)
4248 {
4249 g_hasParamCommand=TRUE;
4250 checkArgumentName(g_token->name,TRUE);
4251 }
4252 else if (m_type==DocParamSect::RetVal)
4253 {
4254 g_hasReturnCommand=TRUE;
4255 checkArgumentName(g_token->name,FALSE);
4256 }
4257
4258 handleLinkedWord(this,m_params);
4259
4260 do
4261 {
4262 DocPara *par = new DocPara(this);
4263 retval = par->parse();
4264 if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
4265 // after </para> and before </param>
4266 {
4267 delete par;
4268 break;
4269 }
4270 else // append the paragraph to the list
4271 {
4272 if (m_paragraphs.isEmpty())
4273 {
4274 par->markFirst();
4275 }
4276 else
4277 {
4278 m_paragraphs.last()->markLast(FALSE);
4279 }
4280 par->markLast();
4281 m_paragraphs.append(par);
4282 }
4283
4284 if (retval == 0) break;
4285
4286 } while (retval==RetVal_CloseXml &&
4287 Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
4288 Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM &&
4289 Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
4290
4291
4292 if (retval==0) /* premature end of comment block */
4293 {
4294 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unterminated param or exception tag");
4295 }
4296 else
4297 {
4298 retval=RetVal_OK;
4299 }
4300
4301
4302 DBG(("DocParamList::parse() end retval=%d\n",retval));
4303 DocNode *n=g_nodeStack.pop();
4304 ASSERT(n==this);
4305 return retval;
4306}
4307
4308//--------------------------------------------------------------------------
4309
4310int DocParamSect::parse(const QCString &cmdName,bool xmlContext, Direction d)
4311{
4312 int retval=RetVal_OK;
4313 DBG(("DocParamSect::parse() start\n"));
4314 g_nodeStack.push(this);
4315
4316 if (d!=Unspecified)
4317 {
4318 m_hasInOutSpecifier=TRUE;
4319 }
4320
4321 DocParamList *pl = new DocParamList(this,m_type,d);
4322 if (m_children.isEmpty())
4323 {
4324 pl->markFirst();
4325 pl->markLast();
4326 }
4327 else
4328 {
4329 ASSERT(m_children.last()->kind()==DocNode::Kind_ParamList);
4330 ((DocParamList *)m_children.last())->markLast(FALSE);
4331 pl->markLast();
4332 }
4333 m_children.append(pl);
4334 if (xmlContext)
4335 {
4336 retval = pl->parseXml(cmdName);
4337 }
4338 else
4339 {
4340 retval = pl->parse(cmdName);
4341 }
4342
4343 DBG(("DocParamSect::parse() end retval=%d\n",retval));
4344 DocNode *n=g_nodeStack.pop();
4345 ASSERT(n==this);
4346 return retval;
4347}
4348
4349//--------------------------------------------------------------------------
4350
4351int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
4352{
4353 DocSimpleSect *ss=0;
4354 bool needsSeparator = FALSE;
4355 if (!m_children.isEmpty() && // previous element
4356 m_children.last()->kind()==Kind_SimpleSect && // was a simple sect
4357 ((DocSimpleSect *)m_children.last())->type()==t && // of same type
4358 t!=DocSimpleSect::User) // but not user defined
4359 {
4360 // append to previous section
4361 ss=(DocSimpleSect *)m_children.last();
4362 needsSeparator = TRUE;
4363 }
4364 else // start new section
4365 {
4366 ss=new DocSimpleSect(this,t);
4367 m_children.append(ss);
4368 }
4369 int rv = RetVal_OK;
4370 if (xmlContext)
4371 {
4372 return ss->parseXml();
4373 }
4374 else
4375 {
4376 rv = ss->parse(t==DocSimpleSect::User,needsSeparator);
4377 }
4378 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4379}
4380
4381int DocPara::handleParamSection(const QCString &cmdName,
4382 DocParamSect::Type t,
4383 bool xmlContext=FALSE,
4384 int direction=DocParamSect::Unspecified)
4385{
4386 DocParamSect *ps=0;
4387 if (!m_children.isEmpty() && // previous element
4388 m_children.last()->kind()==Kind_ParamSect && // was a param sect
4389 ((DocParamSect *)m_children.last())->type()==t) // of same type
4390 {
4391 // append to previous section
4392 ps=(DocParamSect *)m_children.last();
4393 }
4394 else // start new section
4395 {
4396 ps=new DocParamSect(this,t);
4397 m_children.append(ps);
4398 }
4399 int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
4400 return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
4401}
4402
4403int DocPara::handleXRefItem()
4404{
4405 int retval=doctokenizerYYlex();
4406 ASSERT(retval==TK_WHITESPACE);
4407 doctokenizerYYsetStateXRefItem();
4408 retval=doctokenizerYYlex();
4409 if (retval==RetVal_OK)
4410 {
4411 DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name);
4412 if (ref->parse())
4413 {
4414 m_children.append(ref);
4415 }
4416 else
4417 {
4418 delete ref;
4419 }
4420 }
4421 doctokenizerYYsetStatePara();
4422 return retval;
4423}
4424
4425void DocPara::handleIncludeOperator(const QCString &cmdName,DocIncOperator::Type t)
4426{
4427 DBG(("handleIncludeOperator(%s)\n",qPrint(cmdName)));
4428 int tok=doctokenizerYYlex();
4429 if (tok!=TK_WHITESPACE)
4430 {
4431 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4432 qPrint(cmdName));
4433 return;
4434 }
4435 doctokenizerYYsetStatePattern();
4436 tok=doctokenizerYYlex();
4437 doctokenizerYYsetStatePara();
4438 if (tok==0)
4439 {
4440 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4441 "argument of command %s", qPrint(cmdName));
4442 return;
4443 }
4444 else if (tok!=TK_WORD)
4445 {
4446 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4447 tokToString(tok),qPrint(cmdName));
4448 return;
4449 }
4450 DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
4451 DocNode *n1 = m_children.last();
4452 DocNode *n2 = n1!=0 ? m_children.prev() : 0;
4453 bool isFirst = n1==0 || // no last node
4454 (n1->kind()!=DocNode::Kind_IncOperator &&
4455 n1->kind()!=DocNode::Kind_WhiteSpace
4456 ) || // last node is not operator or whitespace
4457 (n1->kind()==DocNode::Kind_WhiteSpace &&
4458 n2!=0 && n2->kind()!=DocNode::Kind_IncOperator
4459 ); // previous not is not operator
4460 op->markFirst(isFirst);
4461 op->markLast(TRUE);
4462 if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator)
4463 {
4464 ((DocIncOperator *)n1)->markLast(FALSE);
4465 }
4466 else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace &&
4467 n2!=0 && n2->kind()==DocNode::Kind_IncOperator
4468 )
4469 {
4470 ((DocIncOperator *)n2)->markLast(FALSE);
4471 }
4472 m_children.append(op);
4473 op->parse();
4474}
4475
4476void DocPara::handleImage(const QCString &cmdName)
4477{
4478 int tok=doctokenizerYYlex();
4479 if (tok!=TK_WHITESPACE)
4480 {
4481 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4482 qPrint(cmdName));
4483 return;
4484 }
4485 tok=doctokenizerYYlex();
4486 if (tok!=TK_WORD && tok!=TK_LNKWORD)
4487 {
4488 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4489 tokToString(tok),qPrint(cmdName));
4490 return;
4491 }
4492 tok=doctokenizerYYlex();
4493 if (tok!=TK_WHITESPACE)
4494 {
4495 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4496 qPrint(cmdName));
4497 return;
4498 }
4499 DocImage::Type t;
4500 QCString imgType = g_token->name.lower();
4501 if (imgType=="html") t=DocImage::Html;
4502 else if (imgType=="latex") t=DocImage::Latex;
4503 else if (imgType=="rtf") t=DocImage::Rtf;
4504 else
4505 {
4506 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: image type %s specified as the first argument of "
4507 "%s is not valid",
4508 qPrint(imgType),qPrint(cmdName));
4509 return;
4510 }
4511 doctokenizerYYsetStateFile();
4512 tok=doctokenizerYYlex();
4513 doctokenizerYYsetStatePara();
4514 if (tok!=TK_WORD)
4515 {
4516 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4517 tokToString(tok),qPrint(cmdName));
4518 return;
4519 }
4520 HtmlAttribList attrList;
4521 DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t);
4522 m_children.append(img);
4523 img->parse();
4524}
4525
4526void DocPara::handleDotFile(const QCString &cmdName)
4527{
4528 int tok=doctokenizerYYlex();
4529 if (tok!=TK_WHITESPACE)
4530 {
4531 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4532 qPrint(cmdName));
4533 return;
4534 }
4535 doctokenizerYYsetStateFile();
4536 tok=doctokenizerYYlex();
4537 doctokenizerYYsetStatePara();
4538 if (tok!=TK_WORD)
4539 {
4540 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4541 tokToString(tok),qPrint(cmdName));
4542 return;
4543 }
4544 QCString name = g_token->name;
4545 DocDotFile *df = new DocDotFile(this,name,g_context);
4546 m_children.append(df);
4547 df->parse();
4548}
4549
4550void DocPara::handleMscFile(const QCString &cmdName)
4551{
4552 int tok=doctokenizerYYlex();
4553 if (tok!=TK_WHITESPACE)
4554 {
4555 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4556 qPrint(cmdName));
4557 return;
4558 }
4559 doctokenizerYYsetStateFile();
4560 tok=doctokenizerYYlex();
4561 doctokenizerYYsetStatePara();
4562 if (tok!=TK_WORD)
4563 {
4564 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4565 tokToString(tok),qPrint(cmdName));
4566 return;
4567 }
4568 QCString name = g_token->name;
4569 DocMscFile *df = new DocMscFile(this,name,g_context);
4570 m_children.append(df);
4571 df->parse();
4572}
4573
4574void DocPara::handleLink(const QCString &cmdName,bool isJavaLink)
4575{
4576 int tok=doctokenizerYYlex();
4577 if (tok!=TK_WHITESPACE)
4578 {
4579 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4580 qPrint(cmdName));
4581 return;
4582 }
4583 doctokenizerYYsetStateLink();
4584 tok=doctokenizerYYlex();
4585 if (tok!=TK_WORD)
4586 {
4587 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4588 tokToString(tok),qPrint(cmdName));
4589 return;
4590 }
4591 doctokenizerYYsetStatePara();
4592 DocLink *lnk = new DocLink(this,g_token->name);
4593 m_children.append(lnk);
4594 QCString leftOver = lnk->parse(isJavaLink);
4595 if (!leftOver.isEmpty())
4596 {
4597 m_children.append(new DocWord(this,leftOver));
4598 }
4599}
4600
4601void DocPara::handleRef(const QCString &cmdName)
4602{
4603 DBG(("handleRef(%s)\n",qPrint(cmdName)));
4604 int tok=doctokenizerYYlex();
4605 if (tok!=TK_WHITESPACE)
4606 {
4607 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4608 qPrint(cmdName));
4609 return;
4610 }
4611 doctokenizerYYsetStateRef();
4612 tok=doctokenizerYYlex(); // get the reference id
4613 DocRef *ref=0;
4614 if (tok!=TK_WORD)
4615 {
4616 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4617 tokToString(tok),qPrint(cmdName));
4618 goto endref;
4619 }
4620 ref = new DocRef(this,g_token->name,g_context);
4621 m_children.append(ref);
4622 ref->parse();
4623endref:
4624 doctokenizerYYsetStatePara();
4625}
4626
4627
4628void DocPara::handleInclude(const QCString &cmdName,DocInclude::Type t)
4629{
4630 DBG(("handleInclude(%s)\n",qPrint(cmdName)));
4631 int tok=doctokenizerYYlex();
4632 if (tok!=TK_WHITESPACE)
4633 {
4634 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4635 qPrint(cmdName));
4636 return;
4637 }
4638 doctokenizerYYsetStateFile();
4639 tok=doctokenizerYYlex();
4640 doctokenizerYYsetStatePara();
4641 if (tok==0)
4642 {
4643 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4644 "argument of command %s",qPrint(cmdName));
4645 return;
4646 }
4647 else if (tok!=TK_WORD)
4648 {
4649 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4650 tokToString(tok),qPrint(cmdName));
4651 return;
4652 }
4653 DocInclude *inc = new DocInclude(this,g_token->name,g_context,t,g_isExample,g_exampleName);
4654 m_children.append(inc);
4655 inc->parse();
4656}
4657
4658void DocPara::handleSection(const QCString &cmdName)
4659{
4660 // get the argument of the section command.
4661 int tok=doctokenizerYYlex();
4662 if (tok!=TK_WHITESPACE)
4663 {
4664 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4665 qPrint(cmdName));
4666 return;
4667 }
4668 tok=doctokenizerYYlex();
4669 if (tok==0)
4670 {
4671 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
4672 "argument of command %s\n", qPrint(cmdName));
4673 return;
4674 }
4675 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
4676 {
4677 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
4678 tokToString(tok),qPrint(cmdName));
4679 return;
4680 }
4681 g_token->sectionId = g_token->name;
4682 doctokenizerYYsetStateSkipTitle();
4683 doctokenizerYYlex();
4684 doctokenizerYYsetStatePara();
4685}
4686
4687int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
4688{
4689 DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level);
4690 m_children.append(header);
4691 int retval = header->parse();
4692 return (retval==RetVal_OK) ? TK_NEWPARA : retval;
4693}
4694
4695// For XML tags whose content is stored in attributes rather than
4696// contained within the element, we need a way to inject the attribute
4697// text into the current paragraph.
4698bool DocPara::injectToken(int tok,const QCString &tokText)
4699{
4700 g_token->name = tokText;
4701 return defaultHandleToken(this,tok,m_children);
4702}
4703
4704int DocPara::handleStartCode()
4705{
4706 int retval = doctokenizerYYlex();
4707 // search for the first non-whitespace line, index is stored in li
4708 int i=0,li=0,l=g_token->verb.length();
4709 while (i<l && (g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n'))
4710 {
4711 if (g_token->verb.at(i)=='\n') li=i+1;
4712 i++;
4713 }
4714 m_children.append(new DocVerbatim(this,g_context,g_token->verb.mid(li),DocVerbatim::Code,g_isExample,g_exampleName));
4715 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: code section ended without end marker");
4716 doctokenizerYYsetStatePara();
4717 return retval;
4718}
4719
4720void DocPara::handleInheritDoc()
4721{
4722 if (g_memberDef) // inheriting docs from a member
4723 {
4724 MemberDef *reMd = g_memberDef->reimplements();
4725 if (reMd) // member from which was inherited.
4726 {
4727 MemberDef *thisMd = g_memberDef;
4728 //printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data());
4729 docParserPushContext();
4730 g_scope=reMd->getOuterScope();
4731 if (g_scope!=Doxygen::globalScope)
4732 {
4733 g_context=g_scope->name();
4734 }
4735 g_memberDef=reMd;
4736 g_styleStack.clear();
4737 g_nodeStack.clear();
4738 g_copyStack.append(reMd);
4739 internalValidatingParseDoc(this,m_children,reMd->briefDescription());
4740 internalValidatingParseDoc(this,m_children,reMd->documentation());
4741 g_copyStack.remove(reMd);
4742 docParserPopContext(TRUE);
4743 g_memberDef = thisMd;
4744 }
4745 }
4746}
4747
4748
4749int DocPara::handleCommand(const QCString &cmdName)
4750{
4751 DBG(("handleCommand(%s)\n",qPrint(cmdName)));
4752 int retval = RetVal_OK;
4753 int cmdId = Mappers::cmdMapper->map(cmdName);
4754 switch (cmdId)
4755 {
4756 case CMD_UNKNOWN:
4757 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Found unknown command `\\%s'",qPrint(cmdName));
4758 break;
4759 case CMD_EMPHASIS:
4760 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
4761 retval=handleStyleArgument(this,m_children,cmdName);
4762 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
4763 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
4764 break;
4765 case CMD_BOLD:
4766 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
4767 retval=handleStyleArgument(this,m_children,cmdName);
4768 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
4769 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
4770 break;
4771 case CMD_CODE:
4772 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
4773 retval=handleStyleArgument(this,m_children,cmdName);
4774 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
4775 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
4776 break;
4777 case CMD_BSLASH:
4778 m_children.append(new DocSymbol(this,DocSymbol::BSlash));
4779 break;
4780 case CMD_AT:
4781 m_children.append(new DocSymbol(this,DocSymbol::At));
4782 break;
4783 case CMD_LESS:
4784 m_children.append(new DocSymbol(this,DocSymbol::Less));
4785 break;
4786 case CMD_GREATER:
4787 m_children.append(new DocSymbol(this,DocSymbol::Greater));
4788 break;
4789 case CMD_AMP:
4790 m_children.append(new DocSymbol(this,DocSymbol::Amp));
4791 break;
4792 case CMD_DOLLAR:
4793 m_children.append(new DocSymbol(this,DocSymbol::Dollar));
4794 break;
4795 case CMD_HASH:
4796 m_children.append(new DocSymbol(this,DocSymbol::Hash));
4797 break;
4798 case CMD_DCOLON:
4799 m_children.append(new DocSymbol(this,DocSymbol::DoubleColon));
4800 break;
4801 case CMD_PERCENT:
4802 m_children.append(new DocSymbol(this,DocSymbol::Percent));
4803 break;
4804 case CMD_QUOTE:
4805 m_children.append(new DocSymbol(this,DocSymbol::Quot));
4806 break;
4807 case CMD_SA:
4808 g_inSeeBlock=TRUE;
4809 retval = handleSimpleSection(DocSimpleSect::See);
4810 g_inSeeBlock=FALSE;
4811 break;
4812 case CMD_RETURN:
4813 retval = handleSimpleSection(DocSimpleSect::Return);
4814 g_hasReturnCommand=TRUE;
4815 break;
4816 case CMD_AUTHOR:
4817 retval = handleSimpleSection(DocSimpleSect::Author);
4818 break;
4819 case CMD_AUTHORS:
4820 retval = handleSimpleSection(DocSimpleSect::Authors);
4821 break;
4822 case CMD_VERSION:
4823 retval = handleSimpleSection(DocSimpleSect::Version);
4824 break;
4825 case CMD_SINCE:
4826 retval = handleSimpleSection(DocSimpleSect::Since);
4827 break;
4828 case CMD_DATE:
4829 retval = handleSimpleSection(DocSimpleSect::Date);
4830 break;
4831 case CMD_NOTE:
4832 retval = handleSimpleSection(DocSimpleSect::Note);
4833 break;
4834 case CMD_WARNING:
4835 retval = handleSimpleSection(DocSimpleSect::Warning);
4836 break;
4837 case CMD_PRE:
4838 retval = handleSimpleSection(DocSimpleSect::Pre);
4839 break;
4840 case CMD_POST:
4841 retval = handleSimpleSection(DocSimpleSect::Post);
4842 break;
4843 case CMD_INVARIANT:
4844 retval = handleSimpleSection(DocSimpleSect::Invar);
4845 break;
4846 case CMD_REMARK:
4847 retval = handleSimpleSection(DocSimpleSect::Remark);
4848 break;
4849 case CMD_ATTENTION:
4850 retval = handleSimpleSection(DocSimpleSect::Attention);
4851 break;
4852 case CMD_PAR:
4853 retval = handleSimpleSection(DocSimpleSect::User);
4854 break;
4855 case CMD_LI:
4856 {
4857DocSimpleList *sl=new DocSimpleList(this);
4858m_children.append(sl);
4859 retval = sl->parse();
4860 }
4861 break;
4862 case CMD_SECTION:
4863 {
4864 handleSection(cmdName);
4865retval = RetVal_Section;
4866 }
4867 break;
4868 case CMD_SUBSECTION:
4869 {
4870 handleSection(cmdName);
4871 retval = RetVal_Subsection;
4872 }
4873 break;
4874 case CMD_SUBSUBSECTION:
4875 {
4876 handleSection(cmdName);
4877 retval = RetVal_Subsubsection;
4878 }
4879 break;
4880 case CMD_PARAGRAPH:
4881 {
4882 handleSection(cmdName);
4883 retval = RetVal_Paragraph;
4884 }
4885 break;
4886 case CMD_STARTCODE:
4887 {
4888 doctokenizerYYsetStateCode();
4889 retval = handleStartCode();
4890 }
4891 break;
4892 case CMD_HTMLONLY:
4893 {
4894 doctokenizerYYsetStateHtmlOnly();
4895 retval = doctokenizerYYlex();
4896 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
4897 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: htmlonly section ended without end marker");
4898 doctokenizerYYsetStatePara();
4899 }
4900 break;
4901 case CMD_MANONLY:
4902 {
4903 doctokenizerYYsetStateManOnly();
4904 retval = doctokenizerYYlex();
4905 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
4906 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: manonly section ended without end marker");
4907 doctokenizerYYsetStatePara();
4908 }
4909 break;
4910 case CMD_LATEXONLY:
4911 {
4912 doctokenizerYYsetStateLatexOnly();
4913 retval = doctokenizerYYlex();
4914 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
4915 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: latexonly section ended without end marker");
4916 doctokenizerYYsetStatePara();
4917 }
4918 break;
4919 case CMD_XMLONLY:
4920 {
4921 doctokenizerYYsetStateXmlOnly();
4922 retval = doctokenizerYYlex();
4923 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
4924 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: xmlonly section ended without end marker");
4925 doctokenizerYYsetStatePara();
4926 }
4927 break;
4928 case CMD_VERBATIM:
4929 {
4930 doctokenizerYYsetStateVerbatim();
4931 retval = doctokenizerYYlex();
4932 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName));
4933 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: verbatim section ended without end marker");
4934 doctokenizerYYsetStatePara();
4935 }
4936 break;
4937 case CMD_DOT:
4938 {
4939 doctokenizerYYsetStateDot();
4940 retval = doctokenizerYYlex();
4941 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName));
4942 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: dot section ended without end marker");
4943 doctokenizerYYsetStatePara();
4944 }
4945 break;
4946 case CMD_MSC:
4947 {
4948 doctokenizerYYsetStateMsc();
4949 retval = doctokenizerYYlex();
4950 m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName));
4951 if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: msc section ended without end marker");
4952 doctokenizerYYsetStatePara();
4953 }
4954 break;
4955 case CMD_ENDCODE:
4956 case CMD_ENDHTMLONLY:
4957 case CMD_ENDMANONLY:
4958 case CMD_ENDLATEXONLY:
4959 case CMD_ENDXMLONLY:
4960 case CMD_ENDLINK:
4961 case CMD_ENDVERBATIM:
4962 case CMD_ENDDOT:
4963 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
4964 break;
4965 case CMD_ENDMSC:
4966 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
4967 break;
4968 case CMD_PARAM:
4969 retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
4970 break;
4971 case CMD_TPARAM:
4972 retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir);
4973 break;
4974 case CMD_RETVAL:
4975 retval = handleParamSection(cmdName,DocParamSect::RetVal);
4976 break;
4977 case CMD_EXCEPTION:
4978 retval = handleParamSection(cmdName,DocParamSect::Exception);
4979 break;
4980 case CMD_XREFITEM:
4981 retval = handleXRefItem();
4982 break;
4983 case CMD_LINEBREAK:
4984 {
4985 DocLineBreak *lb = new DocLineBreak(this);
4986 m_children.append(lb);
4987 }
4988 break;
4989 case CMD_ANCHOR:
4990 {
4991 int tok=doctokenizerYYlex();
4992 if (tok!=TK_WHITESPACE)
4993 {
4994 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
4995 qPrint(cmdName));
4996 break;
4997 }
4998 tok=doctokenizerYYlex();
4999 if (tok==0)
5000 {
5001 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
5002 "argument of command %s",qPrint(cmdName));
5003 break;
5004 }
5005 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
5006 {
5007 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5008 tokToString(tok),qPrint(cmdName));
5009 break;
5010 }
5011 DocAnchor *anchor = new DocAnchor(this,g_token->name,FALSE);
5012 m_children.append(anchor);
5013 }
5014 break;
5015 case CMD_ADDINDEX:
5016 {
5017 DocIndexEntry *ie = new DocIndexEntry(this,
5018 g_scope!=Doxygen::globalScope?g_scope:0,
5019 g_memberDef);
5020 m_children.append(ie);
5021 retval = ie->parse();
5022 }
5023 break;
5024 case CMD_INTERNAL:
5025 retval = RetVal_Internal;
5026 break;
5027 case CMD_COPYDOC: // fall through
5028 case CMD_COPYBRIEF: // fall through
5029 case CMD_COPYDETAILS:
5030 {
5031 int tok=doctokenizerYYlex();
5032 if (tok!=TK_WHITESPACE)
5033 {
5034 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: expected whitespace after %s command",
5035 qPrint(cmdName));
5036 break;
5037 }
5038 tok=doctokenizerYYlex();
5039 if (tok==0)
5040 {
5041 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected end of comment block while parsing the "
5042 "argument of command %s\n", qPrint(cmdName));
5043 break;
5044 }
5045 else if (tok!=TK_WORD && tok!=TK_LNKWORD)
5046 {
5047 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected token %s as the argument of %s",
5048 tokToString(tok),qPrint(cmdName));
5049 break;
5050 }
5051 DocCopy *cpy = new DocCopy(this,g_token->name,
5052 cmdId==CMD_COPYDOC || cmdId==CMD_COPYBRIEF,
5053 cmdId==CMD_COPYDOC || cmdId==CMD_COPYDETAILS);
5054 m_children.append(cpy);
5055 cpy->parse();
5056 }
5057 break;
5058 case CMD_INCLUDE:
5059 handleInclude(cmdName,DocInclude::Include);
5060 break;
5061 case CMD_INCWITHLINES:
5062 handleInclude(cmdName,DocInclude::IncWithLines);
5063 break;
5064 case CMD_DONTINCLUDE:
5065 handleInclude(cmdName,DocInclude::DontInclude);
5066 break;
5067 case CMD_HTMLINCLUDE:
5068 handleInclude(cmdName,DocInclude::HtmlInclude);
5069 break;
5070 case CMD_VERBINCLUDE:
5071 handleInclude(cmdName,DocInclude::VerbInclude);
5072 break;
5073 case CMD_SKIP:
5074 handleIncludeOperator(cmdName,DocIncOperator::Skip);
5075 break;
5076 case CMD_UNTIL:
5077 handleIncludeOperator(cmdName,DocIncOperator::Until);
5078 break;
5079 case CMD_SKIPLINE:
5080 handleIncludeOperator(cmdName,DocIncOperator::SkipLine);
5081 break;
5082 case CMD_LINE:
5083 handleIncludeOperator(cmdName,DocIncOperator::Line);
5084 break;
5085 case CMD_IMAGE:
5086 handleImage(cmdName);
5087 break;
5088 case CMD_DOTFILE:
5089 handleDotFile(cmdName);
5090 break;
5091 case CMD_MSCFILE:
5092 handleMscFile(cmdName);
5093 break;
5094 case CMD_LINK:
5095 handleLink(cmdName,FALSE);
5096 break;
5097 case CMD_JAVALINK:
5098 handleLink(cmdName,TRUE);
5099 break;
5100 case CMD_REF: // fall through
5101 case CMD_SUBPAGE:
5102 handleRef(cmdName);
5103 break;
5104 case CMD_SECREFLIST:
5105 {
5106 DocSecRefList *list = new DocSecRefList(this);
5107 m_children.append(list);
5108 list->parse();
5109 }
5110 break;
5111 case CMD_SECREFITEM:
5112 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5113 break;
5114 case CMD_ENDSECREFLIST:
5115 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5116 break;
5117 case CMD_FORMULA:
5118 {
5119 DocFormula *form=new DocFormula(this,g_token->id);
5120 m_children.append(form);
5121 }
5122 break;
5123 //case CMD_LANGSWITCH:
5124 // retval = handleLanguageSwitch();
5125 // break;
5126 case CMD_INTERNALREF:
5127 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: unexpected command %s",qPrint(g_token->name));
5128 break;
5129 case CMD_INHERITDOC:
5130 handleInheritDoc();
5131 break;
5132 default:
5133 // we should not get here!
5134 ASSERT(0);
5135 break;
5136 }
5137 INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec ||
5138 retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA ||
5139 retval==RetVal_Section || retval==RetVal_EndList ||
5140 retval==RetVal_Internal || retval==RetVal_SwitchLang
5141 );
5142 DBG(("handleCommand(%s) end retval=%x\n",qPrint(cmdName),retval));
5143 return retval;
5144}
5145
5146static bool findAttribute(const HtmlAttribList &tagHtmlAttribs,
5147 const char *attrName,
5148 QCString *result)
5149{
5150
5151 HtmlAttribListIterator li(tagHtmlAttribs);
5152 HtmlAttrib *opt;
5153 for (li.toFirst();(opt=li.current());++li)
5154 {
5155 if (opt->name==attrName)
5156 {
5157 *result = opt->value;
5158 return TRUE;
5159 }
5160 }
5161 return FALSE;
5162}
5163
5164int DocPara::handleHtmlStartTag(const QCString &tagName,const HtmlAttribList &tagHtmlAttribs)
5165{
5166 DBG(("handleHtmlStartTag(%s,%d)\n",qPrint(tagName),tagHtmlAttribs.count()));
5167 int retval=RetVal_OK;
5168 int tagId = Mappers::htmlTagMapper->map(tagName);
5169 if (g_token->emptyTag && !(tagId&XML_CmdMask) &&
5170 tagId!=HTML_UNKNOWN && tagId!=HTML_IMG && tagId!=HTML_BR)
5171 {
5172 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: HTML tags may not use the 'empty tag' XHTML syntax.");
5173 }
5174 switch (tagId)
5175 {
5176 case HTML_UL:
5177 {
5178 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered);
5179 m_children.append(list);
5180 retval=list->parse();
5181 }
5182 break;
5183 case HTML_OL:
5184 {
5185 DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered);
5186 m_children.append(list);
5187 retval=list->parse();
5188 }
5189 break;
5190 case HTML_LI:
5191 if (!insideUL(this) && !insideOL(this))
5192 {
5193 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: lonely <li> tag found");
5194 }
5195 else
5196 {
5197 retval=RetVal_ListItem;
5198 }
5199 break;
5200 case HTML_BOLD:
5201 handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
5202 break;
5203 case HTML_CODE:
5204 if (getLanguageFromFileName(g_fileName)==SrcLangExt_CSharp)
5205 // for C# code we treat <code> as an XML tag
5206 {
5207 doctokenizerYYsetStateXmlCode();
5208 retval = handleStartCode();
5209 }
5210 else // normal HTML markup
5211 {
5212 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
5213 }
5214 break;
5215 case HTML_EMPHASIS:
5216 handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
5217 break;
5218 case HTML_DIV:
5219 handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs);
5220 break;
5221 case HTML_SPAN:
5222 handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs);
5223 break;
5224 case HTML_SUB:
5225 handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs);
5226 break;
5227 case HTML_SUP:
5228 handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs);
5229 break;
5230 case HTML_CENTER:
5231 handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs);
5232 break;
5233 case HTML_SMALL:
5234 handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs);
5235 break;
5236 case HTML_PRE:
5237 handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
5238 setInsidePreformatted(TRUE);
5239 //doctokenizerYYsetInsidePre(TRUE);
5240 break;
5241 case HTML_P:
5242 retval=TK_NEWPARA;
5243 break;
5244 case HTML_DL:
5245 {
5246 DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs);
5247 m_children.append(list);
5248 retval=list->parse();
5249 }
5250 break;
5251 case HTML_DT:
5252 retval = RetVal_DescTitle;
5253 break;
5254 case HTML_DD:
5255 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag <dd> found");
5256 break;
5257 case HTML_TABLE:
5258 {
5259 DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
5260 m_children.append(table);
5261 retval=table->parse();
5262 }
5263 break;
5264 case HTML_TR:
5265 retval = RetVal_TableRow;
5266 break;
5267 case HTML_TD:
5268 retval = RetVal_TableCell;
5269 break;
5270 case HTML_TH:
5271 retval = RetVal_TableHCell;
5272 break;
5273 case HTML_CAPTION:
5274 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag <caption> found");
5275 break;
5276 case HTML_BR:
5277 {
5278 DocLineBreak *lb = new DocLineBreak(this);
5279 m_children.append(lb);
5280 }
5281 break;
5282 case HTML_HR:
5283 {
5284 DocHorRuler *hr = new DocHorRuler(this);
5285 m_children.append(hr);
5286 }
5287 break;
5288 case HTML_A:
5289 retval=handleAHref(this,m_children,tagHtmlAttribs);
5290 break;
5291 case HTML_H1:
5292 retval=handleHtmlHeader(tagHtmlAttribs,1);
5293 break;
5294 case HTML_H2:
5295 retval=handleHtmlHeader(tagHtmlAttribs,2);
5296 break;
5297 case HTML_H3:
5298 retval=handleHtmlHeader(tagHtmlAttribs,3);
5299 break;
5300 case HTML_H4:
5301 retval=handleHtmlHeader(tagHtmlAttribs,4);
5302 break;
5303 case HTML_H5:
5304 retval=handleHtmlHeader(tagHtmlAttribs,5);
5305 break;
5306 case HTML_H6:
5307 retval=handleHtmlHeader(tagHtmlAttribs,6);
5308 break;
5309 case HTML_IMG:
5310 {
5311 HtmlAttribListIterator li(tagHtmlAttribs);
5312 HtmlAttrib *opt;
5313 bool found=FALSE;
5314 int index=0;
5315 for (li.toFirst();(opt=li.current());++li,++index)
5316 {
5317 //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
5318 if (opt->name=="src" && !opt->value.isEmpty())
5319 {
5320 // copy attributes
5321 HtmlAttribList attrList = tagHtmlAttribs;
5322 // and remove the src attribute
5323 bool result = attrList.remove(index);
5324 ASSERT(result);
5325 DocImage *img = new DocImage(this,attrList,opt->value,DocImage::Html);
5326 m_children.append(img);
5327 found = TRUE;
5328 }
5329 }
5330 if (!found)
5331 {
5332 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: IMG tag does not have a SRC attribute!\n");
5333 }
5334 }
5335 break;
5336
5337 case XML_SUMMARY:
5338 case XML_REMARKS:
5339 case XML_VALUE:
5340 case XML_PARA:
5341 if (!m_children.isEmpty())
5342 {
5343 retval = TK_NEWPARA;
5344 }
5345 break;
5346 case XML_EXAMPLE:
5347 case XML_DESCRIPTION:
5348 if (insideTable(this))
5349 {
5350 retval=RetVal_TableCell;
5351 }
5352 break;
5353 case XML_C:
5354 handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
5355 break;
5356 case XML_PARAM:
5357 case XML_TYPEPARAM:
5358 {
5359 QCString paramName;
5360 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5361 {
5362 if (paramName.isEmpty())
5363 {
5364 if (Config_getBool("WARN_NO_PARAMDOC"))
5365 {
5366 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: empty 'name' attribute for <param> tag.");
5367 }
5368 }
5369 else
5370 {
5371 retval = handleParamSection(paramName,
5372 tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam,
5373 TRUE);
5374 }
5375 }
5376 else
5377 {
5378 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <param> tag.");
5379 }
5380 }
5381 break;
5382 case XML_PARAMREF:
5383 case XML_TYPEPARAMREF:
5384 {
5385 QCString paramName;
5386 if (findAttribute(tagHtmlAttribs,"name",&paramName))
5387 {
5388 //printf("paramName=%s\n",paramName.data());
5389 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
5390 m_children.append(new DocWord(this,paramName));
5391 m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
5392 if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
5393 }
5394 else
5395 {
5396 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type");
5397 }
5398 }
5399 break;
5400 case XML_EXCEPTION:
5401 {
5402 QCString exceptName;
5403 if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
5404 {
5405 retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
5406 }
5407 else
5408 {
5409 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'name' attribute from <exception> tag.");
5410 }
5411 }
5412 break;
5413 case XML_ITEM:
5414 case XML_LISTHEADER:
5415 if (insideTable(this))
5416 {
5417 retval=RetVal_TableRow;
5418 }
5419 else if (insideUL(this) || insideOL(this))
5420 {
5421 retval=RetVal_ListItem;
5422 }
5423 else
5424 {
5425 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: lonely <item> tag found");
5426 }
5427 break;
5428 case XML_RETURNS:
5429 retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
5430 g_hasReturnCommand=TRUE;
5431 break;
5432 case XML_TERM:
5433 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
5434 if (insideTable(this))
5435 {
5436 retval=RetVal_TableCell;
5437 }
5438 break;
5439 case XML_SEE:
5440 // I'm not sure if <see> is the same as <seealso> or if it
5441 // should you link a member without producing a section. The
5442 // C# specification is extremely vague about this (but what else
5443 // can we expect from Microsoft...)
5444 {
5445 QCString cref;
5446 //printf("XML_SEE: empty tag=%d\n",g_token->emptyTag);
5447 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5448 {
5449 if (g_token->emptyTag) // <see cref="..."/> style
5450 {
5451 bool inSeeBlock = g_inSeeBlock;
5452 g_token->name = cref;
5453 g_inSeeBlock = TRUE;
5454 handleLinkedWord(this,m_children);
5455 g_inSeeBlock = inSeeBlock;
5456 }
5457 else // <see cref="...">...</see> style
5458 {
5459 //DocRef *ref = new DocRef(this,cref);
5460 //m_children.append(ref);
5461 //ref->parse();
5462 doctokenizerYYsetStatePara();
5463 DocLink *lnk = new DocLink(this,cref);
5464 m_children.append(lnk);
5465 QCString leftOver = lnk->parse(FALSE,TRUE);
5466 if (!leftOver.isEmpty())
5467 {
5468 m_children.append(new DocWord(this,leftOver));
5469 }
5470 }
5471 }
5472 else
5473 {
5474 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'cref' attribute from <see> tag.");
5475 }
5476 }
5477 break;
5478 case XML_SEEALSO:
5479 {
5480 QCString cref;
5481 if (findAttribute(tagHtmlAttribs,"cref",&cref))
5482 {
5483 // Look for an existing "see" section
5484 DocSimpleSect *ss=0;
5485 QListIterator<DocNode> cli(m_children);
5486 DocNode *n;
5487 for (cli.toFirst();(n=cli.current());++cli)
5488 {
5489 if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
5490 {
5491 ss = (DocSimpleSect *)n;
5492 }
5493 }
5494
5495 if (!ss) // start new section
5496 {
5497 ss=new DocSimpleSect(this,DocSimpleSect::See);
5498 m_children.append(ss);
5499 }
5500
5501 ss->appendLinkWord(cref);
5502 retval = RetVal_OK;
5503 }
5504 else
5505 {
5506 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Missing 'cref' attribute from <seealso> tag.");
5507 }
5508 }
5509 break;
5510 case XML_LIST:
5511 {
5512 QCString type;
5513 findAttribute(tagHtmlAttribs,"type",&type);
5514 DocHtmlList::Type listType = DocHtmlList::Unordered;
5515 HtmlAttribList emptyList;
5516 if (type=="number")
5517 {
5518 listType=DocHtmlList::Ordered;
5519 }
5520 if (type=="table")
5521 {
5522 DocHtmlTable *table = new DocHtmlTable(this,emptyList);
5523 m_children.append(table);
5524 retval=table->parseXml();
5525 }
5526 else
5527 {
5528 DocHtmlList *list = new DocHtmlList(this,emptyList,listType);
5529 m_children.append(list);
5530 retval=list->parseXml();
5531 }
5532 }
5533 break;
5534 case XML_INCLUDE:
5535 case XML_PERMISSION:
5536 // These tags are defined in .Net but are currently unsupported
5537 break;
5538 case HTML_UNKNOWN:
5539 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported xml/html tag <%s> found", qPrint(tagName));
5540 m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
5541 break;
5542 default:
5543 // we should not get here!
5544 ASSERT(0);
5545 break;
5546 }
5547 return retval;
5548}
5549
5550int DocPara::handleHtmlEndTag(const QCString &tagName)
5551{
5552 DBG(("handleHtmlEndTag(%s)\n",qPrint(tagName)));
5553 int tagId = Mappers::htmlTagMapper->map(tagName);
5554 int retval=RetVal_OK;
5555 switch (tagId)
5556 {
5557 case HTML_UL:
5558 if (!insideUL(this))
5559 {
5560 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </ul> tag without matching <ul>");
5561 }
5562 else
5563 {
5564 retval=RetVal_EndList;
5565 }
5566 break;
5567 case HTML_OL:
5568 if (!insideOL(this))
5569 {
5570 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </ol> tag without matching <ol>");
5571 }
5572 else
5573 {
5574 retval=RetVal_EndList;
5575 }
5576 break;
5577 case HTML_LI:
5578 if (!insideLI(this))
5579 {
5580 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </li> tag without matching <li>");
5581 }
5582 else
5583 {
5584 // ignore </li> tags
5585 }
5586 break;
5587 //case HTML_PRE:
5588 // if (!insidePRE(this))
5589 // {
5590 // warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found </pre> tag without matching <pre>");
5591 // }
5592 // else
5593 // {
5594 // retval=RetVal_EndPre;
5595 // }
5596 // break;
5597 case HTML_BOLD:
5598 handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
5599 break;
5600 case HTML_CODE:
5601 handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
5602 break;
5603 case HTML_EMPHASIS:
5604 handleStyleLeave(this,m_children,DocStyleChange::Italic,"em");
5605 break;
5606 case HTML_DIV:
5607 handleStyleLeave(this,m_children,DocStyleChange::Div,"div");
5608 break;
5609 case HTML_SPAN:
5610 handleStyleLeave(this,m_children,DocStyleChange::Span,"span");
5611 break;
5612 case HTML_SUB:
5613 handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub");
5614 break;
5615 case HTML_SUP:
5616 handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup");
5617 break;
5618 case HTML_CENTER:
5619 handleStyleLeave(this,m_children,DocStyleChange::Center,"center");
5620 break;
5621 case HTML_SMALL:
5622 handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
5623 break;
5624 case HTML_PRE:
5625 handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
5626 setInsidePreformatted(FALSE);
5627 //doctokenizerYYsetInsidePre(FALSE);
5628 break;
5629 case HTML_P:
5630 // ignore </p> tag
5631 break;
5632 case HTML_DL:
5633 retval=RetVal_EndDesc;
5634 break;
5635 case HTML_DT:
5636 // ignore </dt> tag
5637 break;
5638 case HTML_DD:
5639 // ignore </dd> tag
5640 break;
5641 case HTML_TABLE:
5642 retval=RetVal_EndTable;
5643 break;
5644 case HTML_TR:
5645 // ignore </tr> tag
5646 break;
5647 case HTML_TD:
5648 // ignore </td> tag
5649 break;
5650 case HTML_TH:
5651 // ignore </th> tag
5652 break;
5653 case HTML_CAPTION:
5654 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </caption> found");
5655 break;
5656 case HTML_BR:
5657 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Illegal </br> tag found\n");
5658 break;
5659 case HTML_H1:
5660 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h1> found");
5661 break;
5662 case HTML_H2:
5663 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h2> found");
5664 break;
5665 case HTML_H3:
5666 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </h3> found");
5667 break;
5668 case HTML_IMG:
5669 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </img> found");
5670 break;
5671 case HTML_HR:
5672 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </hr> found");
5673 break;
5674 case HTML_A:
5675 //warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected tag </a> found");
5676 // ignore </a> tag (can be part of <a name=...></a>
5677 break;
5678
5679 case XML_TERM:
5680 //m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
5681 break;
5682 case XML_SUMMARY:
5683 case XML_REMARKS:
5684 case XML_PARA:
5685 case XML_VALUE:
5686 case XML_LIST:
5687 case XML_EXAMPLE:
5688 case XML_PARAM:
5689 case XML_TYPEPARAM:
5690 case XML_RETURNS:
5691 case XML_SEE:
5692 case XML_SEEALSO:
5693 case XML_EXCEPTION:
5694 retval = RetVal_CloseXml;
5695 break;
5696 case XML_C:
5697 handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
5698 break;
5699 case XML_ITEM:
5700 case XML_LISTHEADER:
5701 case XML_INCLUDE:
5702 case XML_PERMISSION:
5703 case XML_DESCRIPTION:
5704 case XML_PARAMREF:
5705 case XML_TYPEPARAMREF:
5706 // These tags are defined in .Net but are currently unsupported
5707 break;
5708 case HTML_UNKNOWN:
5709 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported xml/html tag </%s> found", qPrint(tagName));
5710 m_children.append(new DocWord(this,"</"+tagName+">"));
5711 break;
5712 default:
5713 // we should not get here!
5714 warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",qPrint(tagName));
5715 ASSERT(0);
5716 break;
5717 }
5718 return retval;
5719}
5720
5721int DocPara::parse()
5722{
5723 DBG(("DocPara::parse() start\n"));
5724 g_nodeStack.push(this);
5725 // handle style commands "inherited" from the previous paragraph
5726 handleInitialStyleCommands(this,m_children);
5727 int tok;
5728 int retval=0;
5729 while ((tok=doctokenizerYYlex())) // get the next token
5730 {
5731reparsetoken:
5732 DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
5733 if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL ||
5734 tok==TK_COMMAND || tok==TK_HTMLTAG
5735 )
5736 {
5737 DBG((" name=%s",qPrint(g_token->name)));
5738 }
5739 DBG(("\n"));
5740 switch(tok)
5741 {
5742 case TK_WORD:
5743 m_children.append(new DocWord(this,g_token->name));
5744 break;
5745 case TK_LNKWORD:
5746 handleLinkedWord(this,m_children);
5747 break;
5748 case TK_URL:
5749 m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr));
5750 break;
5751 case TK_WHITESPACE:
5752 {
5753 // prevent leading whitespace and collapse multiple whitespace areas
5754 DocNode::Kind k;
5755 if (insidePRE(this) || // all whitespace is relevant
5756 (
5757 // remove leading whitespace
5758 !m_children.isEmpty() &&
5759 // and whitespace after certain constructs
5760 (k=m_children.last()->kind())!=DocNode::Kind_HtmlDescList &&
5761 k!=DocNode::Kind_HtmlTable &&
5762 k!=DocNode::Kind_HtmlList &&
5763 k!=DocNode::Kind_SimpleSect &&
5764 k!=DocNode::Kind_AutoList &&
5765 k!=DocNode::Kind_SimpleList &&
5766 /*k!=DocNode::Kind_Verbatim &&*/
5767 k!=DocNode::Kind_HtmlHeader &&
5768 k!=DocNode::Kind_ParamSect &&
5769 k!=DocNode::Kind_XRefItem
5770 )
5771 )
5772 {
5773 m_children.append(new DocWhiteSpace(this,g_token->chars));
5774 }
5775 }
5776 break;
5777 case TK_LISTITEM:
5778 {
5779 DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind()));
5780 DocNode *n=parent();
5781 while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent();
5782 if (n) // we found an auto list up in the hierarchy
5783 {
5784 DocAutoList *al = (DocAutoList *)n;
5785 DBG(("previous list item at %d\n",al->indent()));
5786 if (al->indent()>=g_token->indent)
5787 // new item at the same or lower indent level
5788 {
5789 retval=TK_LISTITEM;
5790 goto endparagraph;
5791 }
5792 }
5793
5794 // determine list depth
5795 int depth = 0;
5796 n=parent();
5797 while(n)
5798 {
5799 if(n->kind() == DocNode::Kind_AutoList) ++depth;
5800 n=n->parent();
5801 }
5802
5803 // first item or sub list => create new list
5804 DocAutoList *al=0;
5805 do
5806 {
5807 al = new DocAutoList(this,g_token->indent,g_token->isEnumList,
5808 depth);
5809 m_children.append(al);
5810 retval = al->parse();
5811 } while (retval==TK_LISTITEM && // new list
5812 al->indent()==g_token->indent // at same indent level
5813 );
5814
5815 // check the return value
5816 if (retval==RetVal_SimpleSec) // auto list ended due to simple section command
5817 {
5818 // Reparse the token that ended the section at this level,
5819 // so a new simple section will be started at this level.
5820 // This is the same as unputting the last read token and continuing.
5821 g_token->name = g_token->simpleSectName;
5822 if (g_token->name.left(4)=="rcs:") // RCS section
5823 {
5824 g_token->name = g_token->name.mid(4);
5825 g_token->text = g_token->simpleSectText;
5826 tok = TK_RCSTAG;
5827 }
5828 else // other section
5829 {
5830 tok = TK_COMMAND;
5831 }
5832 DBG(("reparsing command %s\n",qPrint(g_token->name)));
5833 goto reparsetoken;
5834 }
5835 else if (retval==TK_ENDLIST)
5836 {
5837 if (al->indent()>g_token->indent) // end list
5838 {
5839 goto endparagraph;
5840 }
5841 else // continue with current paragraph
5842 {
5843 }
5844 }
5845 else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF
5846 {
5847 goto endparagraph;
5848 }
5849 }
5850 break;
5851 case TK_ENDLIST:
5852 DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno));
5853 if (parent()->kind()==DocNode::Kind_AutoListItem)
5854 {
5855 ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList);
5856 DocAutoList *al = (DocAutoList *)parent()->parent();
5857 if (al->indent()>=g_token->indent)
5858 {
5859 // end of list marker ends this paragraph
5860 retval=TK_ENDLIST;
5861 goto endparagraph;
5862 }
5863 else
5864 {
5865 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: End of list marker found "
5866 "has invalid indent level");
5867 }
5868 }
5869 else
5870 {
5871 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: End of list marker found without any preceding "
5872 "list items");
5873 }
5874 break;
5875 case TK_COMMAND:
5876 {
5877 // see if we have to start a simple section
5878 int cmd = Mappers::cmdMapper->map(g_token->name);
5879 DocNode *n=parent();
5880 while (n &&
5881 n->kind()!=DocNode::Kind_SimpleSect &&
5882 n->kind()!=DocNode::Kind_ParamSect
5883 )
5884 {
5885 n=n->parent();
5886 }
5887 if (cmd&SIMPLESECT_BIT)
5888 {
5889 if (n) // already in a simple section
5890 {
5891 // simple section cannot start in this paragraph, need
5892 // to unwind the stack and remember the command.
5893 g_token->simpleSectName = g_token->name.copy();
5894 retval=RetVal_SimpleSec;
5895 goto endparagraph;
5896 }
5897 }
5898 // see if we are in a simple list
5899 n=parent();
5900 while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent();
5901 if (n)
5902 {
5903 if (cmd==CMD_LI)
5904 {
5905 retval=RetVal_ListItem;
5906 goto endparagraph;
5907 }
5908 }
5909
5910 // handle the command
5911 retval=handleCommand(g_token->name.copy());
5912 DBG(("handleCommand returns %x\n",retval));
5913
5914 // check the return value
5915 if (retval==RetVal_SimpleSec)
5916 {
5917 // Reparse the token that ended the section at this level,
5918 // so a new simple section will be started at this level.
5919 // This is the same as unputting the last read token and continuing.
5920 g_token->name = g_token->simpleSectName;
5921 if (g_token->name.left(4)=="rcs:") // RCS section
5922 {
5923 g_token->name = g_token->name.mid(4);
5924 g_token->text = g_token->simpleSectText;
5925 tok = TK_RCSTAG;
5926 }
5927 else // other section
5928 {
5929 tok = TK_COMMAND;
5930 }
5931 DBG(("reparsing command %s\n",qPrint(g_token->name)));
5932 goto reparsetoken;
5933 }
5934 else if (retval==RetVal_OK)
5935 {
5936 // the command ended normally, keep scanning for new tokens.
5937 retval = 0;
5938 }
5939 else if (retval>0 && retval<RetVal_OK)
5940 {
5941 // the command ended with a new command, reparse this token
5942 tok = retval;
5943 goto reparsetoken;
5944 }
5945 else // end of file, end of paragraph, start or end of section
5946 // or some auto list marker
5947 {
5948 goto endparagraph;
5949 }
5950 }
5951 break;
5952 case TK_HTMLTAG:
5953 {
5954 if (!g_token->endTag) // found a start tag
5955 {
5956 retval = handleHtmlStartTag(g_token->name,g_token->attribs);
5957 }
5958 else // found an end tag
5959 {
5960 retval = handleHtmlEndTag(g_token->name);
5961 }
5962 if (retval==RetVal_OK)
5963 {
5964 // the command ended normally, keep scanner for new tokens.
5965 retval = 0;
5966 }
5967 else
5968 {
5969 goto endparagraph;
5970 }
5971 }
5972 break;
5973 case TK_SYMBOL:
5974 {
5975 char letter='\0';
5976 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
5977 if (s!=DocSymbol::Unknown)
5978 {
5979 m_children.append(new DocSymbol(this,s,letter));
5980 }
5981 else
5982 {
5983 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
5984 qPrint(g_token->name));
5985 }
5986 break;
5987 }
5988 case TK_NEWPARA:
5989 retval=TK_NEWPARA;
5990 goto endparagraph;
5991 case TK_RCSTAG:
5992 {
5993 DocNode *n=parent();
5994 while (n &&
5995 n->kind()!=DocNode::Kind_SimpleSect &&
5996 n->kind()!=DocNode::Kind_ParamSect
5997 )
5998 {
5999 n=n->parent();
6000 }
6001 if (n) // already in a simple section
6002 {
6003 // simple section cannot start in this paragraph, need
6004 // to unwind the stack and remember the command.
6005 g_token->simpleSectName = "rcs:"+g_token->name;
6006 g_token->simpleSectText = g_token->text;
6007 retval=RetVal_SimpleSec;
6008 goto endparagraph;
6009 }
6010
6011 // see if we are in a simple list
6012 DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs);
6013 m_children.append(ss);
6014 ss->parseRcs();
6015 }
6016 break;
6017 default:
6018 warn_doc_error(g_fileName,doctokenizerYYlineno,
6019 "warning: Found unexpected token (id=%x)\n",tok);
6020 break;
6021 }
6022 }
6023 retval=0;
6024endparagraph:
6025 handlePendingStyleCommands(this,m_children);
6026 DocNode *n = g_nodeStack.pop();
6027 ASSERT(n==this);
6028 DBG(("DocPara::parse() end retval=%x\n",retval));
6029 INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM ||
6030 retval==TK_ENDLIST || retval>RetVal_OK
6031);
6032
6033 return retval;
6034}
6035
6036//--------------------------------------------------------------------------
6037
6038int DocSection::parse()
6039{
6040 DBG(("DocSection::parse() start %s level=%d\n",qPrint(g_token->sectionId),m_level));
6041 int retval=RetVal_OK;
6042 g_nodeStack.push(this);
6043
6044 SectionInfo *sec;
6045 if (!m_id.isEmpty())
6046 {
6047 sec=Doxygen::sectionDict[m_id];
6048 if (sec)
6049 {
6050 m_file = sec->fileName;
6051 m_anchor = sec->label;
6052 m_title = sec->title;
6053 if (m_title.isEmpty()) m_title = sec->label;
6054 if (g_sectionDict && g_sectionDict->find(m_id)==0)
6055 {
6056 g_sectionDict->insert(m_id,sec);
6057 }
6058 }
6059 }
6060
6061 // first parse any number of paragraphs
6062 bool isFirst=TRUE;
6063 DocPara *lastPar=0;
6064 do
6065 {
6066 DocPara *par = new DocPara(this);
6067 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6068 retval=par->parse();
6069 if (!par->isEmpty())
6070 {
6071 m_children.append(par);
6072 lastPar=par;
6073 }
6074 else
6075 {
6076 delete par;
6077 }
6078 if (retval==TK_LISTITEM)
6079 {
6080 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found");
6081 }
6082 } while (retval!=0 &&
6083 retval!=RetVal_Internal &&
6084 retval!=RetVal_Section &&
6085 retval!=RetVal_Subsection &&
6086 retval!=RetVal_Subsubsection &&
6087 retval!=RetVal_Paragraph
6088 );
6089
6090 if (lastPar) lastPar->markLast();
6091
6092 //printf("m_level=%d <-> %d\n",m_level,Doxygen::subpageNestingLevel);
6093
6094 if (retval==RetVal_Subsection && m_level==Doxygen::subpageNestingLevel+1)
6095 {
6096 // then parse any number of nested sections
6097 while (retval==RetVal_Subsection) // more sections follow
6098 {
6099 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6100 DocSection *s=new DocSection(this,
6101 QMIN(2+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6102 m_children.append(s);
6103 retval = s->parse();
6104 }
6105 }
6106 else if (retval==RetVal_Subsubsection && m_level==Doxygen::subpageNestingLevel+2)
6107 {
6108 // then parse any number of nested sections
6109 while (retval==RetVal_Subsubsection) // more sections follow
6110 {
6111 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6112 DocSection *s=new DocSection(this,
6113 QMIN(3+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6114 m_children.append(s);
6115 retval = s->parse();
6116 }
6117 }
6118 else if (retval==RetVal_Paragraph && m_level==QMIN(5,Doxygen::subpageNestingLevel+3))
6119 {
6120 // then parse any number of nested sections
6121 while (retval==RetVal_Paragraph) // more sections follow
6122 {
6123 //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6124 DocSection *s=new DocSection(this,
6125 QMIN(4+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6126 m_children.append(s);
6127 retval = s->parse();
6128 }
6129 }
6130 else if ((m_level<=1+Doxygen::subpageNestingLevel && retval==RetVal_Subsubsection) ||
6131 (m_level<=2+Doxygen::subpageNestingLevel && retval==RetVal_Paragraph)
6132 )
6133 {
6134 int level;
6135 if (retval==RetVal_Subsection) level=2;
6136 else if (retval==RetVal_Subsubsection) level=3;
6137 else level=4;
6138 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected %s "
6139 "command found inside %s!",
6140 sectionLevelToName[level],sectionLevelToName[m_level]);
6141 retval=0; // stop parsing
6142
6143 }
6144 else if (retval==RetVal_Internal)
6145 {
6146 DocInternal *in = new DocInternal(this);
6147 m_children.append(in);
6148 retval = in->parse(m_level+1);
6149 }
6150 else
6151 {
6152 }
6153
6154 INTERNAL_ASSERT(retval==0 ||
6155 retval==RetVal_Section ||
6156 retval==RetVal_Subsection ||
6157 retval==RetVal_Subsubsection ||
6158 retval==RetVal_Paragraph ||
6159 retval==RetVal_Internal
6160 );
6161
6162 DBG(("DocSection::parse() end\n"));
6163 DocNode *n = g_nodeStack.pop();
6164 ASSERT(n==this);
6165 return retval;
6166}
6167
6168//--------------------------------------------------------------------------
6169
6170void DocText::parse()
6171{
6172 DBG(("DocText::parse() start\n"));
6173 g_nodeStack.push(this);
6174 doctokenizerYYsetStateText();
6175
6176 int tok;
6177 while ((tok=doctokenizerYYlex())) // get the next token
6178 {
6179 switch(tok)
6180 {
6181 case TK_WORD:
6182m_children.append(new DocWord(this,g_token->name));
6183break;
6184 case TK_WHITESPACE:
6185 m_children.append(new DocWhiteSpace(this,g_token->chars));
6186break;
6187 case TK_SYMBOL:
6188 {
6189 char letter='\0';
6190 DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
6191 if (s!=DocSymbol::Unknown)
6192 {
6193 m_children.append(new DocSymbol(this,s,letter));
6194 }
6195 else
6196 {
6197 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unsupported symbol %s found",
6198 qPrint(g_token->name));
6199 }
6200 }
6201 break;
6202 case TK_COMMAND:
6203 switch (Mappers::cmdMapper->map(g_token->name))
6204 {
6205 case CMD_BSLASH:
6206 m_children.append(new DocSymbol(this,DocSymbol::BSlash));
6207 break;
6208 case CMD_AT:
6209 m_children.append(new DocSymbol(this,DocSymbol::At));
6210 break;
6211 case CMD_LESS:
6212 m_children.append(new DocSymbol(this,DocSymbol::Less));
6213 break;
6214 case CMD_GREATER:
6215 m_children.append(new DocSymbol(this,DocSymbol::Greater));
6216 break;
6217 case CMD_AMP:
6218 m_children.append(new DocSymbol(this,DocSymbol::Amp));
6219 break;
6220 case CMD_DOLLAR:
6221 m_children.append(new DocSymbol(this,DocSymbol::Dollar));
6222 break;
6223 case CMD_HASH:
6224 m_children.append(new DocSymbol(this,DocSymbol::Hash));
6225 break;
6226 case CMD_DCOLON:
6227 m_children.append(new DocSymbol(this,DocSymbol::DoubleColon));
6228 break;
6229 case CMD_PERCENT:
6230 m_children.append(new DocSymbol(this,DocSymbol::Percent));
6231 break;
6232 case CMD_QUOTE:
6233 m_children.append(new DocSymbol(this,DocSymbol::Quot));
6234 break;
6235 default:
6236 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected command `%s' found",
6237 qPrint(g_token->name));
6238 break;
6239 }
6240 break;
6241 default:
6242 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Unexpected token %s",
6243 tokToString(tok));
6244 break;
6245 }
6246 }
6247
6248 handleUnclosedStyleCommands();
6249
6250 DocNode *n = g_nodeStack.pop();
6251 ASSERT(n==this);
6252 DBG(("DocText::parse() end\n"));
6253}
6254
6255
6256//--------------------------------------------------------------------------
6257
6258void DocRoot::parse()
6259{
6260 DBG(("DocRoot::parse() start\n"));
6261 g_nodeStack.push(this);
6262 doctokenizerYYsetStatePara();
6263 int retval=0;
6264
6265 // first parse any number of paragraphs
6266 bool isFirst=TRUE;
6267 DocPara *lastPar=0;
6268 do
6269 {
6270 DocPara *par = new DocPara(this);
6271 if (isFirst) { par->markFirst(); isFirst=FALSE; }
6272 retval=par->parse();
6273 if (!par->isEmpty())
6274 {
6275 m_children.append(par);
6276 lastPar=par;
6277 }
6278 else
6279 {
6280 delete par;
6281 }
6282 if (retval==TK_LISTITEM)
6283 {
6284 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid list item found");
6285 }
6286 else if (retval==RetVal_Subsection)
6287 {
6288 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found subsection command outside of section context!");
6289 }
6290 else if (retval==RetVal_Subsubsection)
6291 {
6292 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found subsubsection command outside of subsection context!");
6293 }
6294 else if (retval==RetVal_Paragraph)
6295 {
6296 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: found paragraph command outside of subsubsection context!");
6297 }
6298 } while (retval!=0 && retval!=RetVal_Section && retval!=RetVal_Internal);
6299 if (lastPar) lastPar->markLast();
6300
6301 //printf("DocRoot::parse() retval=%d %d\n",retval,RetVal_Section);
6302 // then parse any number of level1 sections
6303 while (retval==RetVal_Section)
6304 {
6305 SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
6306 if (sec)
6307 {
6308 DocSection *s=new DocSection(this,
6309 QMIN(1+Doxygen::subpageNestingLevel,5),g_token->sectionId);
6310 m_children.append(s);
6311 retval = s->parse();
6312 }
6313 else
6314 {
6315 warn_doc_error(g_fileName,doctokenizerYYlineno,"warning: Invalid section id `%s'; ignoring section",qPrint(g_token->sectionId));
6316 retval = 0;
6317 }
6318 }
6319
6320 if (retval==RetVal_Internal)
6321 {
6322 DocInternal *in = new DocInternal(this);
6323 m_children.append(in);
6324 retval = in->parse(1);
6325 }
6326
6327
6328 handleUnclosedStyleCommands();
6329
6330 DocNode *n = g_nodeStack.pop();
6331 ASSERT(n==this);
6332 DBG(("DocRoot::parse() end\n"));
6333}
6334
6335//--------------------------------------------------------------------------
6336
6337DocNode *validatingParseDoc(const char *fileName,int startLine,
6338 Definition *ctx,MemberDef *md,
6339 const char *input,bool indexWords,
6340 bool isExample, const char *exampleName,
6341 bool singleLine, bool linkFromIndex)
6342{
6343 //printf("validatingParseDoc(%s,%s)=[%s]\n",ctx?ctx->name().data():"<none>",
6344 // md?md->name().data():"<none>",
6345 // input);
6346 //printf("========== validating %s at line %d\n",fileName,startLine);
6347 //printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input);
6348 //g_token = new TokenInfo;
6349
6350 // store parser state so we can re-enter this function if needed
6351 bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
6352 docParserPushContext();
6353
6354 if (ctx && ctx!=Doxygen::globalScope &&
6355 (ctx->definitionType()==Definition::TypeClass ||
6356 ctx->definitionType()==Definition::TypeNamespace
6357 )
6358 )
6359 {
6360 g_context = ctx->name();
6361 }
6362 else if (ctx && ctx->definitionType()==Definition::TypePage)
6363 {
6364 Definition *scope = ((PageDef*)ctx)->getPageScope();
6365 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
6366 }
6367 else if (ctx && ctx->definitionType()==Definition::TypeGroup)
6368 {
6369 Definition *scope = ((GroupDef*)ctx)->getGroupScope();
6370 if (scope && scope!=Doxygen::globalScope) g_context = scope->name();
6371 }
6372 else
6373 {
6374 g_context = "";
6375 }
6376 g_scope = ctx;
6377
6378 if (indexWords && md && Doxygen::searchIndex)
6379 {
6380 g_searchUrl=md->getOutputFileBase();
6381 Doxygen::searchIndex->setCurrentDoc(
6382 (fortranOpt?theTranslator->trSubprogram(TRUE,TRUE):theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(),
6383 g_searchUrl,
6384 md->anchor());
6385 }
6386 else if (indexWords && ctx && Doxygen::searchIndex)
6387 {
6388 g_searchUrl=ctx->getOutputFileBase();
6389 QCString name = ctx->qualifiedName();
6390 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
6391 {
6392 name = substitute(name,"::",".");
6393 }
6394 switch (ctx->definitionType())
6395 {
6396 case Definition::TypePage:
6397 {
6398 PageDef *pd = (PageDef *)ctx;
6399 if (!pd->title().isEmpty())
6400 {
6401 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title();
6402 }
6403 else
6404 {
6405 name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name();
6406 }
6407 }
6408 break;
6409 case Definition::TypeClass:
6410 {
6411 ClassDef *cd = (ClassDef *)ctx;
6412 name.prepend(cd->compoundTypeString()+" ");
6413 }
6414 break;
6415 case Definition::TypeNamespace:
6416 {
6417 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
6418 {
6419 name = theTranslator->trPackage(name);
6420 }
6421 else if(fortranOpt)
6422 {
6423 name.prepend(theTranslator->trModule(TRUE,TRUE)+" ");
6424 }
6425 else
6426 {
6427 name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" ");
6428 }
6429 }
6430 break;
6431 case Definition::TypeGroup:
6432 {
6433 GroupDef *gd = (GroupDef *)ctx;
6434 if (gd->groupTitle())
6435 {
6436 name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle();
6437 }
6438 else
6439 {
6440 name.prepend(theTranslator->trGroup(TRUE,TRUE)+" ");
6441 }
6442 }
6443 break;
6444 default:
6445 break;
6446 }
6447 Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl);
6448 }
6449 else
6450 {
6451 g_searchUrl="";
6452 }
6453
6454 g_fileName = fileName;
6455 g_relPath = (!linkFromIndex && ctx) ?
6456 QCString(relativePathToRoot(ctx->getOutputFileBase())) :
6457 QCString("");
6458 //printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data());
6459 g_memberDef = md;
6460 g_nodeStack.clear();
6461 g_styleStack.clear();
6462 g_initialStyleStack.clear();
6463 g_inSeeBlock = FALSE;
6464 g_insideHtmlLink = FALSE;
6465 g_includeFileText = "";
6466 g_includeFileOffset = 0;
6467 g_includeFileLength = 0;
6468 g_isExample = isExample;
6469 g_exampleName = exampleName;
6470 g_hasParamCommand = FALSE;
6471 g_hasReturnCommand = FALSE;
6472 g_paramsFound.setAutoDelete(FALSE);
6473 g_paramsFound.clear();
6474 g_sectionDict = 0; //sections;
6475
6476 //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
6477 doctokenizerYYlineno=startLine;
6478 doctokenizerYYinit(input,g_fileName);
6479
6480
6481 // build abstract syntax tree
6482 DocRoot *root = new DocRoot(md!=0,singleLine);
6483 root->parse();
6484
6485
6486 if (Debug::isFlagSet(Debug::PrintTree))
6487 {
6488 // pretty print the result
6489 PrintDocVisitor *v = new PrintDocVisitor;
6490 root->accept(v);
6491 delete v;
6492 }
6493
6494
6495 checkUndocumentedParams();
6496 detectNoDocumentedParams();
6497
6498 // TODO: These should be called at the end of the program.
6499 //doctokenizerYYcleanup();
6500 //Mappers::cmdMapper->freeInstance();
6501 //Mappers::htmlTagMapper->freeInstance();
6502
6503 // restore original parser state
6504 docParserPopContext();
6505
6506 //printf(">>>>>> end validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>",
6507 // md?md->name().data():"<none>");
6508
6509 return root;
6510}
6511
6512DocNode *validatingParseText(const char *input)
6513{
6514 // store parser state so we can re-enter this function if needed
6515 docParserPushContext();
6516
6517 //printf("------------ input ---------\n%s\n"
6518 // "------------ end input -----\n",input);
6519 //g_token = new TokenInfo;
6520 g_context = "";
6521 g_fileName = "<parseText>";
6522 g_relPath = "";
6523 g_memberDef = 0;
6524 g_nodeStack.clear();
6525 g_styleStack.clear();
6526 g_initialStyleStack.clear();
6527 g_inSeeBlock = FALSE;
6528 g_insideHtmlLink = FALSE;
6529 g_includeFileText = "";
6530 g_includeFileOffset = 0;
6531 g_includeFileLength = 0;
6532 g_isExample = FALSE;
6533 g_exampleName = "";
6534 g_hasParamCommand = FALSE;
6535 g_hasReturnCommand = FALSE;
6536 g_paramsFound.setAutoDelete(FALSE);
6537 g_paramsFound.clear();
6538 g_searchUrl="";
6539
6540 DocText *txt = new DocText;
6541
6542 if (input)
6543 {
6544 doctokenizerYYlineno=1;
6545 doctokenizerYYinit(input,g_fileName);
6546
6547 // build abstract syntax tree
6548 txt->parse();
6549
6550 if (Debug::isFlagSet(Debug::PrintTree))
6551 {
6552 // pretty print the result
6553 PrintDocVisitor *v = new PrintDocVisitor;
6554 txt->accept(v);
6555 delete v;
6556 }
6557 }
6558
6559 // restore original parser state
6560 docParserPopContext();
6561 return txt;
6562}
6563
6564void docFindSections(const char *input,
6565 Definition *d,
6566 MemberGroup *mg,
6567 const char *fileName)
6568{
6569 doctokenizerYYFindSections(input,d,mg,fileName);
6570}
6571
6572void initDocParser()
6573{
6574 static bool searchEngine = Config_getBool("SEARCHENGINE");
6575 static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
6576 if (searchEngine && serverBasedSearch)
6577 {
6578 Doxygen::searchIndex = new SearchIndex;
6579 }
6580 else // no search engine or pure javascript based search function
6581 {
6582 Doxygen::searchIndex = 0;
6583 }
6584}
6585
6586void finializeDocParser()
6587{
6588 delete Doxygen::searchIndex;
6589}
6590
6591

Archive Download this file

Revision: 1322