docparser.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  * $Id: $
00004  *
00005  *
00006  * Copyright (C) 1997-2008 by Dimitri van Heesch.
00007  *
00008  * Permission to use, copy, modify, and distribute this software and its
00009  * documentation under the terms of the GNU General Public License is hereby 
00010  * granted. No representations are made about the suitability of this software 
00011  * for any purpose. It is provided "as is" without express or implied warranty.
00012  * See the GNU General Public License for more details.
00013  *
00014  * Documents produced by Doxygen are derivative works derived from the
00015  * input used in their production; they are not affected by this license.
00016  *
00017  */
00018 
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 
00022 #include <qfile.h>
00023 #include <qfileinfo.h>
00024 #include <qcstring.h>
00025 #include <qstack.h>
00026 #include <qdict.h>
00027 #include <qregexp.h>
00028 #include <ctype.h>
00029 
00030 #include "doxygen.h"
00031 #include "debug.h"
00032 #include "util.h"
00033 #include "pagedef.h"
00034 
00035 #include "docparser.h"
00036 #include "doctokenizer.h"
00037 #include "cmdmapper.h"
00038 #include "printdocvisitor.h"
00039 #include "message.h"
00040 #include "section.h"
00041 #include "searchindex.h"
00042 #include "language.h"
00043 #include "portable.h"
00044 
00045 // debug off
00046 #define DBG(x) do {} while(0)
00047 
00048 // debug to stdout
00049 //#define DBG(x) printf x
00050 
00051 // debug to stderr
00052 //#define myprintf(x...) fprintf(stderr,x)
00053 //#define DBG(x) myprintf x
00054 
00055 #define INTERNAL_ASSERT(x) do {} while(0)
00056 //#define INTERNAL_ASSERT(x) if (!(x)) DBG(("INTERNAL_ASSERT(%s) failed retval=0x%x: file=%s line=%d\n",#x,retval,__FILE__,__LINE__)); 
00057 
00058 //---------------------------------------------------------------------------
00059 
00060 static const char *sectionLevelToName[] = 
00061 {
00062   "page",
00063   "section",
00064   "subsection",
00065   "subsubsection",
00066   "paragraph"
00067 };
00068 
00069 //---------------------------------------------------------------------------
00070 
00071 // Parser state: global variables during a call to validatingParseDoc
00072 static QString                g_context;
00073 static bool                   g_inSeeBlock;
00074 static bool                   g_insideHtmlLink;
00075 static QStack<DocNode>        g_nodeStack;
00076 static QStack<DocStyleChange> g_styleStack;
00077 static QStack<DocStyleChange> g_initialStyleStack;
00078 static QList<Definition>      g_copyStack;
00079 static QString                g_fileName;
00080 static QString                g_relPath;
00081 
00082 static bool                   g_hasParamCommand;
00083 static bool                   g_hasReturnCommand;
00084 static MemberDef *            g_memberDef;
00085 static QDict<void>            g_paramsFound;
00086 static bool                   g_isExample;
00087 static QCString               g_exampleName;
00088 static SectionDict *          g_sectionDict;
00089 static QCString               g_searchUrl;
00090 
00091 static QString                g_includeFileText;
00092 static uint                   g_includeFileOffset;
00093 static uint                   g_includeFileLength;
00094 
00095 // parser's context to store all global variables
00096 struct DocParserContext
00097 {
00098   QString context;
00099   bool inSeeBlock;
00100   bool insideHtmlLink;
00101   QStack<DocNode> nodeStack;
00102   QStack<DocStyleChange> styleStack;
00103   QStack<DocStyleChange> initialStyleStack;
00104   QList<Definition> copyStack;
00105   QString fileName;
00106   QString relPath;
00107 
00108   bool         hasParamCommand;
00109   bool         hasReturnCommand;
00110   MemberDef *  memberDef;
00111   QDict<void>  paramsFound;
00112   bool         isExample;
00113   QCString     exampleName;
00114   SectionDict *sectionDict;
00115   QCString     searchUrl;
00116 
00117   QString  includeFileText;
00118   uint     includeFileOffset;
00119   uint     includeFileLength;
00120 
00121   TokenInfo *token;
00122 };
00123 
00124 static QStack<DocParserContext> g_parserStack;
00125 
00126 //---------------------------------------------------------------------------
00127 
00128 static void docParserPushContext()
00129 {
00130   //QCString indent;
00131   //indent.fill(' ',g_parserStack.count()*2+2);
00132   //printf("%sdocParserPushContext() count=%d\n",indent.data(),g_nodeStack.count());
00133 
00134   doctokenizerYYpushContext();
00135   DocParserContext *ctx   = new DocParserContext;
00136   ctx->context            = g_context;
00137   ctx->inSeeBlock         = g_inSeeBlock;
00138   ctx->insideHtmlLink     = g_insideHtmlLink;
00139   ctx->nodeStack          = g_nodeStack;
00140   ctx->styleStack         = g_styleStack;
00141   ctx->initialStyleStack  = g_initialStyleStack;
00142   ctx->copyStack          = g_copyStack;
00143   ctx->fileName           = g_fileName;
00144   ctx->relPath            = g_relPath;
00145 
00146   ctx->hasParamCommand    = g_hasParamCommand;
00147   ctx->hasReturnCommand   = g_hasReturnCommand;
00148   ctx->memberDef          = g_memberDef;
00149   ctx->paramsFound        = g_paramsFound;
00150   ctx->isExample          = g_isExample;
00151   ctx->exampleName        = g_exampleName;
00152   ctx->sectionDict        = g_sectionDict;
00153   ctx->searchUrl          = g_searchUrl;
00154 
00155   ctx->includeFileText    = g_includeFileText;
00156   ctx->includeFileOffset  = g_includeFileOffset;
00157   ctx->includeFileLength  = g_includeFileLength;
00158   
00159   ctx->token              = g_token;
00160   g_token = new TokenInfo;
00161 
00162   g_parserStack.push(ctx);
00163 }
00164 
00165 static void docParserPopContext(bool keepParamInfo=FALSE)
00166 {
00167   DocParserContext *ctx = g_parserStack.pop();
00168   g_context             = ctx->context;
00169   g_inSeeBlock          = ctx->inSeeBlock;
00170   g_insideHtmlLink      = ctx->insideHtmlLink;
00171   g_nodeStack           = ctx->nodeStack;
00172   g_styleStack          = ctx->styleStack;
00173   g_initialStyleStack   = ctx->initialStyleStack;
00174   g_copyStack           = ctx->copyStack;
00175   g_fileName            = ctx->fileName;
00176   g_relPath             = ctx->relPath;
00177 
00178   if (!keepParamInfo)
00179   {
00180     g_hasParamCommand     = ctx->hasParamCommand;
00181     g_hasReturnCommand    = ctx->hasReturnCommand;
00182     g_paramsFound         = ctx->paramsFound;
00183   }
00184   g_memberDef           = ctx->memberDef;
00185   g_isExample           = ctx->isExample;
00186   g_exampleName         = ctx->exampleName;
00187   g_sectionDict         = ctx->sectionDict;
00188   g_searchUrl           = ctx->searchUrl;
00189 
00190   g_includeFileText     = ctx->includeFileText;
00191   g_includeFileOffset   = ctx->includeFileOffset;
00192   g_includeFileLength   = ctx->includeFileLength;
00193 
00194   delete g_token;
00195   g_token               = ctx->token;
00196 
00197   delete ctx;
00198   doctokenizerYYpopContext();
00199 
00200   //QCString indent;
00201   //indent.fill(' ',g_parserStack.count()*2+2);
00202   //printf("%sdocParserPopContext() count=%d\n",indent.data(),g_nodeStack.count());
00203 }
00204 
00205 //---------------------------------------------------------------------------
00206 
00211 static QCString findAndCopyImage(const char *fileName,DocImage::Type type)
00212 {
00213   QCString result;
00214   bool ambig;
00215   FileDef *fd;
00216   //printf("Search for %s\n",fileName);
00217   if ((fd=findFileDef(Doxygen::imageNameDict,fileName,ambig)))
00218   {
00219     QCString inputFile = fd->absFilePath();
00220     QFile inImage(inputFile);
00221     if (inImage.open(IO_ReadOnly))
00222     {
00223       result = fileName;
00224       int i;
00225       if ((i=result.findRev('/'))!=-1 || (i=result.findRev('\\'))!=-1)
00226       {
00227         result = result.right(result.length()-i-1);
00228       }
00229       //printf("fileName=%s result=%s\n",fileName,result.data());
00230       QCString outputDir;
00231       switch(type)
00232       {
00233         case DocImage::Html: 
00234           if (!Config_getBool("GENERATE_HTML")) return result;
00235           outputDir = Config_getString("HTML_OUTPUT");
00236           break;
00237         case DocImage::Latex: 
00238           if (!Config_getBool("GENERATE_LATEX")) return result;
00239           outputDir = Config_getString("LATEX_OUTPUT");
00240           break;
00241         case DocImage::Rtf:
00242           if (!Config_getBool("GENERATE_RTF")) return result;
00243           outputDir = Config_getString("RTF_OUTPUT");
00244           break;
00245       }
00246       QCString outputFile = outputDir+"/"+result;
00247       if (outputFile!=inputFile) // prevent copying to ourself
00248       {
00249         QFile outImage(outputFile.data());
00250         if (outImage.open(IO_WriteOnly)) // copy the image
00251         {
00252           char *buffer = new char[inImage.size()];
00253           inImage.readBlock(buffer,inImage.size());
00254           outImage.writeBlock(buffer,inImage.size());
00255           outImage.flush();
00256           delete buffer;
00257         }
00258         else
00259         {
00260           warn_doc_error(g_fileName,doctokenizerYYlineno,
00261               "Warning: could not write output image %s",outputFile.data());
00262         }
00263       }
00264     }
00265     else
00266     {
00267       warn_doc_error(g_fileName,doctokenizerYYlineno,
00268           "Warning: could not open image %s",fileName);
00269     }
00270 
00271     if (type==DocImage::Latex && Config_getBool("USE_PDFLATEX") && 
00272         fd->name().right(4)==".eps"
00273        )
00274     { // we have an .eps image in pdflatex mode => convert it to a pdf.
00275       QCString outputDir = Config_getString("LATEX_OUTPUT");
00276       QCString baseName  = fd->name().left(fd->name().length()-4);
00277       QCString epstopdfArgs(4096);
00278       epstopdfArgs.sprintf("\"%s/%s.eps\" --outfile=\"%s/%s.pdf\"",
00279                            outputDir.data(), baseName.data(),
00280                            outputDir.data(), baseName.data());
00281       if (portable_system("epstopdf",epstopdfArgs)!=0)
00282       {
00283         err("Error: Problems running epstopdf. Check your TeX installation!\n");
00284       }
00285       return baseName;
00286     }
00287   }
00288   else if (ambig)
00289   {
00290     QCString text;
00291     text.sprintf("Warning: image file name %s is ambigious.\n",fileName);
00292     text+="Possible candidates:\n";
00293     text+=showFileDefMatches(Doxygen::imageNameDict,fileName);
00294     warn_doc_error(g_fileName,doctokenizerYYlineno,text);
00295   }
00296   else
00297   {
00298     result=fileName;
00299     if (result.left(5)!="http:" && result.left(6)!="https:")
00300     {
00301       warn_doc_error(g_fileName,doctokenizerYYlineno,
00302            "Warning: image file %s is not found in IMAGE_PATH: "  
00303            "assuming external image.",fileName
00304           );
00305     }
00306   }
00307   return result;
00308 }
00309 
00316 static void checkArgumentName(const QString &name,bool isParam)
00317 {                
00318   if (!Config_getBool("WARN_IF_DOC_ERROR")) return;
00319   if (g_memberDef==0) return; // not a member
00320   LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ? 
00321                    g_memberDef->argumentList() :
00322                    g_memberDef->declArgumentList();
00323   if (al==0) return; // no argument list
00324 
00325   static QRegExp re("[a-zA-Z0-9_]+\\.*");
00326   int p=0,i=0,l;
00327   while ((i=re.match(name,p,&l))!=-1) // to handle @param x,y
00328   {
00329     QString aName=name.mid(i,l);
00330     //printf("aName=`%s'\n",aName.data());
00331     ArgumentListIterator ali(*al);
00332     Argument *a;
00333     bool found=FALSE;
00334     for (ali.toFirst();(a=ali.current());++ali)
00335     {
00336       QString argName = g_memberDef->isDefine() ? a->type : a->name;
00337       //printf("argName=`%s'\n",argName.data());
00338       if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
00339       if (aName==argName) 
00340       {
00341         //printf("adding `%s'\n",aName.data());
00342         g_paramsFound.insert(aName,(void *)(0x8));
00343         found=TRUE;
00344         break;
00345       }
00346     }
00347     if (!found && isParam)
00348     {
00349       //printf("member type=%d\n",memberDef->memberType());
00350       QString scope=g_memberDef->getScopeString();
00351       if (!scope.isEmpty()) scope+="::"; else scope="";
00352       QString inheritedFrom = "";
00353       QString docFile = g_memberDef->docFile();
00354       int docLine = g_memberDef->docLine();
00355       MemberDef *inheritedMd = g_memberDef->inheritsDocsFrom();
00356       if (inheritedMd) // documentation was inherited
00357       {
00358         inheritedFrom.sprintf(" inherited from member %s at line "
00359             "%d in file %s",inheritedMd->name().data(),
00360             inheritedMd->docLine(),inheritedMd->docFile().data());
00361         docFile = g_memberDef->getDefFileName();
00362         docLine = g_memberDef->getDefLine();
00363         
00364       }
00365       warn_doc_error(docFile,docLine,
00366           "Warning: argument `%s' of command @param "
00367           "is not found in the argument list of %s%s%s%s",
00368           aName.data(),scope.data(),g_memberDef->name().data(),
00369           argListToString(al.pointer()).data(),inheritedFrom.data());
00370     }
00371     p=i+l;
00372   }
00373 }
00374 
00380 static void checkUndocumentedParams()
00381 {
00382   if (g_memberDef && g_hasParamCommand && Config_getBool("WARN_IF_DOC_ERROR"))
00383   {
00384     LockingPtr<ArgumentList> al=g_memberDef->isDocsForDefinition() ? 
00385       g_memberDef->argumentList() :
00386       g_memberDef->declArgumentList();
00387     if (al!=0)
00388     {
00389       ArgumentListIterator ali(*al);
00390       Argument *a;
00391       bool found=FALSE;
00392       for (ali.toFirst();(a=ali.current());++ali)
00393       {
00394         QString argName = g_memberDef->isDefine() ? a->type : a->name;
00395         if (argName.right(3)=="...") argName=argName.left(argName.length()-3);
00396         if (!argName.isEmpty() && g_paramsFound.find(argName)==0 && a->docs.isEmpty()) 
00397         {
00398           found = TRUE;
00399           break;
00400         }
00401       }
00402       if (found)
00403       {
00404         bool first=TRUE;
00405         QString errMsg=
00406             "Warning: The following parameters of "+
00407             QString(g_memberDef->qualifiedName()) + 
00408             QString(argListToString(al.pointer())) +
00409             " are not documented:\n";
00410         for (ali.toFirst();(a=ali.current());++ali)
00411         {
00412           QString argName = g_memberDef->isDefine() ? a->type : a->name;
00413           if (!argName.isEmpty() && g_paramsFound.find(argName)==0) 
00414           {
00415             if (!first)
00416             {
00417               errMsg+="\n";
00418             }
00419             else
00420             {
00421               first=FALSE;
00422             }
00423             errMsg+="  parameter "+argName;
00424           }
00425         }
00426         if (g_memberDef->inheritsDocsFrom())
00427         {
00428            warn_doc_error(g_memberDef->getDefFileName(),
00429                           g_memberDef->getDefLine(),
00430                           substitute(errMsg,"%","%%"));
00431         }
00432         else
00433         {
00434            warn_doc_error(g_memberDef->docFile(),
00435                           g_memberDef->docLine(),
00436                           substitute(errMsg,"%","%%"));
00437         }
00438       }
00439     }
00440   }
00441 }
00442 
00448 static void detectNoDocumentedParams()
00449 {
00450   if (g_memberDef && Config_getBool("WARN_NO_PARAMDOC"))
00451   {
00452     LockingPtr<ArgumentList> al     = g_memberDef->argumentList();
00453     LockingPtr<ArgumentList> declAl = g_memberDef->declArgumentList();
00454     QString returnType   = g_memberDef->typeString();
00455 
00456     if (!g_memberDef->hasDocumentedParams() &&
00457         g_hasParamCommand)
00458     {
00459       //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
00460       g_memberDef->setHasDocumentedParams(TRUE);
00461     }
00462     else if (!g_memberDef->hasDocumentedParams())
00463     {
00464       bool allDoc=TRUE; // no paramater => all parameters are documented
00465       if ( // member has parameters
00466              al!=0 &&       // but the member has a parameter list
00467              al->count()>0  // with at least one parameter (that is not void)
00468          )
00469       {
00470         ArgumentListIterator ali(*al);
00471         Argument *a;
00472 
00473         // see if all parameters have documentation
00474         for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
00475         {
00476           if (!a->name.isEmpty() && a->type!="void")
00477           {
00478             allDoc = !a->docs.isEmpty();
00479           }
00480           //printf("a->type=%s a->name=%s doc=%s\n",
00481           //        a->type.data(),a->name.data(),a->docs.data());
00482         }
00483         if (!allDoc && declAl!=0) // try declaration arguments as well
00484         {
00485           allDoc=TRUE;
00486           ArgumentListIterator ali(*declAl);
00487           Argument *a;
00488           for (ali.toFirst();(a=ali.current()) && allDoc;++ali)
00489           {
00490             if (!a->name.isEmpty() && a->type!="void")
00491             {
00492               allDoc = !a->docs.isEmpty();
00493             }
00494             //printf("a->name=%s doc=%s\n",a->name.data(),a->docs.data());
00495           }
00496         }
00497       }
00498       if (allDoc) 
00499       {
00500         //printf("%s->setHasDocumentedParams(TRUE);\n",g_memberDef->name().data());
00501         g_memberDef->setHasDocumentedParams(TRUE);
00502       }
00503     }
00504     //printf("Member %s hasReturnCommand=%d\n",g_memberDef->name().data(),g_hasReturnCommand);
00505     if (!g_memberDef->hasDocumentedReturnType() && // docs not yet found
00506         g_hasReturnCommand)
00507     {
00508       g_memberDef->setHasDocumentedReturnType(TRUE);
00509     }
00510     else if ( // see if return needs to documented 
00511         g_memberDef->hasDocumentedReturnType() ||
00512         returnType.isEmpty() ||          // empty return type
00513         returnType.find("void")!=-1  ||  // void return type
00514         !g_memberDef->isConstructor() || // a constructor
00515         !g_memberDef->isDestructor()     // or destructor
00516        )
00517     {
00518       g_memberDef->setHasDocumentedReturnType(TRUE);
00519     }
00520        
00521   }
00522 }
00523 
00524 
00525 //---------------------------------------------------------------------------
00526 
00528 static QString stripKnownExtensions(const char *text)
00529 {
00530   QString result=text;
00531   if (result.right(4)==".tex")
00532   {
00533     result=result.left(result.length()-4);
00534   }
00535   else if (result.right(Doxygen::htmlFileExtension.length())==
00536          QString(Doxygen::htmlFileExtension)) 
00537   {
00538     result=result.left(result.length()-Doxygen::htmlFileExtension.length());
00539   }
00540   return result;
00541 }
00542 
00543 
00544 //---------------------------------------------------------------------------
00545 
00547 static bool insidePRE(DocNode *n)
00548 {
00549   while (n)
00550   {
00551     if (n->isPreformatted()) return TRUE;
00552     n=n->parent();
00553   }
00554   return FALSE;
00555 }
00556 
00557 //---------------------------------------------------------------------------
00558 
00560 static bool insideLI(DocNode *n)
00561 {
00562   while (n)
00563   {
00564     if (n->kind()==DocNode::Kind_HtmlListItem) return TRUE;
00565     n=n->parent();
00566   }
00567   return FALSE;
00568 }
00569 
00570 //---------------------------------------------------------------------------
00571 
00573 static bool insideUL(DocNode *n)
00574 {
00575   while (n)
00576   {
00577     if (n->kind()==DocNode::Kind_HtmlList && 
00578         ((DocHtmlList *)n)->type()==DocHtmlList::Unordered) return TRUE;
00579     n=n->parent();
00580   }
00581   return FALSE;
00582 }
00583 
00584 //---------------------------------------------------------------------------
00585 
00587 static bool insideOL(DocNode *n)
00588 {
00589   while (n)
00590   {
00591     if (n->kind()==DocNode::Kind_HtmlList && 
00592         ((DocHtmlList *)n)->type()==DocHtmlList::Ordered) return TRUE;
00593     n=n->parent();
00594   }
00595   return FALSE;
00596 }
00597 
00598 //---------------------------------------------------------------------------
00599 
00600 static bool insideTable(DocNode *n)
00601 {
00602   while (n)
00603   {
00604     if (n->kind()==DocNode::Kind_HtmlTable) return TRUE;
00605     n=n->parent();
00606   }
00607   return FALSE;
00608 }
00609 
00610 //---------------------------------------------------------------------------
00611 
00613 //static bool insideLang(DocNode *n)
00614 //{
00615 //  while (n)
00616 //  {
00617 //    if (n->kind()==DocNode::Kind_Language) return TRUE;
00618 //    n=n->parent();
00619 //  }
00620 //  return FALSE;
00621 //}
00622 
00623 
00624 //---------------------------------------------------------------------------
00625 
00633 static bool findDocsForMemberOrCompound(const char *commandName,
00634                                  QString *pDoc,
00635                                  QString *pBrief,
00636                                  Definition **pDef)
00637 {
00638   //printf("findDocsForMemberOrCompound(%s)\n",commandName);
00639   *pDoc="";
00640   *pBrief="";
00641   *pDef=0;
00642   QString cmdArg=substitute(commandName,"#","::");
00643   int l=cmdArg.length();
00644   if (l==0) return FALSE;
00645 
00646   int funcStart=cmdArg.find('(');
00647   if (funcStart==-1) funcStart=l;
00648 
00649   QString name=removeRedundantWhiteSpace(cmdArg.left(funcStart).latin1());
00650   QString args=cmdArg.right(l-funcStart);
00651 
00652   // try if the link is to a member
00653   MemberDef    *md=0;
00654   ClassDef     *cd=0;
00655   FileDef      *fd=0;
00656   NamespaceDef *nd=0;
00657   GroupDef     *gd=0;
00658   PageDef      *pd=0;
00659   bool found = getDefs(
00660       g_context.find('.')==-1?g_context.latin1():"", // `find('.') is a hack to detect files
00661       name.latin1(),
00662       args.isEmpty()?0:args.latin1(),
00663       md,cd,fd,nd,gd,FALSE,0,TRUE);
00664   //printf("found=%d context=%s name=%s\n",found,g_context.data(),name.data());
00665   if (found && md)
00666   {
00667     *pDoc=md->documentation();
00668     *pBrief=md->briefDescription();
00669     *pDef=md;
00670     return TRUE;
00671   }
00672 
00673 
00674   int scopeOffset=g_context.length();
00675   do // for each scope
00676   {
00677     QString fullName=cmdArg;
00678     if (scopeOffset>0)
00679     {
00680       fullName.prepend(g_context.left(scopeOffset)+"::");
00681     }
00682     //printf("Trying fullName=`%s'\n",fullName.data());
00683 
00684     // try class, namespace, group, page, file reference
00685     cd = Doxygen::classSDict->find(fullName);
00686     if (cd) // class 
00687     {
00688       *pDoc=cd->documentation();
00689       *pBrief=cd->briefDescription();
00690       *pDef=cd;
00691       return TRUE;
00692     }
00693     nd = Doxygen::namespaceSDict->find(fullName);
00694     if (nd) // namespace
00695     {
00696       *pDoc=nd->documentation();
00697       *pBrief=nd->briefDescription();
00698       *pDef=nd;
00699       return TRUE;
00700     }
00701     gd = Doxygen::groupSDict->find(cmdArg);
00702     if (gd) // group
00703     {
00704       *pDoc=gd->documentation();
00705       *pBrief=gd->briefDescription();
00706       *pDef=gd;
00707       return TRUE;
00708     }
00709     pd = Doxygen::pageSDict->find(cmdArg);
00710     if (pd) // page
00711     {
00712       *pDoc=pd->documentation();
00713       *pBrief=pd->briefDescription();
00714       *pDef=pd;
00715       return TRUE;
00716     }
00717     bool ambig;
00718     fd = findFileDef(Doxygen::inputNameDict,cmdArg,ambig);
00719     if (fd && !ambig) // file
00720     {
00721       *pDoc=fd->documentation();
00722       *pBrief=fd->briefDescription();
00723       *pDef=fd;
00724       return TRUE;
00725     }
00726 
00727     if (scopeOffset==0)
00728     {
00729       scopeOffset=-1;
00730     }
00731     else
00732     {
00733       scopeOffset = g_context.findRev("::",scopeOffset-1);
00734       if (scopeOffset==-1) scopeOffset=0;
00735     }
00736   } while (scopeOffset>=0);
00737 
00738   
00739   return FALSE;
00740 }
00741 //---------------------------------------------------------------------------
00742 
00743 // forward declaration
00744 static bool defaultHandleToken(DocNode *parent,int tok, 
00745                                QList<DocNode> &children,bool
00746                                handleWord=TRUE);
00747 
00748 
00749 static int handleStyleArgument(DocNode *parent,QList<DocNode> &children,
00750                                const QString &cmdName)
00751 {
00752   DBG(("handleStyleArgument(%s)\n",cmdName.data()));
00753   QString tokenName = g_token->name;
00754   int tok=doctokenizerYYlex();
00755   if (tok!=TK_WHITESPACE)
00756   {
00757     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
00758         cmdName.data());
00759     return tok;
00760   }
00761   while ((tok=doctokenizerYYlex()) && 
00762           tok!=TK_WHITESPACE && 
00763           tok!=TK_NEWPARA &&
00764           tok!=TK_LISTITEM && 
00765           tok!=TK_ENDLIST
00766         )
00767   {
00768     static QRegExp specialChar("[.,|()\\[\\]:;\\?]");
00769     if (tok==TK_WORD && g_token->name.length()==1 && 
00770         g_token->name.find(specialChar)!=-1)
00771     {
00772       // special character that ends the markup command
00773       return tok;
00774     }
00775     if (!defaultHandleToken(parent,tok,children))
00776     {
00777       switch (tok)
00778       {
00779         case TK_COMMAND: 
00780           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command \\%s as the argument of a \\%s command",
00781                g_token->name.data(),cmdName.data());
00782           break;
00783         case TK_SYMBOL: 
00784           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found while handling command %s",
00785                g_token->name.data(),cmdName.data());
00786           break;
00787         case TK_HTMLTAG:
00788           if (insideLI(parent) && Mappers::htmlTagMapper->map(g_token->name) && g_token->endTag)
00789           { // ignore </li> as the end of a style command
00790             continue; 
00791           }
00792           return tok;
00793           break;
00794         default:
00795           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s while handling command %s",
00796                tokToString(tok),cmdName.data());
00797           break;
00798       }
00799       break;
00800     }
00801   }
00802   DBG(("handleStyleArgument(%s) end tok=%x\n",cmdName.data(),tok));
00803   return (tok==TK_NEWPARA || tok==TK_LISTITEM || tok==TK_ENDLIST
00804          ) ? tok : RetVal_OK; 
00805 }
00806 
00810 static void handleStyleEnter(DocNode *parent,QList<DocNode> &children,
00811           DocStyleChange::Style s,const HtmlAttribList *attribs)
00812 {
00813   DBG(("HandleStyleEnter\n"));
00814   DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,TRUE,attribs);
00815   children.append(sc);
00816   g_styleStack.push(sc);
00817 }
00818 
00822 static void handleStyleLeave(DocNode *parent,QList<DocNode> &children,
00823          DocStyleChange::Style s,const char *tagName)
00824 {
00825   DBG(("HandleStyleLeave\n"));
00826   if (g_styleStack.isEmpty() ||                           // no style change
00827       g_styleStack.top()->style()!=s ||                   // wrong style change
00828       g_styleStack.top()->position()!=g_nodeStack.count() // wrong position
00829      )
00830   {
00831     if (g_styleStack.isEmpty())
00832     {
00833       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag without matching <%s>",
00834           tagName,tagName);
00835     }
00836     else
00837     {
00838       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </%s> tag while expecting </%s>",
00839           tagName,g_styleStack.top()->styleString());
00840     }
00841   }
00842   else // end the section
00843   {
00844     DocStyleChange *sc= new DocStyleChange(parent,g_nodeStack.count(),s,FALSE);
00845     children.append(sc);
00846     g_styleStack.pop();
00847   }
00848 }
00849 
00854 static void handlePendingStyleCommands(DocNode *parent,QList<DocNode> &children)
00855 {
00856   if (!g_styleStack.isEmpty())
00857   {
00858     DocStyleChange *sc = g_styleStack.top();
00859     while (sc && sc->position()>=g_nodeStack.count()) 
00860     { // there are unclosed style modifiers in the paragraph
00861       children.append(new DocStyleChange(parent,g_nodeStack.count(),sc->style(),FALSE));
00862       g_initialStyleStack.push(sc);
00863       g_styleStack.pop();
00864       sc = g_styleStack.top();
00865     }
00866   }
00867 }
00868 
00869 static void handleInitialStyleCommands(DocPara *parent,QList<DocNode> &children)
00870 {
00871   DocStyleChange *sc;
00872   while ((sc=g_initialStyleStack.pop()))
00873   {
00874     handleStyleEnter(parent,children,sc->style(),&sc->attribs());
00875   }
00876 }
00877 
00878 static int handleAHref(DocNode *parent,QList<DocNode> &children,const HtmlAttribList &tagHtmlAttribs)
00879 {
00880   HtmlAttribListIterator li(tagHtmlAttribs);
00881   HtmlAttrib *opt;
00882   int index=0;
00883   int retval = RetVal_OK;
00884   for (li.toFirst();(opt=li.current());++li,++index)
00885   {
00886     if (opt->name=="name") // <a name=label> tag
00887     {
00888       if (!opt->value.isEmpty())
00889       {
00890         DocAnchor *anc = new DocAnchor(parent,opt->value,TRUE);
00891         children.append(anc);
00892         break; // stop looking for other tag attribs
00893       }
00894       else
00895       {
00896         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <a> tag with name option but without value!");
00897       }
00898     }
00899     else if (opt->name=="href") // <a href=url>..</a> tag
00900     {
00901       // copy attributes
00902       HtmlAttribList attrList = tagHtmlAttribs;
00903       // and remove the href attribute
00904       bool result = attrList.remove(index);
00905       ASSERT(result);
00906       DocHRef *href = new DocHRef(parent,attrList,opt->value);
00907       children.append(href);
00908       g_insideHtmlLink=TRUE;
00909       retval = href->parse();
00910       g_insideHtmlLink=FALSE;
00911       break;
00912     }
00913     else // unsupported option for tag a
00914     {
00915     }
00916   }
00917   return retval;
00918 }
00919 
00920 const char *DocStyleChange::styleString() const
00921 {
00922   switch (m_style)
00923   {
00924     case DocStyleChange::Bold:         return "b"; 
00925     case DocStyleChange::Italic:       return "em"; 
00926     case DocStyleChange::Code:         return "code"; 
00927     case DocStyleChange::Center:       return "center"; 
00928     case DocStyleChange::Small:        return "small"; 
00929     case DocStyleChange::Subscript:    return "subscript"; 
00930     case DocStyleChange::Superscript:  return "superscript"; 
00931     case DocStyleChange::Preformatted: return "pre"; 
00932     case DocStyleChange::Div:          return "div";
00933     case DocStyleChange::Span:         return "span";
00934   }
00935   return "<invalid>";
00936 }
00937 
00938 static void handleUnclosedStyleCommands()
00939 {
00940   if (!g_initialStyleStack.isEmpty())
00941   {
00942     DocStyleChange *sc = g_initialStyleStack.top();
00943     g_initialStyleStack.pop();
00944     handleUnclosedStyleCommands();
00945     warn_doc_error(g_fileName,doctokenizerYYlineno,
00946              "Warning: end of comment block while expecting "
00947              "command </%s>",sc->styleString());
00948   }
00949 }
00950 
00951 
00952 static void handleLinkedWord(DocNode *parent,QList<DocNode> &children)
00953 {
00954   Definition *compound=0;
00955   MemberDef  *member=0;
00956   QString name = linkToText(g_token->name,TRUE);
00957   int len = g_token->name.length();
00958   ClassDef *cd=0;
00959   //printf("handleLinkedWord(%s) g_context=%s\n",name.data(),g_context.data());
00960   if (!g_insideHtmlLink && 
00961       (resolveRef(g_context,g_token->name,g_inSeeBlock,&compound,&member)
00962        || (!g_context.isEmpty() &&  // also try with global scope
00963            resolveRef("",g_token->name,g_inSeeBlock,&compound,&member))
00964       )
00965      )
00966   {
00967     //printf("resolveRef %s = %p (linkable?=%d)\n",g_token->name.data(),member,member ? member->isLinkable() : FALSE);
00968     if (member && member->isLinkable()) // member link
00969     {
00970       if (member->isObjCMethod()) 
00971       {
00972         bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
00973         name = member->objCMethodName(localLink,g_inSeeBlock);
00974       }
00975       children.append(new 
00976           DocLinkedWord(parent,name,
00977             member->getReference(),
00978             member->getOutputFileBase(),
00979             member->anchor(),
00980             member->briefDescriptionAsTooltip()
00981                        )
00982                      );
00983     }
00984     else if (compound->isLinkable()) // compound link
00985     {
00986       if (compound->definitionType()==Definition::TypeFile)
00987       {
00988         name=g_token->name;
00989       }
00990       else if (compound->definitionType()==Definition::TypeGroup)
00991       {
00992         name=((GroupDef*)compound)->groupTitle();
00993       }
00994       children.append(new 
00995           DocLinkedWord(parent,name,
00996                         compound->getReference(),
00997                         compound->getOutputFileBase(),
00998                         "",
00999                         compound->briefDescriptionAsTooltip()
01000                        )
01001                      );
01002     }
01003     else if (compound->definitionType()==Definition::TypeFile &&
01004              ((FileDef*)compound)->generateSourceFile()
01005             ) // undocumented file that has source code we can link to
01006     {
01007       children.append(new 
01008           DocLinkedWord(parent,g_token->name,
01009                          compound->getReference(),
01010                          compound->getSourceFileBase(),
01011                          "",
01012                          compound->briefDescriptionAsTooltip()
01013                        )
01014                      );
01015     }
01016     else // not linkable
01017     {
01018       children.append(new DocWord(parent,name));
01019     }
01020   }
01021   else if (!g_insideHtmlLink && len>1 && g_token->name.at(len-1)==':')
01022   {
01023     // special case, where matching Foo: fails to be an Obj-C reference, 
01024     // but Foo itself might be linkable.
01025     g_token->name=g_token->name.left(len-1);
01026     handleLinkedWord(parent,children);
01027     children.append(new DocWord(parent,":"));
01028   }
01029   else if (!g_insideHtmlLink && (cd=getClass(g_token->name+"-p")))
01030   {
01031     // special case 2, where the token name is not a class, but could
01032     // be a Obj-C protocol
01033     children.append(new 
01034         DocLinkedWord(parent,name,
01035           cd->getReference(),
01036           cd->getOutputFileBase(),
01037           "",
01038           cd->briefDescriptionAsTooltip()
01039           ));
01040   }
01041   else // normal non-linkable word
01042   {
01043     if (g_token->name.at(0)=='#')
01044     {
01045       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: explicit link request to '%s' could not be resolved",name.data());
01046     }
01047     children.append(new DocWord(parent,name));
01048   }
01049 }
01050 
01051 /* Helper function that deals with the most common tokens allowed in
01052  * title like sections. 
01053  * @param parent     Parent node, owner of the children list passed as 
01054  *                   the third argument. 
01055  * @param tok        The token to process.
01056  * @param children   The list of child nodes to which the node representing
01057  *                   the token can be added.
01058  * @param handleWord Indicates if word token should be processed
01059  * @retval TRUE      The token was handled.
01060  * @retval FALSE     The token was not handled.
01061  */
01062 static bool defaultHandleToken(DocNode *parent,int tok, QList<DocNode> &children,bool
01063     handleWord)
01064 {
01065   DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
01066   if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL || 
01067       tok==TK_COMMAND || tok==TK_HTMLTAG
01068      )
01069   {
01070     DBG((" name=%s",g_token->name.data()));
01071   }
01072   DBG(("\n"));
01073 reparsetoken:
01074   QString tokenName = g_token->name;
01075   switch (tok)
01076   {
01077     case TK_COMMAND: 
01078       switch (Mappers::cmdMapper->map(tokenName))
01079       {
01080         case CMD_BSLASH:
01081           children.append(new DocSymbol(parent,DocSymbol::BSlash));
01082           break;
01083         case CMD_AT:
01084           children.append(new DocSymbol(parent,DocSymbol::At));
01085           break;
01086         case CMD_LESS:
01087           children.append(new DocSymbol(parent,DocSymbol::Less));
01088           break;
01089         case CMD_GREATER:
01090           children.append(new DocSymbol(parent,DocSymbol::Greater));
01091           break;
01092         case CMD_AMP:
01093           children.append(new DocSymbol(parent,DocSymbol::Amp));
01094           break;
01095         case CMD_DOLLAR:
01096           children.append(new DocSymbol(parent,DocSymbol::Dollar));
01097           break;
01098         case CMD_HASH:
01099           children.append(new DocSymbol(parent,DocSymbol::Hash));
01100           break;
01101         case CMD_PERCENT:
01102           children.append(new DocSymbol(parent,DocSymbol::Percent));
01103           break;
01104         case CMD_EMPHASIS:
01105           {
01106             children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
01107             tok=handleStyleArgument(parent,children,tokenName);
01108             children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
01109             if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
01110             if (tok==TK_NEWPARA) goto handlepara;
01111             else if (tok==TK_WORD || tok==TK_HTMLTAG) 
01112             {
01113               DBG(("CMD_EMPHASIS: reparsing command %s\n",g_token->name.data()));
01114               goto reparsetoken;
01115             }
01116           }
01117           break;
01118         case CMD_BOLD:
01119           {
01120             children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
01121             tok=handleStyleArgument(parent,children,tokenName);
01122             children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
01123             if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
01124             if (tok==TK_NEWPARA) goto handlepara;
01125             else if (tok==TK_WORD || tok==TK_HTMLTAG) 
01126             {
01127               DBG(("CMD_BOLD: reparsing command %s\n",g_token->name.data()));
01128               goto reparsetoken;
01129             }
01130           }
01131           break;
01132         case CMD_CODE:
01133           {
01134             children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,TRUE));
01135             tok=handleStyleArgument(parent,children,tokenName);
01136             children.append(new DocStyleChange(parent,g_nodeStack.count(),DocStyleChange::Code,FALSE));
01137             if (tok!=TK_WORD) children.append(new DocWhiteSpace(parent," "));
01138             if (tok==TK_NEWPARA) goto handlepara;
01139             else if (tok==TK_WORD || tok==TK_HTMLTAG) 
01140             {
01141               DBG(("CMD_CODE: reparsing command %s\n",g_token->name.data()));
01142               goto reparsetoken;
01143             }
01144           }
01145           break;
01146         case CMD_HTMLONLY:
01147           {
01148             doctokenizerYYsetStateHtmlOnly();
01149             tok = doctokenizerYYlex();
01150             children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
01151             if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: htmlonly section ended without end marker");
01152             doctokenizerYYsetStatePara();
01153           }
01154           break;
01155         case CMD_MANONLY:
01156           {
01157             doctokenizerYYsetStateManOnly();
01158             tok = doctokenizerYYlex();
01159             children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
01160             if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: manonly section ended without end marker");
01161             doctokenizerYYsetStatePara();
01162           }
01163           break;
01164         case CMD_LATEXONLY:
01165           {
01166             doctokenizerYYsetStateLatexOnly();
01167             tok = doctokenizerYYlex();
01168             children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
01169             if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: latexonly section ended without end marker",doctokenizerYYlineno);
01170             doctokenizerYYsetStatePara();
01171           }
01172           break;
01173         case CMD_XMLONLY:
01174           {
01175             doctokenizerYYsetStateXmlOnly();
01176             tok = doctokenizerYYlex();
01177             children.append(new DocVerbatim(parent,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
01178             if (tok==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: xmlonly section ended without end marker",doctokenizerYYlineno);
01179             doctokenizerYYsetStatePara();
01180           }
01181           break;
01182         case CMD_FORMULA:
01183           {
01184             DocFormula *form=new DocFormula(parent,g_token->id);
01185             children.append(form);
01186           }
01187           break;
01188         case CMD_ANCHOR:
01189           {
01190             tok=doctokenizerYYlex();
01191             if (tok!=TK_WHITESPACE)
01192             {
01193               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
01194                   tokenName.data());
01195               break;
01196             }
01197             tok=doctokenizerYYlex();
01198             if (tok==0)
01199             {
01200               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
01201                   "argument of command %s",tokenName.data());
01202               break;
01203             }
01204             else if (tok!=TK_WORD && tok!=TK_LNKWORD)
01205             {
01206               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
01207                   tokToString(tok),tokenName.data());
01208               break;
01209             }
01210             DocAnchor *anchor = new DocAnchor(parent,g_token->name,FALSE);
01211             children.append(anchor);
01212           }
01213           break;
01214         case CMD_INTERNALREF:
01215           {
01216             tok=doctokenizerYYlex();
01217             if (tok!=TK_WHITESPACE)
01218             {
01219               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
01220                   tokenName.data());
01221               break;
01222             }
01223             doctokenizerYYsetStateInternalRef();
01224             tok=doctokenizerYYlex(); // get the reference id
01225             DocInternalRef *ref=0;
01226             if (tok!=TK_WORD && tok!=TK_LNKWORD)
01227             {
01228               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
01229                   tokToString(tok),tokenName.data());
01230               doctokenizerYYsetStatePara();
01231               break;
01232             }
01233             ref = new DocInternalRef(parent,g_token->name);
01234             children.append(ref);
01235             ref->parse();
01236             doctokenizerYYsetStatePara();
01237           }
01238           break;
01239         default:
01240           return FALSE;
01241       }
01242       break;
01243     case TK_HTMLTAG:
01244       {
01245         switch (Mappers::htmlTagMapper->map(tokenName))
01246         {
01247           case HTML_DIV:
01248             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <div> tag in heading\n");
01249             break;
01250           case HTML_PRE:
01251             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found <pre> tag in heading\n");
01252             break;
01253           case HTML_BOLD:
01254             if (!g_token->endTag)
01255             {
01256               handleStyleEnter(parent,children,DocStyleChange::Bold,&g_token->attribs);
01257             }
01258             else
01259             {
01260               handleStyleLeave(parent,children,DocStyleChange::Bold,tokenName);
01261             }
01262             break;
01263           case HTML_CODE:
01264           case XML_C:
01265             if (!g_token->endTag)
01266             {
01267               handleStyleEnter(parent,children,DocStyleChange::Code,&g_token->attribs);
01268             }
01269             else
01270             {
01271               handleStyleLeave(parent,children,DocStyleChange::Code,tokenName);
01272             }
01273             break;
01274           case HTML_EMPHASIS:
01275             if (!g_token->endTag)
01276             {
01277               handleStyleEnter(parent,children,DocStyleChange::Italic,&g_token->attribs);
01278             }
01279             else
01280             {
01281               handleStyleLeave(parent,children,DocStyleChange::Italic,tokenName);
01282             }
01283             break;
01284           case HTML_SUB:
01285             if (!g_token->endTag)
01286             {
01287               handleStyleEnter(parent,children,DocStyleChange::Subscript,&g_token->attribs);
01288             }
01289             else
01290             {
01291               handleStyleLeave(parent,children,DocStyleChange::Subscript,tokenName);
01292             }
01293             break;
01294           case HTML_SUP:
01295             if (!g_token->endTag)
01296             {
01297               handleStyleEnter(parent,children,DocStyleChange::Superscript,&g_token->attribs);
01298             }
01299             else
01300             {
01301               handleStyleLeave(parent,children,DocStyleChange::Superscript,tokenName);
01302             }
01303             break;
01304           case HTML_CENTER:
01305             if (!g_token->endTag)
01306             {
01307               handleStyleEnter(parent,children,DocStyleChange::Center,&g_token->attribs);
01308             }
01309             else
01310             {
01311               handleStyleLeave(parent,children,DocStyleChange::Center,tokenName);
01312             }
01313             break;
01314           case HTML_SMALL:
01315             if (!g_token->endTag)
01316             {
01317               handleStyleEnter(parent,children,DocStyleChange::Small,&g_token->attribs);
01318             }
01319             else
01320             {
01321               handleStyleLeave(parent,children,DocStyleChange::Small,tokenName);
01322             }
01323             break;
01324           default:
01325             return FALSE;
01326             break;
01327         }
01328       }
01329       break;
01330     case TK_SYMBOL: 
01331       {
01332         char letter='\0';
01333         DocSymbol::SymType s = DocSymbol::decodeSymbol(tokenName,&letter);
01334         if (s!=DocSymbol::Unknown)
01335         {
01336           children.append(new DocSymbol(parent,s,letter));
01337         }
01338         else
01339         {
01340           return FALSE;
01341         }
01342       }
01343       break;
01344     case TK_WHITESPACE: 
01345     case TK_NEWPARA: 
01346 handlepara:
01347       if (insidePRE(parent) || !children.isEmpty())
01348       {
01349         children.append(new DocWhiteSpace(parent,g_token->chars));
01350       }
01351       break;
01352     case TK_LNKWORD: 
01353       if (handleWord)
01354       {
01355         handleLinkedWord(parent,children);
01356       }
01357       else
01358         return FALSE;
01359       break;
01360     case TK_WORD: 
01361       if (handleWord)
01362       {
01363         children.append(new DocWord(parent,g_token->name));
01364       }
01365       else
01366         return FALSE;
01367       break;
01368     case TK_URL:
01369       if (g_insideHtmlLink)
01370       {
01371         children.append(new DocWord(parent,g_token->name));
01372       }
01373       else
01374       {
01375         children.append(new DocURL(parent,g_token->name,g_token->isEMailAddr));
01376       }
01377       break;
01378     default:
01379       return FALSE;
01380   }
01381   return TRUE;
01382 }
01383 
01384 
01385 //---------------------------------------------------------------------------
01386 
01387 DocSymbol::SymType DocSymbol::decodeSymbol(const QString &symName,char *letter)
01388 {
01389   int l=symName.length();
01390   DBG(("decodeSymbol(%s) l=%d\n",symName.data(),l));
01391   if      (symName=="&copy;")  return DocSymbol::Copy;
01392   else if (symName=="&trade;") return DocSymbol::Tm;
01393   else if (symName=="&tm;")    return DocSymbol::Tm; // alias for &trace;
01394   else if (symName=="&reg;")   return DocSymbol::Reg;
01395   else if (symName=="&lt;")    return DocSymbol::Less;
01396   else if (symName=="&gt;")    return DocSymbol::Greater;
01397   else if (symName=="&amp;")   return DocSymbol::Amp;
01398   else if (symName=="&apos;")  return DocSymbol::Apos;
01399   else if (symName=="&quot;")  return DocSymbol::Quot;
01400   else if (symName=="&lsquo;") return DocSymbol::Lsquo;
01401   else if (symName=="&rsquo;") return DocSymbol::Rsquo;
01402   else if (symName=="&ldquo;") return DocSymbol::Ldquo;
01403   else if (symName=="&rdquo;") return DocSymbol::Rdquo;
01404   else if (symName=="&ndash;") return DocSymbol::Ndash;
01405   else if (symName=="&mdash;") return DocSymbol::Mdash;
01406   else if (symName=="&szlig;") return DocSymbol::Szlig;
01407   else if (symName=="&nbsp;")  return DocSymbol::Nbsp;
01408   else if (l==6 && symName.right(4)=="uml;")  
01409   {
01410     *letter=symName.at(1);
01411     return DocSymbol::Uml;
01412   }
01413   else if (l==8 && symName.right(6)=="acute;")  
01414   {
01415     *letter=symName.at(1);
01416     return DocSymbol::Acute;
01417   }
01418   else if (l==8 && symName.right(6)=="grave;")
01419   {
01420     *letter=symName.at(1);
01421     return DocSymbol::Grave;
01422   }
01423   else if (l==7 && symName.right(5)=="circ;")
01424   {
01425     *letter=symName.at(1);
01426     return DocSymbol::Circ;
01427   }
01428   else if (l==8 && symName.right(6)=="tilde;")
01429   {
01430     *letter=symName.at(1);
01431     return DocSymbol::Tilde;
01432   }
01433   else if (l==8 && symName.right(6)=="cedil;")
01434   {
01435     *letter=symName.at(1);
01436     return DocSymbol::Cedil;
01437   }
01438   else if (l==7 && symName.right(5)=="ring;")
01439   {
01440     *letter=symName.at(1);
01441     return DocSymbol::Ring;
01442   }
01443   else if (l==8 && symName.right(6)=="slash;")
01444   {
01445     *letter=symName.at(1);
01446     return DocSymbol::Slash;
01447   }
01448   return DocSymbol::Unknown;
01449 }
01450 
01451 //---------------------------------------------------------------------------
01452 
01453 static int internalValidatingParseDoc(DocNode *parent,QList<DocNode> &children,
01454                                     const QString &doc)
01455 {
01456   int retval = RetVal_OK;
01457 
01458   if (doc.isEmpty()) return retval;
01459 
01460   doctokenizerYYinit(doc,g_fileName);
01461 
01462   // first parse any number of paragraphs
01463   bool isFirst=TRUE;
01464   DocPara *lastPar=0;
01465   if (!children.isEmpty() && children.last()->kind()==DocNode::Kind_Para)
01466   { // last child item was a paragraph
01467     lastPar = (DocPara*)children.last();
01468     isFirst=FALSE;
01469   }
01470   do
01471   {
01472     DocPara *par = new DocPara(parent);
01473     if (isFirst) { par->markFirst(); isFirst=FALSE; }
01474     retval=par->parse();
01475     if (!par->isEmpty()) 
01476     {
01477       children.append(par);
01478       if (lastPar) lastPar->markLast(FALSE);
01479       lastPar=par;
01480     }
01481     else
01482     {
01483       delete par;
01484     }
01485   } while (retval==TK_NEWPARA);
01486   if (lastPar) lastPar->markLast();
01487 
01488   return retval;
01489 }
01490 
01491 //---------------------------------------------------------------------------
01492 
01493 static void readTextFileByName(const QString &file,QString &text)
01494 {
01495   bool ambig;
01496   FileDef *fd;
01497   if ((fd=findFileDef(Doxygen::exampleNameDict,file,ambig)))
01498   {
01499     text = fileToString(fd->absFilePath(),Config_getBool("FILTER_SOURCE_FILES"));
01500   }
01501   else if (ambig)
01502   {
01503     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included file name %s is ambigious"
01504            "Possible candidates:\n%s",file.data(),
01505            showFileDefMatches(Doxygen::exampleNameDict,file).data()
01506           );
01507   }
01508   else
01509   {
01510     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included file %s is not found. "
01511            "Check your EXAMPLE_PATH",file.data());
01512   }
01513 }
01514 
01515 //---------------------------------------------------------------------------
01516 
01517 DocWord::DocWord(DocNode *parent,const QString &word) : 
01518       m_parent(parent), m_word(word) 
01519 {
01520   //printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
01521   if (!g_searchUrl.isEmpty())
01522   {
01523     Doxygen::searchIndex->addWord(word,FALSE);
01524   }
01525 }
01526 
01527 //---------------------------------------------------------------------------
01528 
01529 DocLinkedWord::DocLinkedWord(DocNode *parent,const QString &word,
01530                   const QString &ref,const QString &file,
01531                   const QString &anchor,const QString &tooltip) : 
01532       m_parent(parent), m_word(word), m_ref(ref), 
01533       m_file(file), m_relPath(g_relPath), m_anchor(anchor),
01534       m_tooltip(tooltip)
01535 {
01536   //printf("new word %s url=%s\n",word.data(),g_searchUrl.data());
01537   if (!g_searchUrl.isEmpty())
01538   {
01539     Doxygen::searchIndex->addWord(word,FALSE);
01540   }
01541 }
01542 
01543 //---------------------------------------------------------------------------
01544 
01545 DocAnchor::DocAnchor(DocNode *parent,const QString &id,bool newAnchor) 
01546   : m_parent(parent)
01547 {
01548   if (id.isEmpty())
01549   {
01550     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Empty anchor label");
01551   }
01552   if (newAnchor) // found <a name="label">
01553   {
01554     m_anchor = id;
01555   }
01556   else // found \anchor label
01557   {
01558     SectionInfo *sec = Doxygen::sectionDict[id];
01559     if (sec)
01560     {
01561       //printf("Found anchor %s\n",id.data());
01562       m_file   = sec->fileName;
01563       m_anchor = sec->label;
01564       if (g_sectionDict && g_sectionDict->find(id)==0)
01565       {
01566         //printf("Inserting in dictionary!\n");
01567         g_sectionDict->insert(id,sec);
01568       }
01569     }
01570     else
01571     {
01572       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid anchor id `%s'",id.data());
01573       m_anchor = "invalid";
01574       m_file = "invalid";
01575     }
01576   }
01577 }
01578 
01579 //---------------------------------------------------------------------------
01580 
01581 DocVerbatim::DocVerbatim(DocNode *parent,const QString &context,
01582     const QString &text, Type t,bool isExample,
01583     const QString &exampleFile) 
01584   : m_parent(parent), m_context(context), m_text(text), m_type(t),
01585     m_isExample(isExample), m_exampleFile(exampleFile), m_relPath(g_relPath) 
01586 {
01587 }
01588 
01589 
01590 //---------------------------------------------------------------------------
01591 
01592 void DocInclude::parse()
01593 {
01594   DBG(("DocInclude::parse(file=%s,text=%s)\n",m_file.data(),m_text.data()));
01595   switch(m_type)
01596   {
01597     case IncWithLines:
01598       // fall through
01599     case Include:
01600       // fall through
01601     case DontInclude:
01602       readTextFileByName(m_file,m_text);
01603       g_includeFileText   = m_text;
01604       g_includeFileOffset = 0;
01605       g_includeFileLength = m_text.length();
01606       //printf("g_includeFile=<<%s>>\n",g_includeFileText.data());
01607       break;
01608     case VerbInclude: 
01609       // fall through
01610     case HtmlInclude:
01611       readTextFileByName(m_file,m_text);
01612       break;
01613   }
01614 }
01615 
01616 //---------------------------------------------------------------------------
01617 
01618 void DocIncOperator::parse()
01619 {
01620   const char *p = g_includeFileText;
01621   uint l = g_includeFileLength;
01622   uint o = g_includeFileOffset;
01623   DBG(("DocIncOperator::parse() text=%s off=%d len=%d\n",p,o,l));
01624   uint so = o,bo;
01625   bool nonEmpty = FALSE;
01626   switch(type())
01627   {
01628     case Line:
01629       while (o<l)
01630       {
01631         char c = p[o];
01632         if (c=='\n') 
01633         {
01634           if (nonEmpty) break; // we have a pattern to match
01635           so=o+1; // no pattern, skip empty line
01636         }
01637         else if (!isspace((uchar)c)) // no white space char
01638         {
01639           nonEmpty=TRUE;
01640         }
01641         o++;
01642       }
01643       if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
01644       {
01645         m_text = g_includeFileText.mid(so,o-so);
01646         DBG(("DocIncOperator::parse() Line: %s\n",m_text.data()));
01647       }
01648       g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
01649       break;
01650     case SkipLine:
01651       while (o<l)
01652       {
01653         so=o;
01654         while (o<l)
01655         {
01656           char c = p[o];
01657           if (c=='\n')
01658           {
01659             if (nonEmpty) break; // we have a pattern to match
01660             so=o+1; // no pattern, skip empty line
01661           }
01662           else if (!isspace((uchar)c)) // no white space char
01663           {
01664             nonEmpty=TRUE;
01665           }
01666           o++;
01667         }
01668         if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
01669         {
01670           m_text = g_includeFileText.mid(so,o-so);
01671           DBG(("DocIncOperator::parse() SkipLine: %s\n",m_text.data()));
01672           break;
01673         }
01674         o++; // skip new line
01675       }
01676       g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
01677       break;
01678     case Skip:
01679       while (o<l)
01680       {
01681         so=o;
01682         while (o<l)
01683         {
01684           char c = p[o];
01685           if (c=='\n')
01686           {
01687             if (nonEmpty) break; // we have a pattern to match
01688             so=o+1; // no pattern, skip empty line
01689           }
01690           else if (!isspace((uchar)c)) // no white space char
01691           {
01692             nonEmpty=TRUE;
01693           }
01694           o++;
01695         }
01696         if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
01697         {
01698           break;
01699         }
01700         o++; // skip new line
01701       }
01702       g_includeFileOffset = so; // set pointer to start of new line
01703       break;
01704     case Until:
01705       bo=o;
01706       while (o<l)
01707       {
01708         so=o;
01709         while (o<l)
01710         {
01711           char c = p[o];
01712           if (c=='\n')
01713           {
01714             if (nonEmpty) break; // we have a pattern to match
01715             so=o+1; // no pattern, skip empty line
01716           }
01717           else if (!isspace((uchar)c)) // no white space char
01718           {
01719             nonEmpty=TRUE;
01720           }
01721           o++;
01722         }
01723         if (g_includeFileText.mid(so,o-so).find(m_pattern)!=-1)
01724         {
01725           m_text = g_includeFileText.mid(bo,o-bo);
01726           DBG(("DocIncOperator::parse() Until: %s\n",m_text.data()));
01727           break;
01728         }
01729         o++; // skip new line
01730       }
01731       g_includeFileOffset = QMIN(l,o+1); // set pointer to start of new line
01732       break;
01733   }
01734 }
01735 
01736 //---------------------------------------------------------------------------
01737 
01738 void DocCopy::parse()
01739 {
01740   QString doc,brief;
01741   Definition *def;
01742   if (findDocsForMemberOrCompound(m_link,&doc,&brief,&def))
01743   {
01744     if (g_copyStack.findRef(def)==-1) // definition not parsed earlier
01745     {
01746       docParserPushContext();
01747       if (def->definitionType()==Definition::TypeMember && def->getOuterScope())
01748       {
01749         g_context=def->getOuterScope()->name();
01750       }
01751       else
01752       {
01753         g_context=def->name();
01754       }
01755       g_styleStack.clear();
01756       g_nodeStack.clear();
01757       g_copyStack.append(def);
01758       // make sure the descriptions end with a newline, so the parser will correctly
01759       // handle them in all cases.
01760       //printf("doc='%s'\n",doc.data());
01761       //printf("brief='%s'\n",brief.data());
01762       brief+='\n';
01763       doc+='\n';
01764       internalValidatingParseDoc(this,m_children,brief);
01765       internalValidatingParseDoc(this,m_children,doc);
01766       g_copyStack.remove(def);
01767       ASSERT(g_styleStack.isEmpty());
01768       ASSERT(g_nodeStack.isEmpty());
01769       docParserPopContext(TRUE);
01770     }
01771     else // oops, recursion
01772     {
01773       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: recursive call chain of \\copydoc commands detected at %d\n",
01774           doctokenizerYYlineno);
01775     }
01776   }
01777   else
01778   {
01779     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: target %s of \\copydoc command not found",
01780         m_link.data());
01781   }
01782 }
01783 
01784 //---------------------------------------------------------------------------
01785 
01786 DocXRefItem::DocXRefItem(DocNode *parent,int id,const char *key) : 
01787    m_parent(parent), m_id(id), m_key(key), m_relPath(g_relPath)
01788 {
01789 }
01790 
01791 bool DocXRefItem::parse()
01792 {
01793   QString listName;
01794   RefList *refList = Doxygen::xrefLists->find(m_key); 
01795   if (refList && 
01796       (
01797        // either not a built-in list or the list is enabled
01798        (m_key!="todo"       || Config_getBool("GENERATE_TODOLIST")) && 
01799        (m_key!="test"       || Config_getBool("GENERATE_TESTLIST")) && 
01800        (m_key!="bug"        || Config_getBool("GENERATE_BUGLIST"))  && 
01801        (m_key!="deprecated" || Config_getBool("GENERATE_DEPRECATEDLIST"))
01802       ) 
01803      )
01804   {
01805     RefItem *item = refList->getRefItem(m_id);
01806     ASSERT(item!=0);
01807     if (item)
01808     {
01809       if (g_memberDef && g_memberDef->name().at(0)=='@')
01810       {
01811         m_file   = "@";  // can't cross reference anonymous enum
01812         m_anchor = "@";
01813       }
01814       else
01815       {
01816         m_file   = refList->listName();
01817         m_anchor = item->listAnchor;
01818       }
01819       m_title  = refList->sectionTitle();
01820       //printf("DocXRefItem: file=%s anchor=%s title=%s\n",
01821       //    m_file.data(),m_anchor.data(),m_title.data());
01822 
01823       if (!item->text.isEmpty())
01824       {
01825         docParserPushContext();
01826         internalValidatingParseDoc(this,m_children,item->text);
01827         docParserPopContext();
01828       }
01829     }
01830     return TRUE;
01831   }
01832   return FALSE;
01833 }
01834 
01835 //---------------------------------------------------------------------------
01836 
01837 DocFormula::DocFormula(DocNode *parent,int id) :
01838       m_parent(parent), m_relPath(g_relPath)
01839 {
01840   QString formCmd;
01841   formCmd.sprintf("\\form#%d",id);
01842   Formula *formula=Doxygen::formulaNameDict[formCmd];
01843   if (formula)
01844   {
01845     m_id = formula->getId();
01846     m_name.sprintf("form_%d",m_id);
01847     m_text = formula->getFormulaText();
01848   }
01849 }
01850 
01851 //---------------------------------------------------------------------------
01852 
01853 //int DocLanguage::parse()
01854 //{
01855 //  int retval;
01856 //  DBG(("DocLanguage::parse() start\n"));
01857 //  g_nodeStack.push(this);
01858 //
01859 //  // parse one or more paragraphs
01860 //  bool isFirst=TRUE;
01861 //  DocPara *par=0;
01862 //  do
01863 //  {
01864 //    par = new DocPara(this);
01865 //    if (isFirst) { par->markFirst(); isFirst=FALSE; }
01866 //    m_children.append(par);
01867 //    retval=par->parse();
01868 //  }
01869 //  while (retval==TK_NEWPARA);
01870 //  if (par) par->markLast();
01871 //
01872 //  DBG(("DocLanguage::parse() end\n"));
01873 //  DocNode *n = g_nodeStack.pop();
01874 //  ASSERT(n==this);
01875 //  return retval;
01876 //}
01877 
01878 //---------------------------------------------------------------------------
01879 
01880 void DocSecRefItem::parse()
01881 {
01882   DBG(("DocSecRefItem::parse() start\n"));
01883   g_nodeStack.push(this);
01884 
01885   doctokenizerYYsetStateTitle();
01886   int tok;
01887   while ((tok=doctokenizerYYlex()))
01888   {
01889     if (!defaultHandleToken(this,tok,m_children))
01890     {
01891       switch (tok)
01892       {
01893         case TK_COMMAND: 
01894           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\refitem",
01895                g_token->name.data());
01896           break;
01897         case TK_SYMBOL: 
01898           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
01899                g_token->name.data());
01900           break;
01901         default:
01902           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
01903                tokToString(tok));
01904           break;
01905       }
01906     }
01907   }
01908   doctokenizerYYsetStatePara();
01909   handlePendingStyleCommands(this,m_children);
01910 
01911   SectionInfo *sec=0;
01912   if (!m_target.isEmpty())
01913   {
01914     sec=Doxygen::sectionDict[m_target];
01915     if (sec)
01916     {
01917       m_file   = sec->fileName;
01918       m_anchor = sec->label;
01919       if (g_sectionDict && g_sectionDict->find(m_target)==0)
01920       {
01921         g_sectionDict->insert(m_target,sec);
01922       }
01923     }
01924     else
01925     {
01926       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning reference to unknown section %s",
01927           m_target.data());
01928     }
01929   } 
01930   else
01931   {
01932     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning reference to empty target");
01933   }
01934   
01935   DBG(("DocSecRefItem::parse() end\n"));
01936   DocNode *n = g_nodeStack.pop();
01937   ASSERT(n==this);
01938 }
01939 
01940 //---------------------------------------------------------------------------
01941 
01942 void DocSecRefList::parse()
01943 {
01944   DBG(("DocSecRefList::parse() start\n"));
01945   g_nodeStack.push(this);
01946 
01947   int tok=doctokenizerYYlex();
01948   // skip white space
01949   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
01950   // handle items
01951   while (tok)
01952   {
01953     if (tok==TK_COMMAND)
01954     {
01955       switch (Mappers::cmdMapper->map(g_token->name))
01956       {
01957         case CMD_SECREFITEM:
01958           {
01959             int tok=doctokenizerYYlex();
01960             if (tok!=TK_WHITESPACE)
01961             {
01962               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after \\refitem command");
01963               break;
01964             }
01965             tok=doctokenizerYYlex();
01966             if (tok!=TK_WORD && tok!=TK_LNKWORD)
01967             {
01968               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of \\refitem",
01969                   tokToString(tok));
01970               break;
01971             }
01972 
01973             DocSecRefItem *item = new DocSecRefItem(this,g_token->name);
01974             m_children.append(item);
01975             item->parse();
01976           }
01977           break;
01978         case CMD_ENDSECREFLIST:
01979           goto endsecreflist;
01980         default:
01981           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\secreflist",
01982               g_token->name.data());
01983           goto endsecreflist;
01984       }
01985     }
01986     else if (tok==TK_WHITESPACE)
01987     {
01988       // ignore whitespace
01989     }
01990     else
01991     {
01992       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s inside section reference list",
01993           tokToString(tok));
01994       goto endsecreflist;
01995     }
01996     tok=doctokenizerYYlex();
01997   }
01998 
01999 endsecreflist:
02000   DBG(("DocSecRefList::parse() end\n"));
02001   DocNode *n = g_nodeStack.pop();
02002   ASSERT(n==this);
02003 }
02004 
02005 //---------------------------------------------------------------------------
02006 
02007 DocInternalRef::DocInternalRef(DocNode *parent,const QString &ref) 
02008   : m_parent(parent), m_relPath(g_relPath)
02009 {
02010   int i=ref.find('#');
02011   if (i!=-1)
02012   {
02013     m_anchor = ref.right(ref.length()-i-1);
02014     m_file   = ref.left(i);
02015   }
02016   else
02017   {
02018     m_file = ref;
02019   }
02020 }
02021 
02022 void DocInternalRef::parse()
02023 {
02024   g_nodeStack.push(this);
02025   DBG(("DocInternalRef::parse() start\n"));
02026 
02027   int tok;
02028   while ((tok=doctokenizerYYlex()))
02029   {
02030     if (!defaultHandleToken(this,tok,m_children))
02031     {
02032       switch (tok)
02033       {
02034         case TK_COMMAND: 
02035           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\ref",
02036                g_token->name.data());
02037           break;
02038         case TK_SYMBOL: 
02039           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02040                g_token->name.data());
02041           break;
02042         default:
02043           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02044                 tokToString(tok));
02045           break;
02046       }
02047     }
02048   }
02049 
02050   handlePendingStyleCommands(this,m_children);
02051   DBG(("DocInternalRef::parse() end\n"));
02052   DocNode *n=g_nodeStack.pop();
02053   ASSERT(n==this);
02054 }
02055 
02056 //---------------------------------------------------------------------------
02057 
02058 DocRef::DocRef(DocNode *parent,const QString &target,const QString &context) : 
02059    m_parent(parent), m_refToSection(FALSE), m_refToAnchor(FALSE)
02060 {
02061   Definition  *compound = 0;
02062   QCString     anchor;
02063   ASSERT(!target.isEmpty());
02064   m_relPath = g_relPath;
02065   SectionInfo *sec = Doxygen::sectionDict[target];
02066   if (sec) // ref to section or anchor
02067   {
02068     m_text         = sec->title;
02069     if (m_text.isEmpty()) m_text = sec->label;
02070 
02071     m_ref          = sec->ref;
02072     m_file         = stripKnownExtensions(sec->fileName);
02073     if (sec->type!=SectionInfo::Page) m_anchor = sec->label;
02074     m_refToAnchor  = sec->type==SectionInfo::Anchor;
02075     m_refToSection = sec->type!=SectionInfo::Anchor;
02076     //printf("m_text=%s,m_ref=%s,m_file=%s,m_refToAnchor=%d\n",
02077     //    m_text.data(),m_ref.data(),m_file.data(),m_refToAnchor);
02078     return;
02079   }
02080   else if (resolveLink(context,target,TRUE,&compound,anchor))
02081   {
02082     bool isFile = compound ? 
02083                  (compound->definitionType()==Definition::TypeFile ? TRUE : FALSE) : 
02084                  FALSE;
02085     m_text = linkToText(target,isFile);
02086     m_anchor = anchor;
02087     if (compound && compound->isLinkable()) // ref to compound
02088     {
02089       if (anchor.isEmpty() &&                                  /* compound link */
02090           compound->definitionType()==Definition::TypeGroup && /* is group */
02091           ((GroupDef *)compound)->groupTitle()                 /* with title */
02092          )
02093       {
02094         m_text=((GroupDef *)compound)->groupTitle(); // use group's title as link
02095       }
02096       else if (compound->definitionType()==Definition::TypeMember &&
02097           ((MemberDef*)compound)->isObjCMethod())
02098       {
02099         // Objective C Method
02100         MemberDef *member = (MemberDef*)compound;
02101         bool localLink = g_memberDef ? member->getClassDef()==g_memberDef->getClassDef() : FALSE;
02102         m_text = member->objCMethodName(localLink,g_inSeeBlock);
02103       }
02104 
02105       m_file = compound->getOutputFileBase();
02106       m_ref  = compound->getReference();
02107       return;
02108     }
02109     else if (compound->definitionType()==Definition::TypeFile && 
02110              ((FileDef*)compound)->generateSourceFile()
02111             ) // undocumented file that has source code we can link to
02112     {
02113       m_file = compound->getSourceFileBase();
02114       m_ref  = compound->getReference();
02115       return;
02116     }
02117   }
02118   m_text = linkToText(target,FALSE);
02119   warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unable to resolve reference to `%s' for \\ref command",
02120            target.data()); 
02121 }
02122 
02123 static void flattenParagraphs(QList<DocNode> &children)
02124 {
02125   QListIterator<DocNode> li(children);
02126   QList<DocNode> newChildren;
02127   DocNode *dn;
02128   for (li.toFirst();(dn=li.current());++li)
02129   {
02130     if (dn->kind()==DocNode::Kind_Para)
02131     {
02132       DocPara *para = (DocPara*)dn;
02133       QList<DocNode> &paraChildren = para->children();
02134       paraChildren.setAutoDelete(FALSE); // unlink children from paragraph node
02135       QListIterator<DocNode> li2(paraChildren);
02136       DocNode *dn2;
02137       for (li2.toFirst();(dn2=li2.current());++li2)
02138       {
02139         newChildren.append(dn2); // add them to new node
02140       }
02141     }
02142   }
02143   children.clear();
02144   QListIterator<DocNode> li3(newChildren);
02145   for (li3.toFirst();(dn=li3.current());++li3)
02146   {
02147     children.append(dn);
02148   }
02149 }
02150 
02151 void DocRef::parse()
02152 {
02153   g_nodeStack.push(this);
02154   DBG(("DocRef::parse() start\n"));
02155 
02156   int tok;
02157   while ((tok=doctokenizerYYlex()))
02158   {
02159     if (!defaultHandleToken(this,tok,m_children))
02160     {
02161       switch (tok)
02162       {
02163         case TK_COMMAND: 
02164           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\ref",
02165                g_token->name.data());
02166           break;
02167         case TK_SYMBOL: 
02168           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02169                g_token->name.data());
02170           break;
02171         case TK_HTMLTAG:
02172           break;
02173         default:
02174           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02175                 tokToString(tok));
02176           break;
02177       }
02178     }
02179   }
02180 
02181   if (m_children.isEmpty() && !m_text.isEmpty())
02182   {
02183     g_insideHtmlLink=TRUE;
02184     docParserPushContext();
02185     internalValidatingParseDoc(this,m_children,m_text);
02186     docParserPopContext();
02187     g_insideHtmlLink=FALSE;
02188     flattenParagraphs(m_children);
02189   }
02190 
02191   handlePendingStyleCommands(this,m_children);
02192   
02193   DocNode *n=g_nodeStack.pop();
02194   ASSERT(n==this);
02195 }
02196 
02197 //---------------------------------------------------------------------------
02198 
02199 DocLink::DocLink(DocNode *parent,const QString &target) : 
02200       m_parent(parent)
02201 {
02202   Definition *compound;
02203   //PageInfo *page;
02204   QCString anchor;
02205   m_refText = target;
02206   m_relPath = g_relPath;
02207   if (!m_refText.isEmpty() && m_refText.at(0)=='#')
02208   {
02209     m_refText = m_refText.right(m_refText.length()-1);
02210   }
02211   if (resolveLink(g_context,stripKnownExtensions(target),g_inSeeBlock,
02212                   &compound,anchor))
02213   {
02214     m_anchor = anchor;
02215     if (compound && compound->isLinkable())
02216     {
02217       m_file = compound->getOutputFileBase();
02218       m_ref  = compound->getReference();
02219     }
02220     else if (compound->definitionType()==Definition::TypeFile && 
02221              ((FileDef*)compound)->generateSourceFile()
02222             ) // undocumented file that has source code we can link to
02223     {
02224       m_file = compound->getSourceFileBase();
02225       m_ref  = compound->getReference();
02226     }
02227     return;
02228   }
02229 
02230   // bogus link target
02231   warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unable to resolve link to `%s' for \\link command",
02232          target.data()); 
02233 }
02234 
02235 
02236 QString DocLink::parse(bool isJavaLink,bool isXmlLink)
02237 {
02238   QString result;
02239   g_nodeStack.push(this);
02240   DBG(("DocLink::parse() start\n"));
02241 
02242   int tok;
02243   while ((tok=doctokenizerYYlex()))
02244   {
02245     if (!defaultHandleToken(this,tok,m_children,FALSE))
02246     {
02247       switch (tok)
02248       {
02249         case TK_COMMAND: 
02250           switch (Mappers::cmdMapper->map(g_token->name))
02251           {
02252             case CMD_ENDLINK:
02253               if (isJavaLink)
02254               {
02255                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: {@link.. ended with @endlink command");
02256               }
02257               goto endlink;
02258             default:
02259               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\link",
02260                   g_token->name.data());
02261               break;
02262           }
02263           break;
02264         case TK_SYMBOL: 
02265           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02266               g_token->name.data());
02267           break;
02268         case TK_HTMLTAG:
02269           if (g_token->name!="see" || !isXmlLink)
02270           {
02271             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected xml/html command %s found",
02272                 g_token->name.data());
02273           }
02274           goto endlink;
02275         case TK_LNKWORD: 
02276         case TK_WORD: 
02277           if (isJavaLink) // special case to detect closing }
02278           {
02279             QString w = g_token->name;
02280             int p;
02281             if (w=="}")
02282             {
02283               goto endlink;
02284             }
02285             else if ((p=w.find('}'))!=-1)
02286             {
02287               uint l=w.length();
02288               m_children.append(new DocWord(this,w.left(p)));
02289               if ((uint)p<l-1) // something left after the } (for instance a .)
02290               {
02291                 result=w.right(l-p-1);
02292               }
02293               goto endlink;
02294             }
02295           }
02296           m_children.append(new DocWord(this,g_token->name));
02297           break;
02298         default:
02299           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02300              tokToString(tok));
02301         break;
02302       }
02303     }
02304   }
02305   if (tok==0)
02306   {
02307     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
02308            " link command\n"); 
02309   }
02310 endlink:
02311 
02312   if (m_children.isEmpty()) // no link text
02313   {
02314     m_children.append(new DocWord(this,m_refText));
02315   }
02316 
02317   handlePendingStyleCommands(this,m_children);
02318   DBG(("DocLink::parse() end\n"));
02319   DocNode *n=g_nodeStack.pop();
02320   ASSERT(n==this);
02321   return result;
02322 }
02323 
02324 
02325 //---------------------------------------------------------------------------
02326 
02327 DocDotFile::DocDotFile(DocNode *parent,const QString &name,const QString &context) : 
02328       m_parent(parent), m_name(name), m_relPath(g_relPath), m_context(context)
02329 {
02330 }
02331 
02332 void DocDotFile::parse()
02333 {
02334   g_nodeStack.push(this);
02335   DBG(("DocDotFile::parse() start\n"));
02336 
02337   doctokenizerYYsetStateTitle();
02338   int tok;
02339   while ((tok=doctokenizerYYlex()))
02340   {
02341     if (!defaultHandleToken(this,tok,m_children))
02342     {
02343       switch (tok)
02344       {
02345         case TK_COMMAND: 
02346           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\dotfile",
02347                g_token->name.data());
02348           break;
02349         case TK_SYMBOL: 
02350           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02351                g_token->name.data());
02352           break;
02353         default:
02354           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02355                 tokToString(tok));
02356           break;
02357       }
02358     }
02359   }
02360   tok=doctokenizerYYlex();
02361   while (tok==TK_WORD) // there are values following the title
02362   {
02363     if (g_token->name=="width") 
02364     {
02365       m_width=g_token->chars;
02366     }
02367     else if (g_token->name=="height") 
02368     {
02369       m_height=g_token->chars;
02370     }
02371     else 
02372     {
02373       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unknown option %s after image title",
02374             g_token->name.data());
02375     }
02376     tok=doctokenizerYYlex();
02377   }
02378   ASSERT(tok==0);
02379   doctokenizerYYsetStatePara();
02380   handlePendingStyleCommands(this,m_children);
02381 
02382   bool ambig;
02383   FileDef *fd = findFileDef(Doxygen::dotFileNameDict,m_name,ambig);
02384   if (fd)
02385   {
02386     m_file = fd->absFilePath();
02387   }
02388   else if (ambig)
02389   {
02390     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included dot file name %s is ambigious.\n"
02391            "Possible candidates:\n%s",m_name.data(),
02392            showFileDefMatches(Doxygen::exampleNameDict,m_name).data()
02393           );
02394   }
02395   else
02396   {
02397     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: included dot file %s is not found "
02398            "in any of the paths specified via DOTFILE_DIRS!",m_name.data());
02399   }
02400 
02401   DBG(("DocDotFile::parse() end\n"));
02402   DocNode *n=g_nodeStack.pop();
02403   ASSERT(n==this);
02404 }
02405 
02406 
02407 //---------------------------------------------------------------------------
02408 
02409 DocImage::DocImage(DocNode *parent,const HtmlAttribList &attribs,const QString &name,Type t) : 
02410       m_parent(parent), m_attribs(attribs), m_name(name), 
02411       m_type(t), m_relPath(g_relPath)
02412 {
02413 }
02414 
02415 void DocImage::parse()
02416 {
02417   g_nodeStack.push(this);
02418   DBG(("DocImage::parse() start\n"));
02419 
02420   // parse title
02421   doctokenizerYYsetStateTitle();
02422   int tok;
02423   while ((tok=doctokenizerYYlex()))
02424   {
02425     if (tok==TK_WORD && (g_token->name=="width=" || g_token->name=="height="))
02426     {
02427       // special case: no title, but we do have a size indicator
02428       doctokenizerYYsetStateTitleAttrValue();
02429       // strip =
02430       g_token->name=g_token->name.left(g_token->name.length()-1);
02431       break;
02432     } 
02433     if (!defaultHandleToken(this,tok,m_children))
02434     {
02435       switch (tok)
02436       {
02437         case TK_COMMAND: 
02438           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a \\image",
02439               g_token->name.data());
02440           break;
02441         case TK_SYMBOL: 
02442           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02443               g_token->name.data());
02444           break;
02445         default:
02446           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02447               tokToString(tok));
02448           break;
02449       }
02450     }
02451   }
02452   // parse size attributes
02453   tok=doctokenizerYYlex();
02454   while (tok==TK_WORD) // there are values following the title
02455   {
02456     if (g_token->name=="width") 
02457     {
02458       m_width=g_token->chars;
02459     }
02460     else if (g_token->name=="height") 
02461     {
02462       m_height=g_token->chars;
02463     }
02464     else 
02465     {
02466       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unknown option %s after image title",
02467           g_token->name.data());
02468     }
02469     tok=doctokenizerYYlex();
02470   }
02471   doctokenizerYYsetStatePara();
02472 
02473   handlePendingStyleCommands(this,m_children);
02474   DBG(("DocImage::parse() end\n"));
02475   DocNode *n=g_nodeStack.pop();
02476   ASSERT(n==this);
02477 }
02478 
02479 
02480 //---------------------------------------------------------------------------
02481 
02482 int DocHtmlHeader::parse()
02483 {
02484   int retval=RetVal_OK;
02485   g_nodeStack.push(this);
02486   DBG(("DocHtmlHeader::parse() start\n"));
02487 
02488   int tok;
02489   while ((tok=doctokenizerYYlex()))
02490   {
02491     if (!defaultHandleToken(this,tok,m_children))
02492     {
02493       switch (tok)
02494       {
02495         case TK_COMMAND: 
02496           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <h%d> tag",
02497                g_token->name.data(),m_level);
02498           break;
02499         case TK_HTMLTAG:
02500           {
02501             int tagId=Mappers::htmlTagMapper->map(g_token->name);
02502             if (tagId==HTML_H1 && g_token->endTag) // found </h1> tag
02503             {
02504               if (m_level!=1)
02505               {
02506                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h1>",
02507                     m_level); 
02508               }
02509               goto endheader;
02510             }
02511             else if (tagId==HTML_H2 && g_token->endTag) // found </h2> tag
02512             {
02513               if (m_level!=2)
02514               {
02515                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h2>",
02516                     m_level); 
02517               }
02518               goto endheader;
02519             }
02520             else if (tagId==HTML_H3 && g_token->endTag) // found </h3> tag
02521             {
02522               if (m_level!=3)
02523               {
02524                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h3>",
02525                     m_level); 
02526               }
02527               goto endheader;
02528             }
02529             else if (tagId==HTML_H4 && g_token->endTag) // found </h4> tag
02530             {
02531               if (m_level!=4)
02532               {
02533                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h4>",
02534                     m_level); 
02535               }
02536               goto endheader;
02537             }
02538             else if (tagId==HTML_H5 && g_token->endTag) // found </h5> tag
02539             {
02540               if (m_level!=5)
02541               {
02542                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h5>",
02543                     m_level); 
02544               }
02545               goto endheader;
02546             }
02547             else if (tagId==HTML_H6 && g_token->endTag) // found </h6> tag
02548             {
02549               if (m_level!=6)
02550               {
02551                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: <h%d> ended with </h6>",
02552                     m_level); 
02553               }
02554               goto endheader;
02555             }
02556             else if (tagId==HTML_A)
02557             {
02558               if (!g_token->endTag)
02559               {
02560                 handleAHref(this,m_children,g_token->attribs);
02561               }
02562             }
02563             else if (tagId==HTML_BR)
02564             {
02565               DocLineBreak *lb = new DocLineBreak(this);
02566               m_children.append(lb);
02567             }
02568             else
02569             {
02570               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <h%d> context",
02571                   g_token->endTag?"/":"",g_token->name.data(),m_level);
02572             }
02573             
02574           }
02575           break;
02576         case TK_SYMBOL: 
02577           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02578                g_token->name.data());
02579           break;
02580         default:
02581           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02582                 tokToString(tok));
02583           break;
02584       }
02585     }
02586   }
02587   if (tok==0)
02588   {
02589     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
02590            " <h%d> tag\n",m_level); 
02591   }
02592 endheader:
02593   handlePendingStyleCommands(this,m_children);
02594   DBG(("DocHtmlHeader::parse() end\n"));
02595   DocNode *n=g_nodeStack.pop();
02596   ASSERT(n==this);
02597   return retval;
02598 }
02599 
02600 //---------------------------------------------------------------------------
02601 
02602 int DocHRef::parse()
02603 {
02604   int retval=RetVal_OK;
02605   g_nodeStack.push(this);
02606   DBG(("DocHRef::parse() start\n"));
02607 
02608   int tok;
02609   while ((tok=doctokenizerYYlex()))
02610   {
02611     if (!defaultHandleToken(this,tok,m_children))
02612     {
02613       switch (tok)
02614       {
02615         case TK_COMMAND: 
02616           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <a>..</a> block",
02617                g_token->name.data());
02618           break;
02619         case TK_SYMBOL: 
02620           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02621                g_token->name.data());
02622           break;
02623         case TK_HTMLTAG:
02624           {
02625             int tagId=Mappers::htmlTagMapper->map(g_token->name);
02626             if (tagId==HTML_A && g_token->endTag) // found </a> tag
02627             {
02628               goto endhref;
02629             }
02630             else
02631             {
02632               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <a href=...> context",
02633                   g_token->endTag?"/":"",g_token->name.data(),doctokenizerYYlineno);
02634             }
02635           }
02636           break;
02637         default:
02638           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02639                 tokToString(tok),doctokenizerYYlineno);
02640           break;
02641       }
02642     }
02643   }
02644   if (tok==0)
02645   {
02646     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
02647            " <a href=...> tag",doctokenizerYYlineno); 
02648   }
02649 endhref:
02650   handlePendingStyleCommands(this,m_children);
02651   DBG(("DocHRef::parse() end\n"));
02652   DocNode *n=g_nodeStack.pop();
02653   ASSERT(n==this);
02654   return retval;
02655 }
02656 
02657 //---------------------------------------------------------------------------
02658 
02659 int DocInternal::parse(int level)
02660 {
02661   int retval=RetVal_OK;
02662   g_nodeStack.push(this);
02663   DBG(("DocInternal::parse() start\n"));
02664 
02665   // first parse any number of paragraphs
02666   bool isFirst=TRUE;
02667   DocPara *lastPar=0;
02668   do
02669   {
02670     DocPara *par = new DocPara(this);
02671     if (isFirst) { par->markFirst(); isFirst=FALSE; }
02672     retval=par->parse();
02673     if (!par->isEmpty()) 
02674     {
02675       m_children.append(par);
02676       lastPar=par;
02677     }
02678     else
02679     {
02680       delete par;
02681     }
02682     if (retval==TK_LISTITEM)
02683     {
02684       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid list item found",doctokenizerYYlineno);
02685     }
02686   } while (retval!=0 && 
02687            retval!=RetVal_Section &&
02688            retval!=RetVal_Subsection &&
02689            retval!=RetVal_Subsubsection &&
02690            retval!=RetVal_Paragraph
02691           );
02692   if (lastPar) lastPar->markLast();
02693 
02694   // then parse any number of level-n sections
02695   while ((level==1 && retval==RetVal_Section) || 
02696          (level==2 && retval==RetVal_Subsection) ||
02697          (level==3 && retval==RetVal_Subsubsection) ||
02698          (level==4 && retval==RetVal_Paragraph)
02699         )
02700   {
02701     DocSection *s=new DocSection(this,level,g_token->sectionId);
02702     m_children.append(s);
02703     retval = s->parse();
02704   }
02705 
02706   if (retval==RetVal_Internal)
02707   {
02708     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: \\internal command found inside internal section");
02709   }
02710 
02711   DBG(("DocInternal::parse() end\n"));
02712   DocNode *n=g_nodeStack.pop();
02713   ASSERT(n==this);
02714   return retval;
02715 }
02716 
02717 //---------------------------------------------------------------------------
02718 
02719 int DocIndexEntry::parse()
02720 {
02721   int retval=RetVal_OK;
02722   g_nodeStack.push(this);
02723   DBG(("DocIndexEntry::parse() start\n"));
02724   int tok=doctokenizerYYlex();
02725   if (tok!=TK_WHITESPACE)
02726   {
02727     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after \\addindex command");
02728     goto endindexentry;
02729   }
02730   doctokenizerYYsetStateTitle();
02731   m_entry="";
02732   while ((tok=doctokenizerYYlex()))
02733   {
02734     switch (tok)
02735     {
02736       case TK_WHITESPACE:
02737         m_entry+=" ";
02738         break;
02739       case TK_WORD: 
02740       case TK_LNKWORD: 
02741         m_entry+=g_token->name;
02742         break;
02743       case TK_SYMBOL:
02744         {
02745           char letter='\0';
02746           DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
02747           switch (s)
02748           {
02749             case DocSymbol::BSlash:  m_entry+='\\'; break;
02750             case DocSymbol::At:      m_entry+='@';  break;
02751             case DocSymbol::Less:    m_entry+='<';  break;
02752             case DocSymbol::Greater: m_entry+='>';  break;
02753             case DocSymbol::Amp:     m_entry+='&';  break;
02754             case DocSymbol::Dollar:  m_entry+='$';  break;
02755             case DocSymbol::Hash:    m_entry+='#';  break;
02756             case DocSymbol::Percent: m_entry+='%';  break;
02757             case DocSymbol::Apos:    m_entry+='\''; break;
02758             case DocSymbol::Quot:    m_entry+='"';  break;
02759             case DocSymbol::Lsquo:   m_entry+='`';  break;
02760             case DocSymbol::Rsquo:   m_entry+='\'';  break;
02761             case DocSymbol::Ldquo:   m_entry+="``";  break;
02762             case DocSymbol::Rdquo:   m_entry+="''";  break;
02763             case DocSymbol::Ndash:   m_entry+="--";  break;
02764             case DocSymbol::Mdash:   m_entry+="---";  break;
02765             default:
02766               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected symbol found as argument of \\addindex");
02767               break;
02768           }
02769         }
02770         break;
02771     case TK_COMMAND: 
02772       switch (Mappers::cmdMapper->map(g_token->name))
02773       {
02774         case CMD_BSLASH:  m_entry+='\\'; break;
02775         case CMD_AT:      m_entry+='@';  break;
02776         case CMD_LESS:    m_entry+='<';  break;
02777         case CMD_GREATER: m_entry+='>';  break;
02778         case CMD_AMP:     m_entry+='&';  break;
02779         case CMD_DOLLAR:  m_entry+='$';  break;
02780         case CMD_HASH:    m_entry+='#';  break;
02781         case CMD_PERCENT: m_entry+='%';  break;
02782         default:
02783           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected command %s found as argument of \\addindex",
02784                     g_token->name.data());
02785           break;
02786       }
02787       break;
02788       default:
02789         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02790             tokToString(tok));
02791         break;
02792     }
02793   }
02794   if (tok!=0) retval=tok;
02795   doctokenizerYYsetStatePara();
02796 endindexentry:
02797   DBG(("DocIndexEntry::parse() end retval=%x\n",retval));
02798   DocNode *n=g_nodeStack.pop();
02799   ASSERT(n==this);
02800   return retval;
02801 }
02802 
02803 //---------------------------------------------------------------------------
02804 
02805 int DocHtmlCaption::parse()
02806 {
02807   int retval=0;
02808   g_nodeStack.push(this);
02809   DBG(("DocHtmlCaption::parse() start\n"));
02810   int tok;
02811   while ((tok=doctokenizerYYlex()))
02812   {
02813     if (!defaultHandleToken(this,tok,m_children))
02814     {
02815       switch (tok)
02816       {
02817         case TK_COMMAND: 
02818           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <caption> tag",
02819               g_token->name.data());
02820           break;
02821         case TK_SYMBOL: 
02822           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
02823               g_token->name.data());
02824           break;
02825         case TK_HTMLTAG:
02826           {
02827             int tagId=Mappers::htmlTagMapper->map(g_token->name);
02828             if (tagId==HTML_CAPTION && g_token->endTag) // found </caption> tag
02829             {
02830               retval = RetVal_OK;
02831               goto endcaption;
02832             }
02833             else
02834             {
02835               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <caption> context",
02836                   g_token->endTag?"/":"",g_token->name.data());
02837             }
02838           }
02839           break;
02840         default:
02841           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
02842               tokToString(tok));
02843           break;
02844       }
02845     }
02846   }
02847   if (tok==0)
02848   {
02849     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
02850            " <caption> tag",doctokenizerYYlineno); 
02851   }
02852 endcaption:
02853   handlePendingStyleCommands(this,m_children);
02854   DBG(("DocHtmlCaption::parse() end\n"));
02855   DocNode *n=g_nodeStack.pop();
02856   ASSERT(n==this);
02857   return retval;
02858 }
02859 
02860 //---------------------------------------------------------------------------
02861 
02862 int DocHtmlCell::parse()
02863 {
02864   int retval=RetVal_OK;
02865   g_nodeStack.push(this);
02866   DBG(("DocHtmlCell::parse() start\n"));
02867 
02868   // parse one or more paragraphs
02869   bool isFirst=TRUE;
02870   DocPara *par=0;
02871   do
02872   {
02873     par = new DocPara(this);
02874     if (isFirst) { par->markFirst(); isFirst=FALSE; }
02875     m_children.append(par);
02876     retval=par->parse();
02877     if (retval==TK_HTMLTAG)
02878     {
02879       int tagId=Mappers::htmlTagMapper->map(g_token->name);
02880       if (tagId==HTML_TD && g_token->endTag) // found </dt> tag
02881       {
02882         retval=TK_NEWPARA; // ignore the tag
02883       }
02884       else if (tagId==HTML_TH && g_token->endTag) // found </th> tag
02885       {
02886         retval=TK_NEWPARA; // ignore the tag
02887       }
02888     }
02889   }
02890   while (retval==TK_NEWPARA);
02891   if (par) par->markLast();
02892 
02893   DBG(("DocHtmlCell::parse() end\n"));
02894   DocNode *n=g_nodeStack.pop();
02895   ASSERT(n==this);
02896   return retval;
02897 }
02898 
02899 int DocHtmlCell::parseXml()
02900 {
02901   int retval=RetVal_OK;
02902   g_nodeStack.push(this);
02903   DBG(("DocHtmlCell::parseXml() start\n"));
02904 
02905   // parse one or more paragraphs
02906   bool isFirst=TRUE;
02907   DocPara *par=0;
02908   do
02909   {
02910     par = new DocPara(this);
02911     if (isFirst) { par->markFirst(); isFirst=FALSE; }
02912     m_children.append(par);
02913     retval=par->parse();
02914     if (retval==TK_HTMLTAG)
02915     {
02916       int tagId=Mappers::htmlTagMapper->map(g_token->name);
02917       if (tagId==XML_ITEM && g_token->endTag) // found </item> tag
02918       {
02919         retval=TK_NEWPARA; // ignore the tag
02920       }
02921       else if (tagId==XML_DESCRIPTION && g_token->endTag) // found </description> tag
02922       {
02923         retval=TK_NEWPARA; // ignore the tag
02924       }
02925     }
02926   }
02927   while (retval==TK_NEWPARA);
02928   if (par) par->markLast();
02929 
02930   DBG(("DocHtmlCell::parseXml() end\n"));
02931   DocNode *n=g_nodeStack.pop();
02932   ASSERT(n==this);
02933   return retval;
02934 }
02935 
02936 //---------------------------------------------------------------------------
02937 
02938 int DocHtmlRow::parse()
02939 {
02940   int retval=RetVal_OK;
02941   g_nodeStack.push(this);
02942   DBG(("DocHtmlRow::parse() start\n"));
02943 
02944   bool isHeading=FALSE;
02945   bool isFirst=TRUE;
02946   DocHtmlCell *cell=0;
02947 
02948   // get next token
02949   int tok=doctokenizerYYlex();
02950   // skip whitespace
02951   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
02952   // should find a html tag now
02953   if (tok==TK_HTMLTAG)
02954   {
02955     int tagId=Mappers::htmlTagMapper->map(g_token->name);
02956     if (tagId==HTML_TD && !g_token->endTag) // found <td> tag
02957     {
02958     }
02959     else if (tagId==HTML_TH && !g_token->endTag) // found <th> tag
02960     {
02961       isHeading=TRUE;
02962     }
02963     else // found some other tag
02964     {
02965       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <td> or <th> tag but "
02966           "found <%s> instead!",g_token->name.data());
02967       doctokenizerYYpushBackHtmlTag(g_token->name);
02968       goto endrow;
02969     }
02970   }
02971   else if (tok==0) // premature end of comment
02972   {
02973     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
02974         " for a html description title");
02975     goto endrow;
02976   }
02977   else // token other than html token
02978   {
02979     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <td> or <th> tag but found %s token instead!",
02980         tokToString(tok));
02981     goto endrow;
02982   }
02983 
02984   // parse one or more cells
02985   do
02986   {
02987     cell=new DocHtmlCell(this,g_token->attribs,isHeading);
02988     cell->markFirst(isFirst);
02989     isFirst=FALSE;
02990     m_children.append(cell);
02991     retval=cell->parse();
02992     isHeading = retval==RetVal_TableHCell;
02993   }
02994   while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
02995   if (cell) cell->markLast(TRUE);
02996 
02997 endrow:
02998   DBG(("DocHtmlRow::parse() end\n"));
02999   DocNode *n=g_nodeStack.pop();
03000   ASSERT(n==this);
03001   return retval;
03002 }
03003 
03004 int DocHtmlRow::parseXml(bool isHeading)
03005 {
03006   int retval=RetVal_OK;
03007   g_nodeStack.push(this);
03008   DBG(("DocHtmlRow::parseXml() start\n"));
03009 
03010   bool isFirst=TRUE;
03011   DocHtmlCell *cell=0;
03012 
03013   // get next token
03014   int tok=doctokenizerYYlex();
03015   // skip whitespace
03016   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
03017   // should find a html tag now
03018   if (tok==TK_HTMLTAG)
03019   {
03020     int tagId=Mappers::htmlTagMapper->map(g_token->name);
03021     if (tagId==XML_TERM && !g_token->endTag) // found <term> tag
03022     {
03023     }
03024     else if (tagId==XML_DESCRIPTION && !g_token->endTag) // found <description> tag
03025     {
03026     }
03027     else // found some other tag
03028     {
03029       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <term> or <description> tag but "
03030           "found <%s> instead!",g_token->name.data());
03031       doctokenizerYYpushBackHtmlTag(g_token->name);
03032       goto endrow;
03033     }
03034   }
03035   else if (tok==0) // premature end of comment
03036   {
03037     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
03038         " for a html description title");
03039     goto endrow;
03040   }
03041   else // token other than html token
03042   {
03043     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <td> or <th> tag but found %s token instead!",
03044         tokToString(tok));
03045     goto endrow;
03046   }
03047 
03048   do
03049   {
03050     cell=new DocHtmlCell(this,g_token->attribs,isHeading);
03051     cell->markFirst(isFirst);
03052     isFirst=FALSE;
03053     m_children.append(cell);
03054     retval=cell->parseXml();
03055   }
03056   while (retval==RetVal_TableCell || retval==RetVal_TableHCell);
03057   if (cell) cell->markLast(TRUE);
03058 
03059 endrow:
03060   DBG(("DocHtmlRow::parseXml() end\n"));
03061   DocNode *n=g_nodeStack.pop();
03062   ASSERT(n==this);
03063   return retval;
03064 }
03065 
03066 //---------------------------------------------------------------------------
03067 
03068 int DocHtmlTable::parse()
03069 {
03070   int retval=RetVal_OK;
03071   g_nodeStack.push(this);
03072   DBG(("DocHtmlTable::parse() start\n"));
03073   
03074 getrow:
03075   // get next token
03076   int tok=doctokenizerYYlex();
03077   // skip whitespace
03078   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
03079   // should find a html tag now
03080   if (tok==TK_HTMLTAG)
03081   {
03082     int tagId=Mappers::htmlTagMapper->map(g_token->name);
03083     if (tagId==HTML_TR && !g_token->endTag) // found <tr> tag
03084     {
03085       // no caption, just rows
03086       retval=RetVal_TableRow;
03087     }
03088     else if (tagId==HTML_CAPTION && !g_token->endTag) // found <caption> tag
03089     {
03090       if (m_caption)
03091       {
03092         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: table already has a caption, found another one");
03093       }
03094       else
03095       {
03096         m_caption = new DocHtmlCaption(this,g_token->attribs);
03097         retval=m_caption->parse();
03098 
03099         if (retval==RetVal_OK) // caption was parsed ok
03100         {
03101           goto getrow;
03102         }
03103       }
03104     }
03105     else // found wrong token
03106     {
03107       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <tr> or <caption> tag but "
03108           "found <%s%s> instead!", g_token->endTag ? "/" : "", g_token->name.data());
03109     }
03110   }
03111   else if (tok==0) // premature end of comment
03112   {
03113       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
03114           " for a <tr> or <caption> tag");
03115   }
03116   else // token other than html token
03117   {
03118     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <tr> tag but found %s token instead!",
03119         tokToString(tok));
03120   }
03121        
03122   // parse one or more rows
03123   while (retval==RetVal_TableRow)
03124   {
03125     DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
03126     m_children.append(tr);
03127     retval=tr->parse();
03128   } 
03129 
03130   DBG(("DocHtmlTable::parse() end\n"));
03131   DocNode *n=g_nodeStack.pop();
03132   ASSERT(n==this);
03133   return retval==RetVal_EndTable ? RetVal_OK : retval;
03134 }
03135 
03136 int DocHtmlTable::parseXml()
03137 {
03138   int retval=RetVal_OK;
03139   g_nodeStack.push(this);
03140   DBG(("DocHtmlTable::parseXml() start\n"));
03141   
03142   // get next token
03143   int tok=doctokenizerYYlex();
03144   // skip whitespace
03145   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
03146   // should find a html tag now
03147   int tagId=0;
03148   bool isHeader=FALSE;
03149   if (tok==TK_HTMLTAG)
03150   {
03151     tagId=Mappers::htmlTagMapper->map(g_token->name);
03152     if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
03153     {
03154       retval=RetVal_TableRow;
03155     }
03156     if (tagId==XML_LISTHEADER && !g_token->endTag) // found <listheader> tag
03157     {
03158       retval=RetVal_TableRow;
03159       isHeader=TRUE;
03160     }
03161   }
03162 
03163   // parse one or more rows
03164   while (retval==RetVal_TableRow)
03165   {
03166     DocHtmlRow *tr=new DocHtmlRow(this,g_token->attribs);
03167     m_children.append(tr);
03168     retval=tr->parseXml(isHeader);
03169     isHeader=FALSE;
03170   } 
03171 
03172   DBG(("DocHtmlTable::parseXml() end\n"));
03173   DocNode *n=g_nodeStack.pop();
03174   ASSERT(n==this);
03175   return retval==RetVal_EndTable ? RetVal_OK : retval;
03176 }
03177 
03178 uint DocHtmlTable::numCols() const
03179 {
03180   uint cols=0;
03181   QListIterator<DocNode> cli(m_children);
03182   DocNode *n;
03183   for (cli.toFirst();(n=cli.current());++cli)
03184   {
03185     ASSERT(n->kind()==DocNode::Kind_HtmlRow);
03186     cols=QMAX(cols,((DocHtmlRow *)n)->numCells());
03187   }
03188   return cols;
03189 }
03190 
03191 void DocHtmlTable::accept(DocVisitor *v) 
03192 { 
03193   v->visitPre(this); 
03194   // for HTML output we put the caption first
03195   if (m_caption && v->id()==DocVisitor_Html) m_caption->accept(v);
03196   QListIterator<DocNode> cli(m_children);
03197   DocNode *n;
03198   for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
03199   // for other output formats we put the caption last
03200   if (m_caption && v->id()!=DocVisitor_Html) m_caption->accept(v);
03201   v->visitPost(this); 
03202 }
03203 
03204 //---------------------------------------------------------------------------
03205 
03206 int DocHtmlDescTitle::parse()
03207 {
03208   int retval=0;
03209   g_nodeStack.push(this);
03210   DBG(("DocHtmlDescTitle::parse() start\n"));
03211 
03212   int tok;
03213   while ((tok=doctokenizerYYlex()))
03214   {
03215     if (!defaultHandleToken(this,tok,m_children))
03216     {
03217       switch (tok)
03218       {
03219         case TK_COMMAND: 
03220           {
03221             QString cmdName=g_token->name;
03222             bool isJavaLink=FALSE;
03223             switch (Mappers::cmdMapper->map(cmdName))
03224             {
03225               case CMD_REF:
03226                 {
03227                   int tok=doctokenizerYYlex();
03228                   if (tok!=TK_WHITESPACE)
03229                   {
03230                     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
03231                         g_token->name.data());
03232                   }
03233                   else
03234                   {
03235                     doctokenizerYYsetStateRef();
03236                     tok=doctokenizerYYlex(); // get the reference id
03237                     if (tok!=TK_WORD)
03238                     {
03239                       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
03240                           tokToString(tok),cmdName.data());
03241                     }
03242                     else
03243                     {
03244                       DocRef *ref = new DocRef(this,g_token->name,g_context);
03245                       m_children.append(ref);
03246                       ref->parse();
03247                     }
03248                     doctokenizerYYsetStatePara();
03249                   }
03250                 }
03251                 break;
03252               case CMD_JAVALINK:
03253                 isJavaLink=TRUE;
03254                 // fall through
03255               case CMD_LINK:
03256                 {
03257                   int tok=doctokenizerYYlex();
03258                   if (tok!=TK_WHITESPACE)
03259                   {
03260                     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
03261                         cmdName.data());
03262                   }
03263                   else
03264                   {
03265                     doctokenizerYYsetStateLink();
03266                     tok=doctokenizerYYlex();
03267                     if (tok!=TK_WORD)
03268                     {
03269                       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
03270                           tokToString(tok),cmdName.data());
03271                     }
03272                     else
03273                     {
03274                       doctokenizerYYsetStatePara();
03275                       DocLink *lnk = new DocLink(this,g_token->name);
03276                       m_children.append(lnk);
03277                       QString leftOver = lnk->parse(isJavaLink);
03278                       if (!leftOver.isEmpty())
03279                       {
03280                         m_children.append(new DocWord(this,leftOver));
03281                       }
03282                     }
03283                   }
03284                 }
03285 
03286                 break;
03287               default:
03288                 warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a <dt> tag",
03289                                g_token->name.data());
03290             }
03291           }
03292           break;
03293         case TK_SYMBOL: 
03294           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
03295               g_token->name.data());
03296           break;
03297         case TK_HTMLTAG:
03298           {
03299             int tagId=Mappers::htmlTagMapper->map(g_token->name);
03300             if (tagId==HTML_DD && !g_token->endTag) // found <dd> tag
03301             {
03302               retval = RetVal_DescData;
03303               goto endtitle;
03304             }
03305             else if (tagId==HTML_DT && g_token->endTag)
03306             {
03307               // ignore </dt> tag.
03308             }
03309             else if (tagId==HTML_DT)
03310             {
03311               // missing <dt> tag.
03312               retval = RetVal_DescTitle;
03313               goto endtitle;
03314             }
03315             else if (tagId==HTML_DL && g_token->endTag)
03316             {
03317               retval=RetVal_EndDesc;
03318               goto endtitle;
03319             }
03320             else
03321             {
03322               warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected html tag <%s%s> found within <dt> context",
03323                   g_token->endTag?"/":"",g_token->name.data());
03324             }
03325           }
03326           break;
03327         default:
03328           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
03329               tokToString(tok));
03330           break;
03331       }
03332     }
03333   }
03334   if (tok==0)
03335   {
03336     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected end of comment while inside"
03337         " <dt> tag"); 
03338   }
03339 endtitle:
03340   handlePendingStyleCommands(this,m_children);
03341   DBG(("DocHtmlDescTitle::parse() end\n"));
03342   DocNode *n=g_nodeStack.pop();
03343   ASSERT(n==this);
03344   return retval;
03345 }
03346 
03347 //---------------------------------------------------------------------------
03348 
03349 int DocHtmlDescData::parse()
03350 {
03351   m_attribs = g_token->attribs;
03352   int retval=0;
03353   g_nodeStack.push(this);
03354   DBG(("DocHtmlDescData::parse() start\n"));
03355 
03356   bool isFirst=TRUE;
03357   DocPara *par=0;
03358   do
03359   {
03360     par = new DocPara(this);
03361     if (isFirst) { par->markFirst(); isFirst=FALSE; }
03362     m_children.append(par);
03363     retval=par->parse();
03364   }
03365   while (retval==TK_NEWPARA);
03366   if (par) par->markLast();
03367   
03368   DBG(("DocHtmlDescData::parse() end\n"));
03369   DocNode *n=g_nodeStack.pop();
03370   ASSERT(n==this);
03371   return retval;
03372 }
03373 
03374 //---------------------------------------------------------------------------
03375 
03376 int DocHtmlDescList::parse()
03377 {
03378   int retval=RetVal_OK;
03379   g_nodeStack.push(this);
03380   DBG(("DocHtmlDescList::parse() start\n"));
03381 
03382   // get next token
03383   int tok=doctokenizerYYlex();
03384   // skip whitespace
03385   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
03386   // should find a html tag now
03387   if (tok==TK_HTMLTAG)
03388   {
03389     int tagId=Mappers::htmlTagMapper->map(g_token->name);
03390     if (tagId==HTML_DT && !g_token->endTag) // found <dt> tag
03391     {
03392       // continue
03393     }
03394     else // found some other tag
03395     {
03396       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <dt> tag but "
03397           "found <%s> instead!",g_token->name.data());
03398       doctokenizerYYpushBackHtmlTag(g_token->name);
03399       goto enddesclist;
03400     }
03401   }
03402   else if (tok==0) // premature end of comment
03403   {
03404     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
03405         " for a html description title");
03406     goto enddesclist;
03407   }
03408   else // token other than html token
03409   {
03410     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <dt> tag but found %s token instead!",
03411         tokToString(tok));
03412     goto enddesclist;
03413   }
03414 
03415   do
03416   {
03417     DocHtmlDescTitle *dt=new DocHtmlDescTitle(this,g_token->attribs);
03418     m_children.append(dt);
03419     DocHtmlDescData *dd=new DocHtmlDescData(this);
03420     m_children.append(dd);
03421     retval=dt->parse();
03422     if (retval==RetVal_DescData)
03423     {
03424       retval=dd->parse();
03425     }
03426     else if (retval!=RetVal_DescTitle)
03427     {
03428       // error
03429       break;
03430     }
03431   } while (retval==RetVal_DescTitle);
03432 
03433   if (retval==0)
03434   {
03435     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <dl> block");
03436   }
03437 
03438 enddesclist:
03439 
03440   DocNode *n=g_nodeStack.pop();
03441   ASSERT(n==this);
03442   DBG(("DocHtmlDescList::parse() end\n"));
03443   return retval==RetVal_EndDesc ? RetVal_OK : retval;
03444 }
03445 
03446 //---------------------------------------------------------------------------
03447 
03448 int DocHtmlListItem::parse()
03449 {
03450   DBG(("DocHtmlListItem::parse() start\n"));
03451   int retval=0;
03452   g_nodeStack.push(this);
03453 
03454   // parse one or more paragraphs
03455   bool isFirst=TRUE;
03456   DocPara *par=0;
03457   do
03458   {
03459     par = new DocPara(this);
03460     if (isFirst) { par->markFirst(); isFirst=FALSE; }
03461     m_children.append(par);
03462     retval=par->parse();
03463   }
03464   while (retval==TK_NEWPARA);
03465   if (par) par->markLast();
03466 
03467   DocNode *n=g_nodeStack.pop();
03468   ASSERT(n==this);
03469   DBG(("DocHtmlListItem::parse() end retval=%x\n",retval));
03470   return retval;
03471 }
03472 
03473 int DocHtmlListItem::parseXml()
03474 {
03475   DBG(("DocHtmlListItem::parseXml() start\n"));
03476   int retval=0;
03477   g_nodeStack.push(this);
03478 
03479   // parse one or more paragraphs
03480   bool isFirst=TRUE;
03481   DocPara *par=0;
03482   do
03483   {
03484     par = new DocPara(this);
03485     if (isFirst) { par->markFirst(); isFirst=FALSE; }
03486     m_children.append(par);
03487     retval=par->parse();
03488     if (retval==0) break;
03489 
03490     //printf("new item: retval=%x g_token->name=%s g_token->endTag=%d\n",
03491     //    retval,g_token->name.data(),g_token->endTag);
03492     if (retval==RetVal_ListItem)
03493     {
03494       break;
03495     }
03496   }
03497   while (retval!=RetVal_CloseXml);
03498 
03499   if (par) par->markLast();
03500 
03501   DocNode *n=g_nodeStack.pop();
03502   ASSERT(n==this);
03503   DBG(("DocHtmlListItem::parseXml() end retval=%x\n",retval));
03504   return retval;
03505 }
03506 
03507 //---------------------------------------------------------------------------
03508 
03509 int DocHtmlList::parse()
03510 {
03511   DBG(("DocHtmlList::parse() start\n"));
03512   int retval=RetVal_OK;
03513   int num=1;
03514   g_nodeStack.push(this);
03515 
03516   // get next token
03517   int tok=doctokenizerYYlex();
03518   // skip whitespace and paragraph breaks
03519   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
03520   // should find a html tag now
03521   if (tok==TK_HTMLTAG)
03522   {
03523     int tagId=Mappers::htmlTagMapper->map(g_token->name);
03524     if (tagId==HTML_LI && !g_token->endTag) // found <li> tag
03525     {
03526       // ok, we can go on.
03527     }
03528     else // found some other tag
03529     {
03530       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <li> tag but "
03531           "found <%s> instead!",g_token->name.data());
03532       doctokenizerYYpushBackHtmlTag(g_token->name);
03533       goto endlist;
03534     }
03535   }
03536   else if (tok==0) // premature end of comment
03537   {
03538     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
03539         " for a html list item");
03540     goto endlist;
03541   }
03542   else // token other than html token
03543   {
03544     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <li> tag but found %s token instead!",
03545         tokToString(tok));
03546     goto endlist;
03547   }
03548 
03549   do
03550   {
03551     DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
03552     m_children.append(li);
03553     retval=li->parse();
03554   } while (retval==RetVal_ListItem);
03555   
03556   if (retval==0)
03557   {
03558     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <%cl> block",
03559         m_type==Unordered ? 'u' : 'o');
03560   }
03561 
03562 endlist:
03563   DBG(("DocHtmlList::parse() end retval=%x\n",retval));
03564   DocNode *n=g_nodeStack.pop();
03565   ASSERT(n==this);
03566   return retval==RetVal_EndList ? RetVal_OK : retval;
03567 }
03568 
03569 int DocHtmlList::parseXml()
03570 {
03571   DBG(("DocHtmlList::parseXml() start\n"));
03572   int retval=RetVal_OK;
03573   int num=1;
03574   g_nodeStack.push(this);
03575 
03576   // get next token
03577   int tok=doctokenizerYYlex();
03578   // skip whitespace and paragraph breaks
03579   while (tok==TK_WHITESPACE || tok==TK_NEWPARA) tok=doctokenizerYYlex();
03580   // should find a html tag now
03581   if (tok==TK_HTMLTAG)
03582   {
03583     int tagId=Mappers::htmlTagMapper->map(g_token->name);
03584     //printf("g_token->name=%s g_token->endTag=%d\n",g_token->name.data(),g_token->endTag);
03585     if (tagId==XML_ITEM && !g_token->endTag) // found <item> tag
03586     {
03587       // ok, we can go on.
03588     }
03589     else // found some other tag
03590     {
03591       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <item> tag but "
03592           "found <%s> instead!",g_token->name.data());
03593       doctokenizerYYpushBackHtmlTag(g_token->name);
03594       goto endlist;
03595     }
03596   }
03597   else if (tok==0) // premature end of comment
03598   {
03599     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while looking"
03600         " for a html list item");
03601     goto endlist;
03602   }
03603   else // token other than html token
03604   {
03605     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected <item> tag but found %s token instead!",
03606         tokToString(tok));
03607     goto endlist;
03608   }
03609 
03610   do
03611   {
03612     DocHtmlListItem *li=new DocHtmlListItem(this,g_token->attribs,num++);
03613     m_children.append(li);
03614     retval=li->parseXml();
03615     if (retval==0) break;
03616     //printf("retval=%x g_token->name=%s\n",retval,g_token->name.data());
03617   } while (retval==RetVal_ListItem);
03618   
03619   if (retval==0)
03620   {
03621     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment while inside <list type=\"%s\"> block",
03622         m_type==Unordered ? "bullet" : "number");
03623   }
03624 
03625 endlist:
03626   DBG(("DocHtmlList::parseXml() end retval=%x\n",retval));
03627   DocNode *n=g_nodeStack.pop();
03628   ASSERT(n==this);
03629   return retval==RetVal_EndList || 
03630          (retval==RetVal_CloseXml || g_token->name=="list") ? 
03631          RetVal_OK : retval;
03632 }
03633 
03634 //---------------------------------------------------------------------------
03635 
03636 int DocSimpleListItem::parse()
03637 {
03638   g_nodeStack.push(this);
03639   int rv=m_paragraph->parse();
03640   m_paragraph->markFirst();
03641   m_paragraph->markLast();
03642   DocNode *n=g_nodeStack.pop();
03643   ASSERT(n==this);
03644   return rv;
03645 }
03646 
03647 //--------------------------------------------------------------------------
03648 
03649 int DocSimpleList::parse()
03650 {
03651   g_nodeStack.push(this);
03652   int rv;
03653   do
03654   {
03655     DocSimpleListItem *li=new DocSimpleListItem(this);
03656     m_children.append(li);
03657     rv=li->parse();
03658   } while (rv==RetVal_ListItem);
03659   DocNode *n=g_nodeStack.pop();
03660   ASSERT(n==this);
03661   return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
03662 }
03663 
03664 //--------------------------------------------------------------------------
03665 
03666 int DocAutoListItem::parse()
03667 {
03668   int retval = RetVal_OK;
03669   g_nodeStack.push(this);
03670   retval=m_paragraph->parse();
03671   m_paragraph->markFirst();
03672   m_paragraph->markLast();
03673   DocNode *n=g_nodeStack.pop();
03674   ASSERT(n==this);
03675   return retval;
03676 }
03677 
03678 //--------------------------------------------------------------------------
03679 
03680 int DocAutoList::parse()
03681 {
03682   int retval = RetVal_OK;
03683   int num=1;
03684   g_nodeStack.push(this);
03685           // first item or sub list => create new list
03686   do
03687   {
03688     DocAutoListItem *li = new DocAutoListItem(this,num++);
03689     m_children.append(li);
03690     retval=li->parse();
03691   } 
03692   while (retval==TK_LISTITEM &&              // new list item
03693          m_indent==g_token->indent &&        // at same indent level
03694          m_isEnumList==g_token->isEnumList   // of the same kind
03695         );
03696 
03697   DocNode *n=g_nodeStack.pop();
03698   ASSERT(n==this);
03699   return retval;
03700 }
03701 
03702 //--------------------------------------------------------------------------
03703 
03704 void DocTitle::parse()
03705 {
03706   DBG(("DocTitle::parse() start\n"));
03707   g_nodeStack.push(this);
03708   doctokenizerYYsetStateTitle();
03709   int tok;
03710   while ((tok=doctokenizerYYlex()))
03711   {
03712     if (!defaultHandleToken(this,tok,m_children))
03713     {
03714       switch (tok)
03715       {
03716         case TK_COMMAND: 
03717           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal command %s as part of a title section",
03718                g_token->name.data());
03719           break;
03720         case TK_SYMBOL: 
03721           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
03722                g_token->name.data());
03723           break;
03724         default:
03725           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
03726                 tokToString(tok));
03727           break;
03728       }
03729     }
03730   }
03731   doctokenizerYYsetStatePara();
03732   handlePendingStyleCommands(this,m_children);
03733   DBG(("DocTitle::parse() end\n"));
03734   DocNode *n = g_nodeStack.pop();
03735   ASSERT(n==this);
03736 }
03737 
03738 void DocTitle::parseFromString(const QString &text)
03739 {
03740   m_children.append(new DocWord(this,text));
03741 }
03742 
03743 //--------------------------------------------------------------------------
03744 
03745 DocSimpleSect::DocSimpleSect(DocNode *parent,Type t) : 
03746      m_parent(parent), m_type(t)
03747 { 
03748   m_title=0; 
03749 }
03750 
03751 DocSimpleSect::~DocSimpleSect()
03752 { 
03753   delete m_title; 
03754 }
03755 
03756 void DocSimpleSect::accept(DocVisitor *v)
03757 {
03758   v->visitPre(this);
03759   if (m_title) m_title->accept(v);
03760   QListIterator<DocNode> cli(m_children);
03761   DocNode *n;
03762   for (cli.toFirst();(n=cli.current());++cli) n->accept(v);
03763   v->visitPost(this);
03764 }
03765 
03766 int DocSimpleSect::parse(bool userTitle)
03767 {
03768   DBG(("DocSimpleSect::parse() start\n"));
03769   g_nodeStack.push(this);
03770 
03771   // handle case for user defined title
03772   if (userTitle)
03773   {
03774     m_title = new DocTitle(this);
03775     m_title->parse();
03776   }
03777   
03778   // add new paragraph as child
03779   DocPara *par = new DocPara(this);
03780   if (m_children.isEmpty()) 
03781   {
03782     par->markFirst();
03783   }
03784   else
03785   {
03786     ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
03787     ((DocPara *)m_children.last())->markLast(FALSE);
03788   }
03789   par->markLast();
03790   m_children.append(par);
03791   
03792   // parse the contents of the paragraph
03793   int retval = par->parse();
03794 
03795   DBG(("DocSimpleSect::parse() end retval=%d\n",retval));
03796   DocNode *n=g_nodeStack.pop();
03797   ASSERT(n==this);
03798   return retval; // 0==EOF, TK_NEWPARA, TK_LISTITEM, TK_ENDLIST, RetVal_SimpleSec
03799 }
03800 
03801 int DocSimpleSect::parseRcs()
03802 {
03803   DBG(("DocSimpleSect::parseRcs() start\n"));
03804   g_nodeStack.push(this);
03805 
03806   m_title = new DocTitle(this);
03807   m_title->parseFromString(g_token->name);
03808 
03809   QString text = g_token->text;
03810   docParserPushContext(); // this will create a new g_token
03811   internalValidatingParseDoc(this,m_children,text);
03812   docParserPopContext(); // this will restore the old g_token
03813 
03814   DBG(("DocSimpleSect::parseRcs()\n"));
03815   DocNode *n=g_nodeStack.pop();
03816   ASSERT(n==this);
03817   return RetVal_OK; 
03818 }
03819 
03820 int DocSimpleSect::parseXml()
03821 {
03822   DBG(("DocSimpleSect::parse() start\n"));
03823   g_nodeStack.push(this);
03824 
03825   int retval = RetVal_OK;
03826   for (;;) 
03827   {
03828     // add new paragraph as child
03829     DocPara *par = new DocPara(this);
03830     if (m_children.isEmpty()) 
03831     {
03832       par->markFirst();
03833     }
03834     else
03835     {
03836       ASSERT(m_children.last()->kind()==DocNode::Kind_Para);
03837       ((DocPara *)m_children.last())->markLast(FALSE);
03838     }
03839     par->markLast();
03840     m_children.append(par);
03841 
03842     // parse the contents of the paragraph
03843     retval = par->parse();
03844     if (retval == 0) break;
03845     if (retval == RetVal_CloseXml) 
03846     {
03847       retval = RetVal_OK;
03848       break;
03849     }
03850   }
03851   
03852   DBG(("DocSimpleSect::parseXml() end retval=%d\n",retval));
03853   DocNode *n=g_nodeStack.pop();
03854   ASSERT(n==this);
03855   return retval; 
03856 }
03857 
03858 void DocSimpleSect::appendLinkWord(const QString &word)
03859 {
03860   DocPara *p;
03861   if (m_children.isEmpty() || m_children.last()->kind()!=DocNode::Kind_Para)
03862   {
03863     p = new DocPara(this);
03864     m_children.append(p);
03865   }
03866   else
03867   {
03868     p = (DocPara *)m_children.last();
03869     
03870     // Comma-seperate <seealso> links.
03871     p->injectToken(TK_WORD,",");
03872     p->injectToken(TK_WHITESPACE," ");
03873   }
03874   
03875   g_inSeeBlock=TRUE;
03876   p->injectToken(TK_LNKWORD,word);
03877   g_inSeeBlock=FALSE;
03878 }
03879 
03880 QCString DocSimpleSect::typeString() const
03881 {
03882   switch (m_type)
03883   {
03884     case Unknown:    break;
03885     case See:        return "see";
03886     case Return:     return "return";
03887     case Author:     // fall through
03888     case Authors:    return "author";
03889     case Version:    return "version";
03890     case Since:      return "since";
03891     case Date:       return "date";
03892     case Note:       return "note";
03893     case Warning:    return "warning";
03894     case Pre:        return "pre";
03895     case Post:       return "post";
03896     case Invar:      return "invariant";
03897     case Remark:     return "remark";
03898     case Attention:  return "attention";
03899     case User:       return "user";
03900     case Rcs:        return "rcs";
03901   }
03902   return "unknown";
03903 }
03904 
03905 //--------------------------------------------------------------------------
03906 
03907 int DocParamList::parse(const QString &cmdName)
03908 {
03909   int retval=RetVal_OK;
03910   DBG(("DocParamList::parse() start\n"));
03911   g_nodeStack.push(this);
03912   DocPara *par=0;
03913 
03914   int tok=doctokenizerYYlex();
03915   if (tok!=TK_WHITESPACE)
03916   {
03917     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
03918         cmdName.data());
03919   }
03920   doctokenizerYYsetStateParam();
03921   tok=doctokenizerYYlex();
03922   while (tok==TK_WORD) /* there is a parameter name */
03923   {
03924     if (m_type==DocParamSect::Param)
03925     {
03926       g_hasParamCommand=TRUE;
03927       checkArgumentName(g_token->name,TRUE);
03928     }
03929     else if (m_type==DocParamSect::RetVal)
03930     {
03931       g_hasReturnCommand=TRUE;
03932       checkArgumentName(g_token->name,FALSE);
03933     }
03934     //m_params.append(g_token->name);
03935     handleLinkedWord(this,m_params);
03936     tok=doctokenizerYYlex();
03937   }
03938   doctokenizerYYsetStatePara();
03939   if (tok==0) /* premature end of comment block */
03940   {
03941     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
03942         "argument of command %s",cmdName.data());
03943     retval=0;
03944     goto endparamlist;
03945   }
03946   ASSERT(tok==TK_WHITESPACE);
03947 
03948   par = new DocPara(this);
03949   m_paragraphs.append(par);
03950   retval = par->parse();
03951   par->markFirst();
03952   par->markLast();
03953 
03954 endparamlist:
03955   DBG(("DocParamList::parse() end retval=%d\n",retval));
03956   DocNode *n=g_nodeStack.pop();
03957   ASSERT(n==this);
03958   return retval;
03959 }
03960 
03961 int DocParamList::parseXml(const QString &paramName)
03962 {
03963   int retval=RetVal_OK;
03964   DBG(("DocParamList::parseXml() start\n"));
03965   g_nodeStack.push(this);
03966 
03967   g_token->name = paramName;
03968   if (m_type==DocParamSect::Param)
03969   {
03970     g_hasParamCommand=TRUE;
03971     checkArgumentName(g_token->name,TRUE);
03972   }
03973   else if (m_type==DocParamSect::RetVal)
03974   {
03975     g_hasReturnCommand=TRUE;
03976     checkArgumentName(g_token->name,FALSE);
03977   }
03978   
03979   handleLinkedWord(this,m_params);
03980 
03981   do
03982   {
03983     DocPara *par = new DocPara(this);
03984     retval = par->parse();
03985     if (par->isEmpty()) // avoid adding an empty paragraph for the whitespace
03986                         // after </para> and before </param>
03987     {
03988       delete par;
03989       break;
03990     }
03991     else // append the paragraph to the list
03992     {
03993       if (m_paragraphs.isEmpty())
03994       {
03995         par->markFirst();
03996       }
03997       else
03998       {
03999         m_paragraphs.last()->markLast(FALSE);
04000       }
04001       par->markLast();
04002       m_paragraphs.append(par);
04003     }
04004 
04005     if (retval == 0) break;
04006 
04007   } while (retval==RetVal_CloseXml && 
04008            Mappers::htmlTagMapper->map(g_token->name)!=XML_PARAM &&
04009            Mappers::htmlTagMapper->map(g_token->name)!=XML_TYPEPARAM &&
04010            Mappers::htmlTagMapper->map(g_token->name)!=XML_EXCEPTION);
04011   
04012 
04013   if (retval==0) /* premature end of comment block */
04014   {
04015     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unterminated param or exception tag");
04016   }
04017   else
04018   {
04019     retval=RetVal_OK;
04020   }
04021 
04022 
04023   DBG(("DocParamList::parse() end retval=%d\n",retval));
04024   DocNode *n=g_nodeStack.pop();
04025   ASSERT(n==this);
04026   return retval;
04027 }
04028 
04029 //--------------------------------------------------------------------------
04030 
04031 int DocParamSect::parse(const QString &cmdName,bool xmlContext, Direction d)
04032 {
04033   int retval=RetVal_OK;
04034   DBG(("DocParamSect::parse() start\n"));
04035   g_nodeStack.push(this);
04036 
04037   DocParamList *pl = new DocParamList(this,m_type,d);
04038   if (m_children.isEmpty())
04039   {
04040     pl->markFirst();
04041     pl->markLast();
04042   }
04043   else
04044   {
04045     ASSERT(m_children.last()->kind()==DocNode::Kind_ParamList);
04046     ((DocParamList *)m_children.last())->markLast(FALSE);
04047     pl->markLast();
04048   }
04049   m_children.append(pl);
04050   if (xmlContext)
04051   {
04052     retval = pl->parseXml(cmdName);
04053   }
04054   else
04055   {
04056     retval = pl->parse(cmdName);
04057   }
04058   
04059   DBG(("DocParamSect::parse() end retval=%d\n",retval));
04060   DocNode *n=g_nodeStack.pop();
04061   ASSERT(n==this);
04062   return retval;
04063 }
04064 
04065 //--------------------------------------------------------------------------
04066 
04067 int DocPara::handleSimpleSection(DocSimpleSect::Type t, bool xmlContext)
04068 {
04069   DocSimpleSect *ss=0;
04070   if (!m_children.isEmpty() &&                           // previous element
04071       m_children.last()->kind()==Kind_SimpleSect &&      // was a simple sect
04072       ((DocSimpleSect *)m_children.last())->type()==t && // of same type
04073       t!=DocSimpleSect::User)                            // but not user defined
04074   {
04075     // append to previous section
04076     ss=(DocSimpleSect *)m_children.last();
04077   }
04078   else // start new section
04079   {
04080     ss=new DocSimpleSect(this,t);
04081     m_children.append(ss);
04082   }
04083   int rv = RetVal_OK;
04084   if (xmlContext)
04085   {
04086     return ss->parseXml();
04087   }
04088   else
04089   {
04090     rv = ss->parse(t==DocSimpleSect::User);
04091   }
04092   return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
04093 }
04094 
04095 int DocPara::handleParamSection(const QString &cmdName,
04096                                 DocParamSect::Type t,
04097                                 bool xmlContext=FALSE,
04098                                 int direction=DocParamSect::Unspecified)
04099 {
04100   DocParamSect *ps=0;
04101   if (!m_children.isEmpty() &&                        // previous element
04102       m_children.last()->kind()==Kind_ParamSect &&    // was a param sect
04103       ((DocParamSect *)m_children.last())->type()==t) // of same type
04104   {
04105     // append to previous section
04106     ps=(DocParamSect *)m_children.last();
04107   }
04108   else // start new section
04109   {
04110     ps=new DocParamSect(this,t);
04111     m_children.append(ps);
04112   }
04113   int rv=ps->parse(cmdName,xmlContext,(DocParamSect::Direction)direction);
04114   return (rv!=TK_NEWPARA) ? rv : RetVal_OK;
04115 }
04116 
04117 int DocPara::handleXRefItem()
04118 {
04119   int retval=doctokenizerYYlex();
04120   ASSERT(retval==TK_WHITESPACE);
04121   doctokenizerYYsetStateXRefItem();
04122   retval=doctokenizerYYlex();
04123   if (retval==RetVal_OK)
04124   {
04125     DocXRefItem *ref = new DocXRefItem(this,g_token->id,g_token->name);
04126     if (ref->parse())
04127     {
04128       m_children.append(ref);
04129     }
04130     else 
04131     {
04132       delete ref;
04133     }
04134   }
04135   doctokenizerYYsetStatePara();
04136   return retval;
04137 }
04138 
04139 void DocPara::handleIncludeOperator(const QString &cmdName,DocIncOperator::Type t)
04140 {
04141   DBG(("handleIncludeOperator(%s)\n",cmdName.data()));
04142   int tok=doctokenizerYYlex();
04143   if (tok!=TK_WHITESPACE)
04144   {
04145     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04146         cmdName.data());
04147     return;
04148   }
04149   doctokenizerYYsetStatePattern();
04150   tok=doctokenizerYYlex();
04151   doctokenizerYYsetStatePara();
04152   if (tok==0)
04153   {
04154     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
04155         "argument of command %s", cmdName.data());
04156     return;
04157   }
04158   else if (tok!=TK_WORD)
04159   {
04160     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04161         tokToString(tok),cmdName.data());
04162     return;
04163   }
04164   DocIncOperator *op = new DocIncOperator(this,t,g_token->name,g_context,g_isExample,g_exampleName);
04165   DocNode *n1 = m_children.last();
04166   DocNode *n2 = n1!=0 ? m_children.prev() : 0;
04167   bool isFirst = n1==0 || // no last node
04168                  (n1->kind()!=DocNode::Kind_IncOperator && 
04169                   n1->kind()!=DocNode::Kind_WhiteSpace
04170                  ) || // last node is not operator or whitespace
04171                  (n1->kind()==DocNode::Kind_WhiteSpace && 
04172                   n2!=0 && n2->kind()!=DocNode::Kind_IncOperator
04173                  ); // previous not is not operator
04174   op->markFirst(isFirst);
04175   op->markLast(TRUE);
04176   if (n1!=0 && n1->kind()==DocNode::Kind_IncOperator)
04177   {
04178     ((DocIncOperator *)n1)->markLast(FALSE);
04179   }
04180   else if (n1!=0 && n1->kind()==DocNode::Kind_WhiteSpace &&
04181            n2!=0 && n2->kind()==DocNode::Kind_IncOperator
04182           )
04183   {
04184     ((DocIncOperator *)n2)->markLast(FALSE);
04185   }
04186   m_children.append(op);
04187   op->parse();
04188 }
04189 
04190 void DocPara::handleImage(const QString &cmdName)
04191 {
04192   int tok=doctokenizerYYlex();
04193   if (tok!=TK_WHITESPACE)
04194   {
04195     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04196         cmdName.data());
04197     return;
04198   }
04199   tok=doctokenizerYYlex();
04200   if (tok!=TK_WORD && tok!=TK_LNKWORD)
04201   {
04202     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04203         tokToString(tok),cmdName.data());
04204     return;
04205   }
04206   tok=doctokenizerYYlex();
04207   if (tok!=TK_WHITESPACE)
04208   {
04209     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04210         cmdName.data());
04211     return;
04212   }
04213   DocImage::Type t;
04214   QString imgType = g_token->name.lower();
04215   if      (imgType=="html")  t=DocImage::Html;
04216   else if (imgType=="latex") t=DocImage::Latex;
04217   else if (imgType=="rtf")   t=DocImage::Rtf;
04218   else
04219   {
04220     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: image type %s specified as the first argument of "
04221         "%s is not valid",
04222         imgType.data(),cmdName.data());
04223     return;
04224   } 
04225   doctokenizerYYsetStateFile();
04226   tok=doctokenizerYYlex();
04227   doctokenizerYYsetStatePara();
04228   if (tok!=TK_WORD)
04229   {
04230     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04231         tokToString(tok),cmdName.data());
04232     return;
04233   }
04234   HtmlAttribList attrList;
04235   DocImage *img = new DocImage(this,attrList,findAndCopyImage(g_token->name,t),t);
04236   m_children.append(img);
04237   img->parse();
04238 }
04239 
04240 void DocPara::handleDotFile(const QString &cmdName)
04241 {
04242   int tok=doctokenizerYYlex();
04243   if (tok!=TK_WHITESPACE)
04244   {
04245     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04246         cmdName.data());
04247     return;
04248   }
04249   doctokenizerYYsetStateFile();
04250   tok=doctokenizerYYlex();
04251   doctokenizerYYsetStatePara();
04252   if (tok!=TK_WORD)
04253   {
04254     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04255         tokToString(tok),cmdName.data());
04256     return;
04257   }
04258   QString name = g_token->name;
04259   DocDotFile *df = new DocDotFile(this,name,g_context);
04260   m_children.append(df);
04261   df->parse();
04262 }
04263 
04264 void DocPara::handleLink(const QString &cmdName,bool isJavaLink)
04265 {
04266   int tok=doctokenizerYYlex();
04267   if (tok!=TK_WHITESPACE)
04268   {
04269     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04270         cmdName.data());
04271     return;
04272   }
04273   doctokenizerYYsetStateLink();
04274   tok=doctokenizerYYlex();
04275   if (tok!=TK_WORD)
04276   {
04277     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04278         tokToString(tok),cmdName.data());
04279     return;
04280   }
04281   doctokenizerYYsetStatePara();
04282   DocLink *lnk = new DocLink(this,g_token->name);
04283   m_children.append(lnk);
04284   QString leftOver = lnk->parse(isJavaLink);
04285   if (!leftOver.isEmpty())
04286   {
04287     m_children.append(new DocWord(this,leftOver));
04288   }
04289 }
04290 
04291 void DocPara::handleRef(const QString &cmdName)
04292 {
04293   DBG(("handleRef(%s)\n",cmdName.data()));
04294   int tok=doctokenizerYYlex();
04295   if (tok!=TK_WHITESPACE)
04296   {
04297     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04298         cmdName.data());
04299     return;
04300   }
04301   doctokenizerYYsetStateRef();
04302   tok=doctokenizerYYlex(); // get the reference id
04303   DocRef *ref=0;
04304   if (tok!=TK_WORD)
04305   {
04306     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04307         tokToString(tok),cmdName.data());
04308     goto endref;
04309   }
04310   ref = new DocRef(this,g_token->name,g_context);
04311   m_children.append(ref);
04312   ref->parse();
04313 endref:
04314   doctokenizerYYsetStatePara();
04315 }
04316 
04317 
04318 void DocPara::handleInclude(const QString &cmdName,DocInclude::Type t)
04319 {
04320   DBG(("handleInclude(%s)\n",cmdName.data()));
04321   int tok=doctokenizerYYlex();
04322   if (tok!=TK_WHITESPACE)
04323   {
04324     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04325         cmdName.data());
04326     return;
04327   }
04328   doctokenizerYYsetStateFile();
04329   tok=doctokenizerYYlex();
04330   doctokenizerYYsetStatePara();
04331   if (tok==0)
04332   {
04333     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
04334         "argument of command %s",cmdName.data());
04335     return;
04336   }
04337   else if (tok!=TK_WORD)
04338   {
04339     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04340         tokToString(tok),cmdName.data());
04341     return;
04342   }
04343   DocInclude *inc = new DocInclude(this,g_token->name,g_context,t,g_isExample,g_exampleName);
04344   m_children.append(inc);
04345   inc->parse();
04346 }
04347 
04348 void DocPara::handleSection(const QString &cmdName)
04349 {
04350   // get the argument of the section command.
04351   int tok=doctokenizerYYlex();
04352   if (tok!=TK_WHITESPACE)
04353   {
04354     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04355         cmdName.data());
04356     return;
04357   }
04358   tok=doctokenizerYYlex();
04359   if (tok==0)
04360   {
04361     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
04362         "argument of command %s\n", cmdName.data());
04363     return;
04364   }
04365   else if (tok!=TK_WORD && tok!=TK_LNKWORD)
04366   {
04367     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04368         tokToString(tok),cmdName.data());
04369     return;
04370   }
04371   g_token->sectionId = g_token->name;
04372   doctokenizerYYsetStateSkipTitle();
04373   doctokenizerYYlex();
04374   doctokenizerYYsetStatePara();
04375 }
04376 
04377 int DocPara::handleHtmlHeader(const HtmlAttribList &tagHtmlAttribs,int level)
04378 {
04379   DocHtmlHeader *header = new DocHtmlHeader(this,tagHtmlAttribs,level);
04380   m_children.append(header);
04381   int retval = header->parse();
04382   return (retval==RetVal_OK) ? TK_NEWPARA : retval;
04383 }
04384 
04385 // For XML tags whose content is stored in attributes rather than
04386 // contained within the element, we need a way to inject the attribute
04387 // text into the current paragraph.
04388 bool DocPara::injectToken(int tok,const QString &tokText) 
04389 {
04390   g_token->name = tokText;
04391   return defaultHandleToken(this,tok,m_children);
04392 }
04393 
04394 int DocPara::handleStartCode()
04395 {
04396   int retval = doctokenizerYYlex();
04397   // search for the first non-whitespace line, index is stored in li
04398   int i=0,li=0,l=g_token->verb.length();
04399   while (i<l && g_token->verb.at(i)==' ' || g_token->verb.at(i)=='\n')
04400   {
04401     if (g_token->verb.at(i)=='\n') li=i+1;
04402     i++;
04403   }
04404   m_children.append(new DocVerbatim(this,g_context,g_token->verb.mid(li),DocVerbatim::Code,g_isExample,g_exampleName));
04405   if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: code section ended without end marker");
04406   doctokenizerYYsetStatePara();
04407   return retval;
04408 }
04409 
04410 void DocPara::handleInheritDoc()
04411 {
04412   if (g_memberDef) // inheriting docs from a member
04413   {
04414     MemberDef *reMd = g_memberDef->reimplements();
04415     if (reMd) // member from which was inherited.
04416     {
04417       MemberDef *thisMd = g_memberDef;
04418       //printf("{InheritDocs:%s=>%s}\n",g_memberDef->qualifiedName().data(),reMd->qualifiedName().data());
04419       docParserPushContext();
04420       g_context=reMd->getOuterScope()->name();
04421       g_memberDef=reMd;
04422       g_styleStack.clear();
04423       g_nodeStack.clear();
04424       g_copyStack.append(reMd);
04425       internalValidatingParseDoc(this,m_children,reMd->briefDescription());
04426       internalValidatingParseDoc(this,m_children,reMd->documentation());
04427       g_copyStack.remove(reMd);
04428       docParserPopContext(TRUE);
04429       g_memberDef = thisMd;
04430     }
04431   }
04432 }
04433 
04434 
04435 int DocPara::handleCommand(const QString &cmdName)
04436 {
04437   DBG(("handleCommand(%s)\n",cmdName.data()));
04438   int retval = RetVal_OK;
04439   switch (Mappers::cmdMapper->map(cmdName))
04440   {
04441     case CMD_UNKNOWN:
04442       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Found unknown command `\\%s'",cmdName.data());
04443       break;
04444     case CMD_EMPHASIS:
04445       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
04446       retval=handleStyleArgument(this,m_children,cmdName); 
04447       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
04448       if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
04449       break;
04450     case CMD_BOLD:
04451       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
04452       retval=handleStyleArgument(this,m_children,cmdName); 
04453       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
04454       if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
04455       break;
04456     case CMD_CODE:
04457       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,TRUE));
04458       retval=handleStyleArgument(this,m_children,cmdName); 
04459       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Code,FALSE));
04460       if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
04461       break;
04462     case CMD_BSLASH:
04463       m_children.append(new DocSymbol(this,DocSymbol::BSlash));
04464       break;
04465     case CMD_AT:
04466       m_children.append(new DocSymbol(this,DocSymbol::At));
04467       break;
04468     case CMD_LESS:
04469       m_children.append(new DocSymbol(this,DocSymbol::Less));
04470       break;
04471     case CMD_GREATER:
04472       m_children.append(new DocSymbol(this,DocSymbol::Greater));
04473       break;
04474     case CMD_AMP:
04475       m_children.append(new DocSymbol(this,DocSymbol::Amp));
04476       break;
04477     case CMD_DOLLAR:
04478       m_children.append(new DocSymbol(this,DocSymbol::Dollar));
04479       break;
04480     case CMD_HASH:
04481       m_children.append(new DocSymbol(this,DocSymbol::Hash));
04482       break;
04483     case CMD_PERCENT:
04484       m_children.append(new DocSymbol(this,DocSymbol::Percent));
04485       break;
04486     case CMD_SA:
04487       g_inSeeBlock=TRUE;
04488       retval = handleSimpleSection(DocSimpleSect::See);
04489       g_inSeeBlock=FALSE;
04490       break;
04491     case CMD_RETURN:
04492       retval = handleSimpleSection(DocSimpleSect::Return);
04493       g_hasReturnCommand=TRUE;
04494       break;
04495     case CMD_AUTHOR:
04496       retval = handleSimpleSection(DocSimpleSect::Author);
04497       break;
04498     case CMD_AUTHORS:
04499       retval = handleSimpleSection(DocSimpleSect::Authors);
04500       break;
04501     case CMD_VERSION:
04502       retval = handleSimpleSection(DocSimpleSect::Version);
04503       break;
04504     case CMD_SINCE:
04505       retval = handleSimpleSection(DocSimpleSect::Since);
04506       break;
04507     case CMD_DATE:
04508       retval = handleSimpleSection(DocSimpleSect::Date);
04509       break;
04510     case CMD_NOTE:
04511       retval = handleSimpleSection(DocSimpleSect::Note);
04512       break;
04513     case CMD_WARNING:
04514       retval = handleSimpleSection(DocSimpleSect::Warning);
04515       break;
04516     case CMD_PRE:
04517       retval = handleSimpleSection(DocSimpleSect::Pre);
04518       break;
04519     case CMD_POST:
04520       retval = handleSimpleSection(DocSimpleSect::Post);
04521       break;
04522     case CMD_INVARIANT:
04523       retval = handleSimpleSection(DocSimpleSect::Invar);
04524       break;
04525     case CMD_REMARK:
04526       retval = handleSimpleSection(DocSimpleSect::Remark);
04527       break;
04528     case CMD_ATTENTION:
04529       retval = handleSimpleSection(DocSimpleSect::Attention);
04530       break;
04531     case CMD_PAR:
04532       retval = handleSimpleSection(DocSimpleSect::User);
04533       break;
04534     case CMD_LI:
04535       {
04536         DocSimpleList *sl=new DocSimpleList(this);
04537         m_children.append(sl);
04538         retval = sl->parse();
04539       }
04540       break;
04541     case CMD_SECTION:
04542       {
04543         handleSection(cmdName);
04544         retval = RetVal_Section;
04545       }
04546       break;
04547     case CMD_SUBSECTION:
04548       {
04549         handleSection(cmdName);
04550         retval = RetVal_Subsection;
04551       }
04552       break;
04553     case CMD_SUBSUBSECTION:
04554       {
04555         handleSection(cmdName);
04556         retval = RetVal_Subsubsection;
04557       }
04558       break;
04559     case CMD_PARAGRAPH:
04560       {
04561         handleSection(cmdName);
04562         retval = RetVal_Paragraph;
04563       }
04564       break;
04565     case CMD_STARTCODE:
04566       {
04567         doctokenizerYYsetStateCode();
04568         retval = handleStartCode();
04569       }
04570       break;
04571     case CMD_HTMLONLY:
04572       {
04573         doctokenizerYYsetStateHtmlOnly();
04574         retval = doctokenizerYYlex();
04575         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::HtmlOnly,g_isExample,g_exampleName));
04576         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: htmlonly section ended without end marker");
04577         doctokenizerYYsetStatePara();
04578       }
04579       break;
04580     case CMD_MANONLY:
04581       {
04582         doctokenizerYYsetStateManOnly();
04583         retval = doctokenizerYYlex();
04584         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::ManOnly,g_isExample,g_exampleName));
04585         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: manonly section ended without end marker");
04586         doctokenizerYYsetStatePara();
04587       }
04588       break;
04589     case CMD_LATEXONLY:
04590       {
04591         doctokenizerYYsetStateLatexOnly();
04592         retval = doctokenizerYYlex();
04593         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::LatexOnly,g_isExample,g_exampleName));
04594         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: latexonly section ended without end marker");
04595         doctokenizerYYsetStatePara();
04596       }
04597       break;
04598     case CMD_XMLONLY:
04599       {
04600         doctokenizerYYsetStateXmlOnly();
04601         retval = doctokenizerYYlex();
04602         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::XmlOnly,g_isExample,g_exampleName));
04603         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: xmlonly section ended without end marker");
04604         doctokenizerYYsetStatePara();
04605       }
04606       break;
04607     case CMD_VERBATIM:
04608       {
04609         doctokenizerYYsetStateVerbatim();
04610         retval = doctokenizerYYlex();
04611         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Verbatim,g_isExample,g_exampleName));
04612         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: verbatim section ended without end marker");
04613         doctokenizerYYsetStatePara();
04614       }
04615       break;
04616     case CMD_DOT:
04617       {
04618         doctokenizerYYsetStateDot();
04619         retval = doctokenizerYYlex();
04620         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Dot,g_isExample,g_exampleName));
04621         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: dot section ended without end marker");
04622         doctokenizerYYsetStatePara();
04623       }
04624       break;
04625     case CMD_MSC:
04626       {
04627         doctokenizerYYsetStateMsc();
04628         retval = doctokenizerYYlex();
04629         m_children.append(new DocVerbatim(this,g_context,g_token->verb,DocVerbatim::Msc,g_isExample,g_exampleName));
04630         if (retval==0) warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: msc section ended without end marker");
04631         doctokenizerYYsetStatePara();
04632       }
04633       break;
04634     case CMD_ENDCODE:
04635     case CMD_ENDHTMLONLY:
04636     case CMD_ENDMANONLY:
04637     case CMD_ENDLATEXONLY:
04638     case CMD_ENDXMLONLY:
04639     case CMD_ENDLINK:
04640     case CMD_ENDVERBATIM:
04641     case CMD_ENDDOT:
04642       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
04643       break; 
04644     case CMD_ENDMSC:
04645       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
04646       break; 
04647     case CMD_PARAM:
04648       retval = handleParamSection(cmdName,DocParamSect::Param,FALSE,g_token->paramDir);
04649       break;
04650     case CMD_TPARAM:
04651       retval = handleParamSection(cmdName,DocParamSect::TemplateParam,FALSE,g_token->paramDir);
04652       break;
04653     case CMD_RETVAL:
04654       retval = handleParamSection(cmdName,DocParamSect::RetVal);
04655       break;
04656     case CMD_EXCEPTION:
04657       retval = handleParamSection(cmdName,DocParamSect::Exception);
04658       break;
04659     case CMD_XREFITEM:
04660       retval = handleXRefItem();
04661       break;
04662     case CMD_LINEBREAK:
04663       {
04664         DocLineBreak *lb = new DocLineBreak(this);
04665         m_children.append(lb);
04666       }
04667       break;
04668     case CMD_ANCHOR:
04669       {
04670         int tok=doctokenizerYYlex();
04671         if (tok!=TK_WHITESPACE)
04672         {
04673           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04674               cmdName.data());
04675           break;
04676         }
04677         tok=doctokenizerYYlex();
04678         if (tok==0)
04679         {
04680           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
04681               "argument of command %s",cmdName.data());
04682           break;
04683         }
04684         else if (tok!=TK_WORD && tok!=TK_LNKWORD)
04685         {
04686           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04687               tokToString(tok),cmdName.data());
04688           break;
04689         }
04690         DocAnchor *anchor = new DocAnchor(this,g_token->name,FALSE);
04691         m_children.append(anchor);
04692       }
04693       break;
04694     case CMD_ADDINDEX:
04695       {
04696         DocIndexEntry *ie = new DocIndexEntry(this);
04697         m_children.append(ie);
04698         retval = ie->parse();
04699       }
04700       break;
04701     case CMD_INTERNAL:
04702       retval = RetVal_Internal;
04703       break;
04704     case CMD_COPYDOC:
04705       {
04706         int tok=doctokenizerYYlex();
04707         if (tok!=TK_WHITESPACE)
04708         {
04709           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: expected whitespace after %s command",
04710               cmdName.data());
04711           break;
04712         }
04713         tok=doctokenizerYYlex();
04714         if (tok==0)
04715         {
04716           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected end of comment block while parsing the "
04717               "argument of command %s\n", cmdName.data());
04718           break;
04719         }
04720         else if (tok!=TK_WORD && tok!=TK_LNKWORD)
04721         {
04722           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected token %s as the argument of %s",
04723               tokToString(tok),cmdName.data());
04724           break;
04725         }
04726         DocCopy *cpy = new DocCopy(this,g_token->name);
04727         m_children.append(cpy);
04728         cpy->parse();
04729       }
04730       break;
04731     case CMD_INCLUDE:
04732       handleInclude(cmdName,DocInclude::Include);
04733       break;
04734     case CMD_INCWITHLINES:
04735       handleInclude(cmdName,DocInclude::IncWithLines);
04736       break;
04737     case CMD_DONTINCLUDE:
04738       handleInclude(cmdName,DocInclude::DontInclude);
04739       break;
04740     case CMD_HTMLINCLUDE:
04741       handleInclude(cmdName,DocInclude::HtmlInclude);
04742       break;
04743     case CMD_VERBINCLUDE:
04744       handleInclude(cmdName,DocInclude::VerbInclude);
04745       break;
04746     case CMD_SKIP:
04747       handleIncludeOperator(cmdName,DocIncOperator::Skip);
04748       break;
04749     case CMD_UNTIL:
04750       handleIncludeOperator(cmdName,DocIncOperator::Until);
04751       break;
04752     case CMD_SKIPLINE:
04753       handleIncludeOperator(cmdName,DocIncOperator::SkipLine);
04754       break;
04755     case CMD_LINE:
04756       handleIncludeOperator(cmdName,DocIncOperator::Line);
04757       break;
04758     case CMD_IMAGE:
04759       handleImage(cmdName);
04760       break;
04761     case CMD_DOTFILE:
04762       handleDotFile(cmdName);
04763       break;
04764     case CMD_LINK:
04765       handleLink(cmdName,FALSE);
04766       break;
04767     case CMD_JAVALINK:
04768       handleLink(cmdName,TRUE);
04769       break;
04770     case CMD_REF: // fall through
04771     case CMD_SUBPAGE:
04772       handleRef(cmdName);
04773       break;
04774     case CMD_SECREFLIST:
04775       {
04776         DocSecRefList *list = new DocSecRefList(this);
04777         m_children.append(list);
04778         list->parse();
04779       }
04780       break;
04781     case CMD_SECREFITEM:
04782       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
04783       break;
04784     case CMD_ENDSECREFLIST:
04785       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
04786       break;
04787     case CMD_FORMULA:
04788       {
04789         DocFormula *form=new DocFormula(this,g_token->id);
04790         m_children.append(form);
04791       }
04792       break;
04793     //case CMD_LANGSWITCH:
04794     //  retval = handleLanguageSwitch();
04795     //  break;
04796     case CMD_INTERNALREF:
04797       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: unexpected command %s",g_token->name.data());
04798       break;
04799     case CMD_INHERITDOC:
04800       handleInheritDoc();
04801       break;
04802     default:
04803       // we should not get here!
04804       ASSERT(0);
04805       break;
04806   }
04807   INTERNAL_ASSERT(retval==0 || retval==RetVal_OK || retval==RetVal_SimpleSec || 
04808          retval==TK_LISTITEM || retval==TK_ENDLIST || retval==TK_NEWPARA ||
04809          retval==RetVal_Section || retval==RetVal_EndList || 
04810          retval==RetVal_Internal || retval==RetVal_SwitchLang
04811         );
04812   DBG(("handleCommand(%s) end retval=%x\n",cmdName.data(),retval));
04813   return retval;
04814 }
04815 
04816 static bool findAttribute(const HtmlAttribList &tagHtmlAttribs, 
04817                           const char *attrName, 
04818                           QString *result) 
04819 {
04820 
04821   HtmlAttribListIterator li(tagHtmlAttribs);
04822   HtmlAttrib *opt;
04823   for (li.toFirst();(opt=li.current());++li)
04824   {
04825     if (opt->name==attrName) 
04826     {
04827       *result = opt->value;
04828       return TRUE;
04829     }
04830   }
04831   return FALSE;
04832 }
04833 
04834 int DocPara::handleHtmlStartTag(const QString &tagName,const HtmlAttribList &tagHtmlAttribs)
04835 {
04836   DBG(("handleHtmlStartTag(%s,%d)\n",tagName.data(),tagHtmlAttribs.count()));
04837   int retval=RetVal_OK;
04838   int tagId = Mappers::htmlTagMapper->map(tagName);
04839   if (g_token->emptyTag && !(tagId&XML_CmdMask) && tagId!=HTML_UNKNOWN)
04840       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: HTML tags may not use the 'empty tag' XHTML syntax.");
04841   switch (tagId)
04842   {
04843     case HTML_UL: 
04844       {
04845         DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Unordered);
04846         m_children.append(list);
04847         retval=list->parse();
04848       }
04849       break;
04850     case HTML_OL: 
04851       {
04852         DocHtmlList *list = new DocHtmlList(this,tagHtmlAttribs,DocHtmlList::Ordered);
04853         m_children.append(list);
04854         retval=list->parse();
04855       }
04856       break;
04857     case HTML_LI:
04858       if (!insideUL(this) && !insideOL(this))
04859       {
04860         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: lonely <li> tag found");
04861       }
04862       else
04863       {
04864         retval=RetVal_ListItem;
04865       }
04866       break;
04867     case HTML_BOLD:
04868       handleStyleEnter(this,m_children,DocStyleChange::Bold,&g_token->attribs);
04869       break;
04870     case HTML_CODE:
04871       if (g_fileName.right(3)==".cs") 
04872         // for C# code we treat <code> as an XML tag
04873       {
04874         doctokenizerYYsetStateXmlCode();
04875         retval = handleStartCode();
04876       }
04877       else // normal HTML markup
04878       {
04879         handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
04880       }
04881       break;
04882     case HTML_EMPHASIS:
04883       handleStyleEnter(this,m_children,DocStyleChange::Italic,&g_token->attribs);
04884       break;
04885     case HTML_DIV:
04886       handleStyleEnter(this,m_children,DocStyleChange::Div,&g_token->attribs);
04887       break;
04888     case HTML_SPAN:
04889       handleStyleEnter(this,m_children,DocStyleChange::Span,&g_token->attribs);
04890       break;
04891     case HTML_SUB:
04892       handleStyleEnter(this,m_children,DocStyleChange::Subscript,&g_token->attribs);
04893       break;
04894     case HTML_SUP:
04895       handleStyleEnter(this,m_children,DocStyleChange::Superscript,&g_token->attribs);
04896       break;
04897     case HTML_CENTER:
04898       handleStyleEnter(this,m_children,DocStyleChange::Center,&g_token->attribs);
04899       break;
04900     case HTML_SMALL:
04901       handleStyleEnter(this,m_children,DocStyleChange::Small,&g_token->attribs);
04902       break;
04903     case HTML_PRE:
04904       handleStyleEnter(this,m_children,DocStyleChange::Preformatted,&g_token->attribs);
04905       setInsidePreformatted(TRUE);
04906       //doctokenizerYYsetInsidePre(TRUE);
04907       break;
04908     case HTML_P:
04909       retval=TK_NEWPARA;
04910       break;
04911     case HTML_DL:
04912       {
04913         DocHtmlDescList *list = new DocHtmlDescList(this,tagHtmlAttribs);
04914         m_children.append(list);
04915         retval=list->parse();
04916       }
04917       break;
04918     case HTML_DT:
04919       retval = RetVal_DescTitle;
04920       break;
04921     case HTML_DD:
04922       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag <dd> found");
04923       break;
04924     case HTML_TABLE:
04925       {
04926         DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
04927         m_children.append(table);
04928         retval=table->parse();
04929       }
04930       break;
04931     case HTML_TR:
04932       retval = RetVal_TableRow;
04933       break;
04934     case HTML_TD:
04935       retval = RetVal_TableCell;
04936       break;
04937     case HTML_TH:
04938       retval = RetVal_TableHCell;
04939       break;
04940     case HTML_CAPTION:
04941       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag <caption> found");
04942       break;
04943     case HTML_BR:
04944       {
04945         DocLineBreak *lb = new DocLineBreak(this);
04946         m_children.append(lb);
04947       }
04948       break;
04949     case HTML_HR:
04950       {
04951         DocHorRuler *hr = new DocHorRuler(this);
04952         m_children.append(hr);
04953       }
04954       break;
04955     case HTML_A:
04956       retval=handleAHref(this,m_children,tagHtmlAttribs);
04957       break;
04958     case HTML_H1:
04959       retval=handleHtmlHeader(tagHtmlAttribs,1);
04960       break;
04961     case HTML_H2:
04962       retval=handleHtmlHeader(tagHtmlAttribs,2);
04963       break;
04964     case HTML_H3:
04965       retval=handleHtmlHeader(tagHtmlAttribs,3);
04966       break;
04967     case HTML_H4:
04968       retval=handleHtmlHeader(tagHtmlAttribs,4);
04969       break;
04970     case HTML_H5:
04971       retval=handleHtmlHeader(tagHtmlAttribs,5);
04972       break;
04973     case HTML_H6:
04974       retval=handleHtmlHeader(tagHtmlAttribs,6);
04975       break;
04976     case HTML_IMG:
04977       {
04978         HtmlAttribListIterator li(tagHtmlAttribs);
04979         HtmlAttrib *opt;
04980         bool found=FALSE;
04981         int index=0;
04982         for (li.toFirst();(opt=li.current());++li,++index)
04983         {
04984           //printf("option name=%s value=%s\n",opt->name.data(),opt->value.data());
04985           if (opt->name=="src" && !opt->value.isEmpty())
04986           {
04987             // copy attributes
04988             HtmlAttribList attrList = tagHtmlAttribs;
04989             // and remove the href attribute
04990             bool result = attrList.remove(index);
04991             ASSERT(result);
04992             DocImage *img = new DocImage(this,attrList,opt->value,DocImage::Html);
04993             m_children.append(img);
04994             found = TRUE;
04995           }
04996         }
04997         if (!found)
04998         {
04999           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: IMG tag does not have a SRC attribute!\n");
05000         }
05001       }
05002       break;
05003 
05004     case XML_SUMMARY:
05005     case XML_REMARKS:
05006     case XML_VALUE:
05007     case XML_PARA:
05008       if (!m_children.isEmpty())
05009       {
05010         retval = TK_NEWPARA;
05011       }
05012       break;
05013     case XML_EXAMPLE:
05014     case XML_DESCRIPTION:
05015       if (insideTable(this))
05016       {
05017         retval=RetVal_TableCell;
05018       }
05019       break;
05020     case XML_C:
05021       handleStyleEnter(this,m_children,DocStyleChange::Code,&g_token->attribs);
05022       break;
05023     case XML_PARAM:
05024     case XML_TYPEPARAM:
05025       {
05026         QString paramName;
05027         if (findAttribute(tagHtmlAttribs,"name",&paramName))
05028         {
05029           retval = handleParamSection(paramName,
05030               tagId==XML_PARAM ? DocParamSect::Param : DocParamSect::TemplateParam,
05031               TRUE);
05032         }
05033         else
05034         {
05035           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <param> tag.");
05036         }
05037       }
05038       break;
05039     case XML_PARAMREF:
05040     case XML_TYPEPARAMREF:
05041       {
05042         QString paramName;
05043         if (findAttribute(tagHtmlAttribs,"name",&paramName))
05044         {
05045           //printf("paramName=%s\n",paramName.data());
05046           m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,TRUE));
05047           m_children.append(new DocWord(this,paramName)); 
05048           m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Italic,FALSE));
05049           if (retval!=TK_WORD) m_children.append(new DocWhiteSpace(this," "));
05050         }
05051         else
05052         {
05053           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <param%sref> tag.",tagId==XML_PARAMREF?"":"type");
05054         }
05055       }
05056       break;
05057     case XML_EXCEPTION:
05058       {
05059         QString exceptName;
05060         if (findAttribute(tagHtmlAttribs,"cref",&exceptName))
05061         {
05062           retval = handleParamSection(exceptName,DocParamSect::Exception,TRUE);
05063         }
05064         else
05065         {
05066           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'name' attribute from <exception> tag.");
05067         }
05068       }
05069       break;
05070     case XML_ITEM:
05071     case XML_LISTHEADER:
05072       if (insideTable(this))
05073       {
05074         retval=RetVal_TableRow;
05075       }
05076       else if (insideUL(this) || insideOL(this))
05077       {
05078         retval=RetVal_ListItem;
05079       }
05080       else
05081       {
05082         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: lonely <item> tag found");
05083       }
05084       break;
05085     case XML_RETURNS:
05086       retval = handleSimpleSection(DocSimpleSect::Return,TRUE);
05087       g_hasReturnCommand=TRUE;
05088       break;
05089     case XML_TERM:
05090       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,TRUE));
05091       if (insideTable(this))
05092       {
05093         retval=RetVal_TableCell;
05094       }
05095       break;
05096     case XML_SEE:
05097       // I'm not sure if <see> is the same as <seealso> or if it
05098       // should you link a member without producing a section. The
05099       // C# specification is extremely vague about this (but what else 
05100       // can we expect from Microsoft...)
05101       {
05102         QString cref;
05103         //printf("XML_SEE: empty tag=%d\n",g_token->emptyTag);
05104         if (findAttribute(tagHtmlAttribs,"cref",&cref))
05105         {
05106           if (g_token->emptyTag) // <see cref="..."/> style
05107           {
05108             bool inSeeBlock = g_inSeeBlock;
05109             g_token->name = cref;
05110             g_inSeeBlock = TRUE;
05111             handleLinkedWord(this,m_children);
05112             g_inSeeBlock = inSeeBlock;
05113           }
05114           else // <see cref="...">...</see> style
05115           {
05116             //DocRef *ref = new DocRef(this,cref);
05117             //m_children.append(ref);
05118             //ref->parse();
05119             doctokenizerYYsetStatePara();
05120             DocLink *lnk = new DocLink(this,cref);
05121             m_children.append(lnk);
05122             QString leftOver = lnk->parse(FALSE,TRUE);
05123             if (!leftOver.isEmpty())
05124             {
05125               m_children.append(new DocWord(this,leftOver));
05126             }
05127           }
05128         }
05129         else
05130         {
05131           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'cref' attribute from <see> tag.");
05132         }
05133       }
05134       break;
05135     case XML_SEEALSO:
05136       {
05137         QString cref;
05138         if (findAttribute(tagHtmlAttribs,"cref",&cref))
05139         {
05140           // Look for an existing "see" section
05141           DocSimpleSect *ss=0;
05142           QListIterator<DocNode> cli(m_children);
05143           DocNode *n;
05144           for (cli.toFirst();(n=cli.current());++cli)
05145           {
05146             if (n->kind()==Kind_SimpleSect && ((DocSimpleSect *)n)->type()==DocSimpleSect::See)
05147             {
05148               ss = (DocSimpleSect *)n;
05149             }
05150           }
05151   
05152           if (!ss)  // start new section
05153           {
05154             ss=new DocSimpleSect(this,DocSimpleSect::See);
05155             m_children.append(ss);
05156           }
05157           
05158           ss->appendLinkWord(cref);
05159           retval = RetVal_OK;
05160         }
05161         else
05162         {
05163           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Missing 'cref' attribute from <seealso> tag.");
05164         }
05165       }
05166       break;
05167     case XML_LIST:
05168       {
05169         QString type;
05170         findAttribute(tagHtmlAttribs,"type",&type);
05171         DocHtmlList::Type listType = DocHtmlList::Unordered;
05172         if (type=="number")
05173         {
05174           listType=DocHtmlList::Ordered;
05175         }
05176         if (type=="table")
05177         {
05178           DocHtmlTable *table = new DocHtmlTable(this,tagHtmlAttribs);
05179           m_children.append(table);
05180           retval=table->parseXml();
05181         }
05182         else
05183         {
05184           HtmlAttribList emptyList;
05185           DocHtmlList *list = new DocHtmlList(this,emptyList,listType);
05186           m_children.append(list);
05187           retval=list->parseXml();
05188         }
05189       }
05190       break;
05191     case XML_INCLUDE:
05192     case XML_PERMISSION:
05193       // These tags are defined in .Net but are currently unsupported
05194       break;
05195     case HTML_UNKNOWN:
05196       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported xml/html tag <%s> found", tagName.data());
05197       m_children.append(new DocWord(this, "<"+tagName+tagHtmlAttribs.toString()+">"));
05198       break;
05199     default:
05200       // we should not get here!
05201       ASSERT(0);
05202       break;
05203   }
05204   return retval;
05205 }
05206 
05207 int DocPara::handleHtmlEndTag(const QString &tagName)
05208 {
05209   DBG(("handleHtmlEndTag(%s)\n",tagName.data()));
05210   int tagId = Mappers::htmlTagMapper->map(tagName);
05211   int retval=RetVal_OK;
05212   switch (tagId)
05213   {
05214     case HTML_UL: 
05215       if (!insideUL(this))
05216       {
05217         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </ul> tag without matching <ul>");
05218       }
05219       else
05220       {
05221         retval=RetVal_EndList;
05222       }
05223       break;
05224     case HTML_OL: 
05225       if (!insideOL(this))
05226       {
05227         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </ol> tag without matching <ol>");
05228       }
05229       else
05230       {
05231         retval=RetVal_EndList;
05232       }
05233       break;
05234     case HTML_LI:
05235       if (!insideLI(this))
05236       {
05237         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </li> tag without matching <li>");
05238       }
05239       else
05240       {
05241         // ignore </li> tags
05242       }
05243       break;
05244     //case HTML_PRE:
05245     //  if (!insidePRE(this))
05246     //  {
05247     //    warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found </pre> tag without matching <pre>");
05248     //  }
05249     //  else
05250     //  {
05251     //    retval=RetVal_EndPre;
05252     //  }
05253     //  break;
05254     case HTML_BOLD:
05255       handleStyleLeave(this,m_children,DocStyleChange::Bold,"b");
05256       break;
05257     case HTML_CODE:
05258       handleStyleLeave(this,m_children,DocStyleChange::Code,"code");
05259       break;
05260     case HTML_EMPHASIS:
05261       handleStyleLeave(this,m_children,DocStyleChange::Italic,"em");
05262       break;
05263     case HTML_DIV:
05264       handleStyleLeave(this,m_children,DocStyleChange::Div,"div");
05265       break;
05266     case HTML_SPAN:
05267       handleStyleLeave(this,m_children,DocStyleChange::Span,"span");
05268       break;
05269     case HTML_SUB:
05270       handleStyleLeave(this,m_children,DocStyleChange::Subscript,"sub");
05271       break;
05272     case HTML_SUP:
05273       handleStyleLeave(this,m_children,DocStyleChange::Superscript,"sup");
05274       break;
05275     case HTML_CENTER:
05276       handleStyleLeave(this,m_children,DocStyleChange::Center,"center");
05277       break;
05278     case HTML_SMALL:
05279       handleStyleLeave(this,m_children,DocStyleChange::Small,"small");
05280       break;
05281     case HTML_PRE:
05282       handleStyleLeave(this,m_children,DocStyleChange::Preformatted,"pre");
05283       setInsidePreformatted(FALSE);
05284       //doctokenizerYYsetInsidePre(FALSE);
05285       break;
05286     case HTML_P:
05287       // ignore </p> tag
05288       break;
05289     case HTML_DL:
05290       retval=RetVal_EndDesc;
05291       break;
05292     case HTML_DT:
05293       // ignore </dt> tag
05294       break;
05295     case HTML_DD:
05296       // ignore </dd> tag
05297       break;
05298     case HTML_TABLE:
05299       retval=RetVal_EndTable;
05300       break;
05301     case HTML_TR:
05302       // ignore </tr> tag
05303       break;
05304     case HTML_TD:
05305       // ignore </td> tag
05306       break;
05307     case HTML_TH:
05308       // ignore </th> tag
05309       break;
05310     case HTML_CAPTION:
05311       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </caption> found");
05312       break;
05313     case HTML_BR:
05314       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Illegal </br> tag found\n");
05315       break;
05316     case HTML_H1:
05317       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </h1> found");
05318       break;
05319     case HTML_H2:
05320       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </h2> found");
05321       break;
05322     case HTML_H3:
05323       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </h3> found");
05324       break;
05325     case HTML_IMG:
05326       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </img> found");
05327       break;
05328     case HTML_HR:
05329       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </hr> found");
05330       break;
05331     case HTML_A:
05332       //warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected tag </a> found");
05333       // ignore </a> tag (can be part of <a name=...></a>
05334       break;
05335 
05336     case XML_TERM:
05337       m_children.append(new DocStyleChange(this,g_nodeStack.count(),DocStyleChange::Bold,FALSE));
05338       break;
05339     case XML_SUMMARY:
05340     case XML_REMARKS:
05341     case XML_PARA:
05342     case XML_VALUE:
05343     case XML_LIST:
05344     case XML_EXAMPLE:
05345     case XML_PARAM:
05346     case XML_TYPEPARAM:
05347     case XML_RETURNS:
05348     case XML_SEEALSO:
05349     case XML_EXCEPTION:
05350       retval = RetVal_CloseXml;
05351       break;
05352     case XML_C:
05353       handleStyleLeave(this,m_children,DocStyleChange::Code,"c");
05354       break;
05355     case XML_ITEM:
05356     case XML_LISTHEADER:
05357     case XML_INCLUDE:
05358     case XML_PERMISSION:
05359     case XML_DESCRIPTION:
05360     case XML_PARAMREF:
05361     case XML_TYPEPARAMREF:
05362       // These tags are defined in .Net but are currently unsupported
05363       break;
05364     case HTML_UNKNOWN:
05365       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported xml/html tag </%s> found", tagName.data());
05366       m_children.append(new DocWord(this,"</"+tagName+">"));
05367       break;
05368     default:
05369       // we should not get here!
05370       warn_doc_error(g_fileName,doctokenizerYYlineno,"Unexpected end tag %s\n",tagName.data());
05371       ASSERT(0);
05372       break;
05373   }
05374   return retval;
05375 }
05376 
05377 int DocPara::parse()
05378 {
05379   DBG(("DocPara::parse() start\n"));
05380   g_nodeStack.push(this);
05381   // handle style commands "inherited" from the previous paragraph
05382   handleInitialStyleCommands(this,m_children);
05383   int tok;
05384   int retval=0;
05385   while ((tok=doctokenizerYYlex())) // get the next token
05386   {
05387 reparsetoken:
05388     DBG(("token %s at %d",tokToString(tok),doctokenizerYYlineno));
05389     if (tok==TK_WORD || tok==TK_LNKWORD || tok==TK_SYMBOL || tok==TK_URL || 
05390         tok==TK_COMMAND || tok==TK_HTMLTAG
05391        )
05392     {
05393       DBG((" name=%s",g_token->name.data()));
05394     }
05395     DBG(("\n"));
05396     switch(tok)
05397     {
05398       case TK_WORD:        
05399         m_children.append(new DocWord(this,g_token->name));
05400         break;
05401       case TK_LNKWORD:        
05402         handleLinkedWord(this,m_children);
05403         break;
05404       case TK_URL:
05405         m_children.append(new DocURL(this,g_token->name,g_token->isEMailAddr));
05406         break;
05407       case TK_WHITESPACE:  
05408         {
05409           // prevent leading whitespace and collapse multiple whitespace areas
05410           DocNode::Kind k; 
05411           if (insidePRE(this) || // all whitespace is relevant
05412               (                
05413                // remove leading whitespace 
05414                !m_children.isEmpty()  && 
05415                // and whitespace after certain constructs
05416                (k=m_children.last()->kind())!=DocNode::Kind_HtmlDescList &&
05417                k!=DocNode::Kind_HtmlTable &&
05418                k!=DocNode::Kind_HtmlList &&
05419                k!=DocNode::Kind_SimpleSect &&
05420                k!=DocNode::Kind_AutoList &&
05421                k!=DocNode::Kind_SimpleList &&
05422                /*k!=DocNode::Kind_Verbatim &&*/
05423                k!=DocNode::Kind_HtmlHeader &&
05424                k!=DocNode::Kind_ParamSect &&
05425                k!=DocNode::Kind_XRefItem
05426               )
05427              )
05428           {
05429             m_children.append(new DocWhiteSpace(this,g_token->chars));
05430           }
05431         }
05432         break;
05433       case TK_LISTITEM:    
05434         {
05435           DBG(("found list item at %d parent=%d\n",g_token->indent,parent()->kind()));
05436           DocNode *n=parent();
05437           while (n && n->kind()!=DocNode::Kind_AutoList) n=n->parent();
05438           if (n) // we found an auto list up in the hierarchy
05439           {
05440             DocAutoList *al = (DocAutoList *)n;
05441             DBG(("previous list item at %d\n",al->indent()));
05442             if (al->indent()>=g_token->indent) 
05443               // new item at the same or lower indent level
05444             {
05445               retval=TK_LISTITEM;
05446               goto endparagraph;
05447             }
05448           }
05449 
05450           // determine list depth
05451           int depth = 0;
05452           n=parent();
05453           while(n) {
05454             if(n->kind() == DocNode::Kind_AutoList) ++depth;
05455             n=n->parent();
05456           }
05457 
05458           // first item or sub list => create new list
05459           DocAutoList *al=0;
05460           do
05461           {
05462             al = new DocAutoList(this,g_token->indent,g_token->isEnumList,
05463                                  depth);
05464             m_children.append(al);
05465             retval = al->parse();
05466           } while (retval==TK_LISTITEM &&         // new list
05467                    al->indent()==g_token->indent  // at same indent level
05468                   );
05469               
05470           // check the return value
05471           if (retval==RetVal_SimpleSec) // auto list ended due to simple section command
05472           {
05473             // Reparse the token that ended the section at this level,
05474             // so a new simple section will be started at this level.
05475             // This is the same as unputting the last read token and continuing.
05476             g_token->name = g_token->simpleSectName;
05477             if (g_token->name.left(4)=="rcs:") // RCS section
05478             {
05479               g_token->name = g_token->name.mid(4);
05480               g_token->text = g_token->simpleSectText;
05481               tok = TK_RCSTAG;
05482             }
05483             else // other section
05484             {
05485               tok = TK_COMMAND;
05486             }
05487             DBG(("reparsing command %s\n",g_token->name.data()));
05488             goto reparsetoken;
05489           }
05490           else if (retval==TK_ENDLIST)
05491           {
05492             if (al->indent()>g_token->indent) // end list
05493             {
05494               goto endparagraph;
05495             }
05496             else // continue with current paragraph
05497             {
05498             }
05499           }
05500           else // paragraph ended due to TK_NEWPARA, TK_LISTITEM, or EOF
05501           {
05502             goto endparagraph;
05503           }
05504         }
05505         break;
05506       case TK_ENDLIST:     
05507         DBG(("Found end of list inside of paragraph at line %d\n",doctokenizerYYlineno));
05508         if (parent()->kind()==DocNode::Kind_AutoListItem)
05509         {
05510           ASSERT(parent()->parent()->kind()==DocNode::Kind_AutoList);
05511           DocAutoList *al = (DocAutoList *)parent()->parent();
05512           if (al->indent()>=g_token->indent)
05513           {
05514             // end of list marker ends this paragraph
05515             retval=TK_ENDLIST;
05516             goto endparagraph;
05517           }
05518           else
05519           {
05520             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: End of list marker found "
05521                    "has invalid indent level");
05522           }
05523         }
05524         else
05525         {
05526           warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: End of list marker found without any preceding "
05527                  "list items");
05528         }
05529         break;
05530       case TK_COMMAND:    
05531         {
05532           // see if we have to start a simple section
05533           int cmd = Mappers::cmdMapper->map(g_token->name);
05534           DocNode *n=parent();
05535           while (n && 
05536                  n->kind()!=DocNode::Kind_SimpleSect && 
05537                  n->kind()!=DocNode::Kind_ParamSect
05538                 ) 
05539           {
05540             n=n->parent();
05541           }
05542           if (cmd&SIMPLESECT_BIT)
05543           {
05544             if (n)  // already in a simple section
05545             {
05546               // simple section cannot start in this paragraph, need
05547               // to unwind the stack and remember the command.
05548               g_token->simpleSectName = g_token->name.copy();
05549               retval=RetVal_SimpleSec;
05550               goto endparagraph;
05551             }
05552           }
05553           // see if we are in a simple list
05554           n=parent();
05555           while (n && n->kind()!=DocNode::Kind_SimpleListItem) n=n->parent();
05556           if (n)
05557           {
05558             if (cmd==CMD_LI)
05559             {
05560               retval=RetVal_ListItem;
05561               goto endparagraph;
05562             }
05563           }
05564           
05565           // handle the command
05566           retval=handleCommand(g_token->name.copy());
05567           DBG(("handleCommand returns %x\n",retval));
05568 
05569           // check the return value
05570           if (retval==RetVal_SimpleSec)
05571           {
05572             // Reparse the token that ended the section at this level,
05573             // so a new simple section will be started at this level.
05574             // This is the same as unputting the last read token and continuing.
05575             g_token->name = g_token->simpleSectName;
05576             if (g_token->name.left(4)=="rcs:") // RCS section
05577             {
05578               g_token->name = g_token->name.mid(4);
05579               g_token->text = g_token->simpleSectText;
05580               tok = TK_RCSTAG;
05581             }
05582             else // other section
05583             {
05584               tok = TK_COMMAND;
05585             }
05586             DBG(("reparsing command %s\n",g_token->name.data()));
05587             goto reparsetoken;
05588           }
05589           else if (retval==RetVal_OK) 
05590           {
05591             // the command ended normally, keep scanning for new tokens.
05592             retval = 0;
05593           }
05594           else if (retval>0 && retval<RetVal_OK)
05595           { 
05596             // the command ended with a new command, reparse this token
05597             tok = retval;
05598             goto reparsetoken;
05599           }
05600           else // end of file, end of paragraph, start or end of section 
05601                // or some auto list marker
05602           {
05603             goto endparagraph;
05604           }
05605         }
05606         break;
05607       case TK_HTMLTAG:    
05608         {
05609           if (!g_token->endTag) // found a start tag
05610           {
05611             retval = handleHtmlStartTag(g_token->name,g_token->attribs);
05612           }
05613           else // found an end tag
05614           {
05615             retval = handleHtmlEndTag(g_token->name);
05616           }
05617           if (retval==RetVal_OK) 
05618           {
05619             // the command ended normally, keep scanner for new tokens.
05620             retval = 0;
05621           }
05622           else
05623           {
05624             goto endparagraph;
05625           }
05626         }
05627         break;
05628       case TK_SYMBOL:     
05629         {
05630           char letter='\0';
05631           DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
05632           if (s!=DocSymbol::Unknown)
05633           {
05634             m_children.append(new DocSymbol(this,s,letter));
05635           }
05636           else
05637           {
05638             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
05639                 g_token->name.data());
05640           }
05641           break;
05642         }
05643       case TK_NEWPARA:     
05644         retval=TK_NEWPARA;
05645         goto endparagraph;
05646       case TK_RCSTAG:
05647         {
05648           DocNode *n=parent();
05649           while (n && 
05650                  n->kind()!=DocNode::Kind_SimpleSect && 
05651                  n->kind()!=DocNode::Kind_ParamSect
05652                 ) 
05653           {
05654             n=n->parent();
05655           }
05656           if (n)  // already in a simple section
05657           {
05658             // simple section cannot start in this paragraph, need
05659             // to unwind the stack and remember the command.
05660             g_token->simpleSectName = "rcs:"+g_token->name;
05661             g_token->simpleSectText = g_token->text;
05662             retval=RetVal_SimpleSec;
05663             goto endparagraph;
05664           }
05665 
05666           // see if we are in a simple list
05667           DocSimpleSect *ss=new DocSimpleSect(this,DocSimpleSect::Rcs);
05668           m_children.append(ss);
05669           ss->parseRcs();
05670         }
05671         break;
05672       default:
05673         warn_doc_error(g_fileName,doctokenizerYYlineno,
05674             "Warning: Found unexpected token (id=%x)\n",tok);
05675         break;
05676     }
05677   }
05678   retval=0;
05679 endparagraph:
05680   handlePendingStyleCommands(this,m_children);
05681   DocNode *n = g_nodeStack.pop();
05682   ASSERT(n==this);
05683   DBG(("DocPara::parse() end retval=%x\n",retval));
05684   INTERNAL_ASSERT(retval==0 || retval==TK_NEWPARA || retval==TK_LISTITEM || 
05685          retval==TK_ENDLIST || retval>RetVal_OK 
05686         );
05687 
05688   return retval; 
05689 }
05690 
05691 //--------------------------------------------------------------------------
05692 
05693 int DocSection::parse()
05694 {
05695   DBG(("DocSection::parse() start %s level=%d\n",g_token->sectionId.data(),m_level));
05696   int retval=RetVal_OK;
05697   g_nodeStack.push(this);
05698 
05699   SectionInfo *sec;
05700   if (!m_id.isEmpty())
05701   {
05702     sec=Doxygen::sectionDict[m_id];
05703     if (sec)
05704     {
05705       m_file   = sec->fileName;
05706       m_anchor = sec->label;
05707       m_title  = sec->title;
05708       if (m_title.isEmpty()) m_title = sec->label;
05709       if (g_sectionDict && g_sectionDict->find(m_id)==0)
05710       {
05711         g_sectionDict->insert(m_id,sec);
05712       }
05713     }
05714   }
05715 
05716   // first parse any number of paragraphs
05717   bool isFirst=TRUE;
05718   DocPara *lastPar=0;
05719   do
05720   {
05721     DocPara *par = new DocPara(this);
05722     if (isFirst) { par->markFirst(); isFirst=FALSE; }
05723     retval=par->parse();
05724     if (!par->isEmpty()) 
05725     {
05726       m_children.append(par);
05727       lastPar=par;
05728     }
05729     else
05730     {
05731       delete par;
05732     }
05733     if (retval==TK_LISTITEM)
05734     {
05735       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid list item found");
05736     }
05737   } while (retval!=0 && 
05738            retval!=RetVal_Internal      &&
05739            retval!=RetVal_Section       &&
05740            retval!=RetVal_Subsection    &&
05741            retval!=RetVal_Subsubsection &&
05742            retval!=RetVal_Paragraph    
05743           );
05744 
05745   if (lastPar) lastPar->markLast();
05746 
05747   if (retval==RetVal_Subsection && m_level==1)
05748   {
05749     // then parse any number of nested sections
05750     while (retval==RetVal_Subsection) // more sections follow
05751     {
05752       //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
05753       DocSection *s=new DocSection(this,2,g_token->sectionId);
05754       m_children.append(s);
05755       retval = s->parse();
05756     }
05757   }
05758   else if (retval==RetVal_Subsubsection && m_level==2)
05759   {
05760     // then parse any number of nested sections
05761     while (retval==RetVal_Subsubsection) // more sections follow
05762     {
05763       //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
05764       DocSection *s=new DocSection(this,3,g_token->sectionId);
05765       m_children.append(s);
05766       retval = s->parse();
05767     }
05768   }
05769   else if (retval==RetVal_Paragraph && m_level==3)
05770   {
05771     // then parse any number of nested sections
05772     while (retval==RetVal_Paragraph) // more sections follow
05773     {
05774       //SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
05775       DocSection *s=new DocSection(this,4,g_token->sectionId);
05776       m_children.append(s);
05777       retval = s->parse();
05778     }
05779   }
05780   else if ((m_level<=1 && retval==RetVal_Subsubsection) ||
05781            (m_level<=2 && retval==RetVal_Paragraph)
05782           ) 
05783   {
05784     int level; 
05785     if (retval==RetVal_Subsection) level=2; 
05786     else if (retval==RetVal_Subsubsection) level=3;
05787     else level=4;
05788     warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected %s "
05789             "command found inside %s!",
05790             sectionLevelToName[level],sectionLevelToName[m_level]);
05791     retval=0; // stop parsing
05792             
05793   }
05794   else if (retval==RetVal_Internal)
05795   {
05796     DocInternal *in = new DocInternal(this);
05797     m_children.append(in);
05798     retval = in->parse(m_level+1);
05799   }
05800   else
05801   {
05802   }
05803 
05804   INTERNAL_ASSERT(retval==0 || 
05805                   retval==RetVal_Section || 
05806                   retval==RetVal_Subsection || 
05807                   retval==RetVal_Subsubsection || 
05808                   retval==RetVal_Paragraph || 
05809                   retval==RetVal_Internal
05810                  );
05811 
05812   DBG(("DocSection::parse() end\n"));
05813   DocNode *n = g_nodeStack.pop();
05814   ASSERT(n==this);
05815   return retval;
05816 }
05817 
05818 //--------------------------------------------------------------------------
05819 
05820 void DocText::parse()
05821 {
05822   DBG(("DocText::parse() start\n"));
05823   g_nodeStack.push(this);
05824   doctokenizerYYsetStateText();
05825   
05826   int tok;
05827   while ((tok=doctokenizerYYlex())) // get the next token
05828   {
05829     switch(tok)
05830     {
05831       case TK_WORD:        
05832         m_children.append(new DocWord(this,g_token->name));
05833         break;
05834       case TK_WHITESPACE:  
05835         m_children.append(new DocWhiteSpace(this,g_token->chars));
05836         break;
05837       case TK_SYMBOL:     
05838         {
05839           char letter='\0';
05840           DocSymbol::SymType s = DocSymbol::decodeSymbol(g_token->name,&letter);
05841           if (s!=DocSymbol::Unknown)
05842           {
05843             m_children.append(new DocSymbol(this,s,letter));
05844           }
05845           else
05846           {
05847             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unsupported symbol %s found",
05848                 g_token->name.data());
05849           }
05850         }
05851         break;
05852       case TK_COMMAND: 
05853         switch (Mappers::cmdMapper->map(g_token->name))
05854         {
05855           case CMD_BSLASH:
05856             m_children.append(new DocSymbol(this,DocSymbol::BSlash));
05857             break;
05858           case CMD_AT:
05859             m_children.append(new DocSymbol(this,DocSymbol::At));
05860             break;
05861           case CMD_LESS:
05862             m_children.append(new DocSymbol(this,DocSymbol::Less));
05863             break;
05864           case CMD_GREATER:
05865             m_children.append(new DocSymbol(this,DocSymbol::Greater));
05866             break;
05867           case CMD_AMP:
05868             m_children.append(new DocSymbol(this,DocSymbol::Amp));
05869             break;
05870           case CMD_DOLLAR:
05871             m_children.append(new DocSymbol(this,DocSymbol::Dollar));
05872             break;
05873           case CMD_HASH:
05874             m_children.append(new DocSymbol(this,DocSymbol::Hash));
05875             break;
05876           case CMD_PERCENT:
05877             m_children.append(new DocSymbol(this,DocSymbol::Percent));
05878             break;
05879           default:
05880             warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected command `%s' found",
05881                       g_token->name.data());
05882             break;
05883         }
05884         break;
05885       default:
05886         warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Unexpected token %s",
05887             tokToString(tok));
05888         break;
05889     }
05890   }
05891 
05892   handleUnclosedStyleCommands();
05893 
05894   DocNode *n = g_nodeStack.pop();
05895   ASSERT(n==this);
05896   DBG(("DocText::parse() end\n"));
05897 }
05898 
05899 
05900 //--------------------------------------------------------------------------
05901 
05902 void DocRoot::parse()
05903 {
05904   DBG(("DocRoot::parse() start\n"));
05905   g_nodeStack.push(this);
05906   doctokenizerYYsetStatePara();
05907   int retval=0;
05908 
05909   // first parse any number of paragraphs
05910   bool isFirst=TRUE;
05911   DocPara *lastPar=0;
05912   do
05913   {
05914     DocPara *par = new DocPara(this);
05915     if (isFirst) { par->markFirst(); isFirst=FALSE; }
05916     retval=par->parse();
05917     if (!par->isEmpty()) 
05918     {
05919       m_children.append(par);
05920       lastPar=par;
05921     }
05922     else
05923     {
05924       delete par;
05925     }
05926     if (retval==TK_LISTITEM)
05927     {
05928       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid list item found");
05929     }
05930     else if (retval==RetVal_Subsection)
05931     {
05932       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found subsection command outside of section context!");
05933     }
05934     else if (retval==RetVal_Subsubsection)
05935     {
05936       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found subsubsection command outside of subsection context!");
05937     }
05938     else if (retval==RetVal_Paragraph)
05939     {
05940       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: found paragraph command outside of subsubsection context!");
05941     }
05942   } while (retval!=0 && retval!=RetVal_Section && retval!=RetVal_Internal);
05943   if (lastPar) lastPar->markLast();
05944 
05945   // then parse any number of level1 sections
05946   while (retval==RetVal_Section)
05947   {
05948     SectionInfo *sec=Doxygen::sectionDict[g_token->sectionId];
05949     if (sec)
05950     {
05951       DocSection *s=new DocSection(this,1,g_token->sectionId);
05952       m_children.append(s);
05953       retval = s->parse();
05954     }
05955     else
05956     {
05957       warn_doc_error(g_fileName,doctokenizerYYlineno,"Warning: Invalid section id `%s'; ignoring section",g_token->sectionId.data());
05958       retval = 0;
05959     }
05960   }
05961 
05962   if (retval==RetVal_Internal)
05963   {
05964     DocInternal *in = new DocInternal(this);
05965     m_children.append(in);
05966     retval = in->parse(1);
05967   }
05968 
05969 
05970   handleUnclosedStyleCommands();
05971 
05972   DocNode *n = g_nodeStack.pop();
05973   ASSERT(n==this);
05974   DBG(("DocRoot::parse() end\n"));
05975 }
05976 
05977 //--------------------------------------------------------------------------
05978 
05979 DocNode *validatingParseDoc(const char *fileName,int startLine,
05980                             Definition *ctx,MemberDef *md,
05981                             const char *input,bool indexWords,
05982                             bool isExample, const char *exampleName,
05983                             bool singleLine, bool linkFromIndex)
05984 {
05985   //printf("validatingParseDoc(%s,%s)\n",ctx?ctx->name().data():"<none>",
05986   //                                     md?md->name().data():"<none>");
05987   //printf("========== validating %s at line %d\n",fileName,startLine);
05988   //printf("---------------- input --------------------\n%s\n----------- end input -------------------\n",input);
05989   //g_token = new TokenInfo;
05990 
05991   // store parser state so we can re-enter this function if needed
05992   bool fortranOpt = Config_getBool("OPTIMIZE_FOR_FORTRAN");
05993   docParserPushContext();
05994 
05995   if (ctx &&
05996       (ctx->definitionType()==Definition::TypeClass || 
05997        ctx->definitionType()==Definition::TypeNamespace
05998       )
05999      ) 
06000   {
06001     g_context = ctx->name();
06002   }
06003   else if (ctx && ctx->definitionType()==Definition::TypePage)
06004   {
06005     Definition *scope = ((PageDef*)ctx)->getPageScope();
06006     if (scope) g_context = scope->name();
06007   }
06008   else if (ctx && ctx->definitionType()==Definition::TypeGroup)
06009   {
06010     Definition *scope = ((GroupDef*)ctx)->getGroupScope();
06011     if (scope) g_context = scope->name();
06012   }
06013   else
06014   {
06015     g_context = "";
06016   }
06017 
06018   if (indexWords && md && Config_getBool("SEARCHENGINE"))
06019   {
06020       
06021     g_searchUrl=md->getOutputFileBase();
06022     Doxygen::searchIndex->setCurrentDoc(
06023         (fortranOpt?theTranslator->trSubprogram(TRUE,TRUE):theTranslator->trMember(TRUE,TRUE))+" "+md->qualifiedName(),
06024         g_searchUrl,
06025         md->anchor());
06026   }
06027   else if (indexWords && ctx && Config_getBool("SEARCHENGINE"))
06028   {
06029     g_searchUrl=ctx->getOutputFileBase();
06030     QCString name = ctx->qualifiedName();
06031     if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
06032     {
06033       name = substitute(name,"::",".");
06034     }
06035     switch (ctx->definitionType())
06036     {
06037       case Definition::TypePage:
06038         {
06039           PageDef *pd = (PageDef *)ctx;
06040           if (!pd->title().isEmpty())
06041           {
06042             name = theTranslator->trPage(TRUE,TRUE)+" "+pd->title();
06043           }
06044           else
06045           {
06046             name = theTranslator->trPage(TRUE,TRUE)+" "+pd->name();
06047           }
06048         }
06049         break;
06050       case Definition::TypeClass:
06051         {
06052           ClassDef *cd = (ClassDef *)ctx;
06053           name.prepend(cd->compoundTypeString()+" ");
06054         }
06055         break;
06056       case Definition::TypeNamespace:
06057         {
06058           if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
06059           {
06060             name = theTranslator->trPackage(name);
06061           }
06062           else if(fortranOpt)
06063           {
06064             name.prepend(theTranslator->trModule(TRUE,TRUE)+" ");
06065           }
06066             else
06067           {
06068             name.prepend(theTranslator->trNamespace(TRUE,TRUE)+" ");
06069           }
06070         }
06071         break;
06072       case Definition::TypeGroup:
06073         {
06074           GroupDef *gd = (GroupDef *)ctx;
06075           if (gd->groupTitle())
06076           {
06077             name = theTranslator->trGroup(TRUE,TRUE)+" "+gd->groupTitle();
06078           }
06079           else
06080           {
06081             name.prepend(theTranslator->trGroup(TRUE,TRUE)+" ");
06082           }
06083         }
06084         break;
06085       default:
06086         break;
06087     }
06088     Doxygen::searchIndex->setCurrentDoc(name,g_searchUrl);
06089   }
06090   else
06091   {
06092     g_searchUrl="";
06093   }
06094 
06095   g_fileName = fileName;
06096   g_relPath = (!linkFromIndex && ctx) ? 
06097                QString(relativePathToRoot(ctx->getOutputFileBase())) : 
06098                QString("");
06099   //printf("ctx->name=%s relPath=%s\n",ctx->name().data(),g_relPath.data());
06100   g_memberDef = md;
06101   g_nodeStack.clear();
06102   g_styleStack.clear();
06103   g_initialStyleStack.clear();
06104   g_inSeeBlock = FALSE;
06105   g_insideHtmlLink = FALSE;
06106   g_includeFileText = "";
06107   g_includeFileOffset = 0;
06108   g_includeFileLength = 0;
06109   g_isExample = isExample;
06110   g_exampleName = exampleName;
06111   g_hasParamCommand = FALSE;
06112   g_hasReturnCommand = FALSE;
06113   g_paramsFound.setAutoDelete(FALSE);
06114   g_paramsFound.clear();
06115   g_sectionDict = 0; //sections;
06116   
06117   //printf("Starting comment block at %s:%d\n",g_fileName.data(),startLine);
06118   doctokenizerYYlineno=startLine;
06119   doctokenizerYYinit(input,g_fileName);
06120 
06121 
06122   // build abstract syntax tree
06123   DocRoot *root = new DocRoot(md!=0,singleLine);
06124   root->parse();
06125 
06126 
06127   if (Debug::isFlagSet(Debug::PrintTree))
06128   {
06129     // pretty print the result
06130     PrintDocVisitor *v = new PrintDocVisitor;
06131     root->accept(v);
06132     delete v;
06133   }
06134 
06135 
06136   checkUndocumentedParams();
06137   detectNoDocumentedParams();
06138 
06139   // TODO: These should be called at the end of the program.
06140   //doctokenizerYYcleanup();
06141   //Mappers::cmdMapper->freeInstance();
06142   //Mappers::htmlTagMapper->freeInstance();
06143 
06144   // restore original parser state
06145   docParserPopContext();
06146 
06147   return root;
06148 }
06149 
06150 DocNode *validatingParseText(const char *input)
06151 {
06152   // store parser state so we can re-enter this function if needed
06153   docParserPushContext();
06154 
06155   //printf("------------ input ---------\n%s\n"
06156   //       "------------ end input -----\n",input);
06157   //g_token = new TokenInfo;
06158   g_context = "";
06159   g_fileName = "<parseText>";
06160   g_relPath = "";
06161   g_memberDef = 0;
06162   g_nodeStack.clear();
06163   g_styleStack.clear();
06164   g_initialStyleStack.clear();
06165   g_inSeeBlock = FALSE;
06166   g_insideHtmlLink = FALSE;
06167   g_includeFileText = "";
06168   g_includeFileOffset = 0;
06169   g_includeFileLength = 0;
06170   g_isExample = FALSE;
06171   g_exampleName = "";
06172   g_hasParamCommand = FALSE;
06173   g_hasReturnCommand = FALSE;
06174   g_paramsFound.setAutoDelete(FALSE);
06175   g_paramsFound.clear();
06176   g_searchUrl="";
06177 
06178   DocText *txt = new DocText;
06179 
06180   if (input)
06181   {
06182     doctokenizerYYlineno=1;
06183     doctokenizerYYinit(input,g_fileName);
06184 
06185     // build abstract syntax tree
06186     txt->parse();
06187 
06188     if (Debug::isFlagSet(Debug::PrintTree))
06189     {
06190       // pretty print the result
06191       PrintDocVisitor *v = new PrintDocVisitor;
06192       txt->accept(v);
06193       delete v;
06194     }
06195   }
06196 
06197   // restore original parser state
06198   docParserPopContext();
06199   return txt;
06200 }
06201 
06202 void docFindSections(const char *input,
06203                      Definition *d,
06204                      MemberGroup *mg,
06205                      const char *fileName)
06206 {
06207   doctokenizerYYFindSections(input,d,mg,fileName);
06208 }
06209 
06210 void initDocParser()
06211 {
06212   if (Config_getBool("SEARCHENGINE"))
06213   {
06214     Doxygen::searchIndex = new SearchIndex;
06215   }
06216   else
06217   {
06218     Doxygen::searchIndex = 0;
06219   }
06220 }
06221 
06222 void finializeDocParser()
06223 {
06224   delete Doxygen::searchIndex;
06225 }
06226 



Generated on Mon Mar 31 10:58:35 2008 by  doxygen 1.5.1