#include "TDocParser.h"
#include "Riostream.h"
#include "TBaseClass.h"
#include "TClass.h"
#include "TClassDocOutput.h"
#include "TDataMember.h"
#include "TDataType.h"
#include "TDatime.h"
#include "TDocDirective.h"
#include "TEnv.h"
#include "TGlobal.h"
#include "THtml.h"
#include "TMethod.h"
#include "TROOT.h"
#include "TSystem.h"
namespace {
   class TMethodWrapperImpl: public TDocParser::TMethodWrapper {
   public:
      TMethodWrapperImpl(const TMethod* m): fMeth(m) {}
      static void SetClass(const TClass* cl) { fgClass = cl; }
      const char* GetName() const { return fMeth->GetName(); }
      Int_t GetNargs() const { return fMeth->GetNargs(); }
      virtual const TMethod* GetMethod() const { return fMeth; }
      Bool_t IsSortable() const { return kTRUE; }
      Int_t Compare(const TObject *obj) const {
         const TMethodWrapperImpl* m = dynamic_cast<const TMethodWrapperImpl*>(obj);
         if (!m) return 1;
         Int_t ret = strcasecmp(GetName(), m->GetName());
         if (ret == 0) {
            if (GetNargs() < m->GetNargs()) return -1;
            else if (GetNargs() > m->GetNargs()) return 1;
            if (GetMethod()->GetClass()->InheritsFrom(m->GetMethod()->GetClass()))
               return -1;
            else 
               return 1;
         }
         const char* l(GetName());
         const char* r(m->GetName());
         if (l[0] == '~' && r[0] == '~') {
            ++l;
            ++r;
         }
         if (fgClass->InheritsFrom(l)) {
            if (fgClass->InheritsFrom(r)) {
               if (gROOT->GetClass(l)->InheritsFrom(r))
                  return -1;
               else return 1;
            } else return -1;
         } else if (fgClass->InheritsFrom(r))
            return 1;
         if (l[0] == '~') return -1;
         if (r[0] == '~') return 1;
         return (ret < 0) ? -1 : 1;
      }
   private:
      static const TClass* fgClass; 
      const TMethod* fMeth; 
   };
   const TClass* TMethodWrapperImpl::fgClass = 0;
}
// x=sin^2(y)
// y = #sqrt{sin(x)}
// End_Latex
/* BEGIN_LATEX Wow,^{an}_{image}^{inside}_{a}^{html}_{block}
   END_LATEX
*/
// END_HTML
ClassImp(TDocParser);
std::set<std::string>  TDocParser::fgKeywords;
TDocParser::TDocParser(TClassDocOutput& docOutput, TClass* cl):
   fHtml(docOutput.GetHtml()), fDocOutput(&docOutput), fLineNo(0),
   fCurrentClass(cl), fDirectiveCount(0), fDocContext(kIgnore), 
   fCheckForMethod(kFALSE), fFoundClassDescription(kFALSE), 
   fLookForClassDescription(kTRUE), fCommentAtBOL(kFALSE)
{
   
   InitKeywords();
   fSourceInfoTags[kInfoLastUpdate] = fHtml->GetLastUpdateTag();
   fSourceInfoTags[kInfoAuthor]     = fHtml->GetAuthorTag();
   fSourceInfoTags[kInfoCopyright]  = fHtml->GetCopyrightTag();
   fClassDescrTag = fHtml->GetClassDocTag();
   TMethodWrapperImpl::SetClass(cl);
   AddClassMethodsRecursively(0);
   AddClassDataMembersRecursively(0);
   
   fParseContext.push_back(kCode);
   
   TMethod *method;
   TIter nextMethod(fCurrentClass->GetListOfMethods());
   fMethodCounts.clear();
   while ((method = (TMethod *) nextMethod())) {
      ++fMethodCounts[method->GetName()];
   }
}
TDocParser::TDocParser(TDocOutput& docOutput):
   fHtml(docOutput.GetHtml()), fDocOutput(&docOutput), fLineNo(0),
   fCurrentClass(0), fDirectiveCount(0), fDocContext(kIgnore), 
   fCheckForMethod(kFALSE), fFoundClassDescription(kFALSE), 
   fLookForClassDescription(kTRUE), fCommentAtBOL(kFALSE)
{
   
   InitKeywords();
   fSourceInfoTags[kInfoLastUpdate] = fHtml->GetLastUpdateTag();
   fSourceInfoTags[kInfoAuthor]     = fHtml->GetAuthorTag();
   fSourceInfoTags[kInfoCopyright]  = fHtml->GetCopyrightTag();
   fClassDescrTag = fHtml->GetClassDocTag();
   TMethodWrapperImpl::SetClass(0);
}
TDocParser::~TDocParser()
{
   
   if (gDebug > 3) {
      for (std::map<std::string, Int_t>::const_iterator iMethod = fMethodCounts.begin();
         iMethod != fMethodCounts.end(); ++iMethod)
         if (iMethod->second)
            Info("~TDocParser", "Implementation of method %s::%s could not be found.",
            fCurrentClass ? fCurrentClass->GetName() : "",
            iMethod->first.c_str());
      TIter iDirective(&fDirectiveHandlers);
      TDocDirective* directive = 0;
      while ((directive = (TDocDirective*) iDirective())) {
         TString directiveName;
         directive->GetName(directiveName);
         Warning("~TDocParser", "Missing \"%s\" for macro %s", directive->GetEndTag(), directiveName.Data());
      }
   }
}
void TDocParser::AddClassMethodsRecursively(TBaseClass* bc)
{
   
   
   
   
   TClass *cl = fCurrentClass;
   if (bc) 
      cl = bc->GetClassPointer(kFALSE);
   if (!cl) return;
   TMethod *method;
   TIter nextMethod(cl->GetListOfMethods());
   while ((method = (TMethod *) nextMethod())) {
      if (!strcmp(method->GetName(), "Dictionary") ||
          !strcmp(method->GetName(), "Class_Version") ||
          !strcmp(method->GetName(), "Class_Name") ||
          !strcmp(method->GetName(), "DeclFileName") ||
          !strcmp(method->GetName(), "DeclFileLine") ||
          !strcmp(method->GetName(), "ImplFileName") ||
          !strcmp(method->GetName(), "ImplFileLine") ||
          bc && (method->GetName()[0] == '~' 
             || !strcmp(method->GetName(), method->GetReturnTypeName())) 
          )
         continue;
      Int_t mtype = 0;
      if (kIsPrivate & method->Property())
         mtype = 0;
      else if (kIsProtected & method->Property())
         mtype = 1;
      else if (kIsPublic & method->Property())
         mtype = 2;
      if (bc) {
         if (mtype == 0) continue;
         if (bc->Property() & kIsPrivate)
            mtype = 0;
         else if ((bc->Property() & kIsProtected) && mtype == 2)
            mtype = 1;
      }
      Bool_t hidden = kFALSE;
      for (Int_t access = 0; !hidden && access < 3; ++access) {
         TMethodWrapperImpl* other = (TMethodWrapperImpl*) fMethods[access].FindObject(method->GetName());
         hidden |= (other) && (other->GetMethod()->GetClass() != method->GetClass());
      }
      if (!hidden)
         fMethods[mtype].Add(new TMethodWrapperImpl(method));
   }
   TIter iBase(cl->GetListOfBases());
   TBaseClass* base = 0;
   while ((base = (TBaseClass*)iBase()))
      AddClassMethodsRecursively(base);
   if (!bc)
      for (Int_t access = 0; access < 3; ++access) {
         fMethods[access].SetOwner();
         fMethods[access].Sort();
      }
}
void TDocParser::AddClassDataMembersRecursively(TBaseClass* bc) {
   
   
   
   
   TClass *cl = fCurrentClass;
   if (bc) 
      cl = bc->GetClassPointer(kFALSE);
   if (!cl) return;
   TDataMember *dm;
   TIter nextDM(cl->GetListOfDataMembers());
   while ((dm = (TDataMember *) nextDM())) {
      if (!strcmp(dm->GetName(), "fgIsA"))
         continue;
      Int_t mtype = 0;
      if (kIsPrivate & dm->Property())
         mtype = 0;
      else if (kIsProtected & dm->Property())
         mtype = 1;
      else if (kIsPublic & dm->Property())
         mtype = 2;
      if (bc) {
         if (mtype == 0) continue;
         if (bc->Property() & kIsPrivate)
            mtype = 0;
         else if ((bc->Property() & kIsProtected) && mtype == 2)
            mtype = 1;
      }
      const Int_t flagEnumConst = G__BIT_ISENUM | G__BIT_ISCONSTANT | G__BIT_ISSTATIC;
      if ((dm->Property() & flagEnumConst) == flagEnumConst
         && dm->GetDataType() && dm->GetDataType()->GetType() == kInt_t)
         mtype += 3;
      fDataMembers[mtype].Add(dm);
   }
   TIter iBase(cl->GetListOfBases());
   TBaseClass* base = 0;
   while ((base = (TBaseClass*)iBase()))
      AddClassDataMembersRecursively(base);
   if (!bc)
      for (Int_t access = 0; access < 6; ++access) {
         fDataMembers[access].SetOwner(kFALSE);
         if (access < 3) 
            fDataMembers[access].Sort();
      }
}
void TDocParser::AnchorFromLine(TString& anchor) {
   
   
   const char base64String[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
   
   
   
   UInt_t hash = ::Hash(fLineStripped);
   anchor.Remove(0);
   
   anchor += base64String[hash % 52];
   hash /= 52;
   while (hash) {
      anchor += base64String[hash % 64];
      hash /= 64;
   }
}
void TDocParser::Convert(std::ostream& out, std::istream& in, const char* relpath)
{
   
   fParseContext.clear();
   fParseContext.push_back(kComment); 
   while (!in.eof()) {
      fLineRaw.ReadLine(in, kFALSE);
      if (in.eof())
         break;
      
      fLineComment = "";
      fLineSource = fLineRaw;
      fLineStripped = fLineRaw;
      Strip(fLineStripped);
      DecorateKeywords(fLineSource);
      ProcessComment();
      GetDocOutput()->AdjustSourcePath(fLineComment, relpath);
      if (fLineComment.Length() || !InContext(kDirective))
         out << fLineComment << endl;
   }
}
void TDocParser::DecorateKeywords(std::ostream& out, const char *text)
{
   
   TString str(text);
   DecorateKeywords(str);
   out << str;
}
void TDocParser::DecorateKeywords(TString& line)
{
   
   
   
   
   std::list<TClass*> currentType;
   enum {
      kNada,
      kMember,
      kScope,
      kNumAccesses
   } scoping = kNada;
   currentType.push_back(0);
   Ssiz_t i = 0;
   while (isspace((UChar_t)line[i]))
      ++i;
   Ssiz_t startOfLine = i;
   
   
   Ssiz_t copiedToCommentUpTo = 0;
   if (InContext(kDirective) && fDirectiveHandlers.Last()) {
      
      TDocDirective* directive = (TDocDirective*)fDirectiveHandlers.Last();
      const char* endTag = directive->GetEndTag();
      Ssiz_t posEndTag = i;
      while (kNPOS != (posEndTag = line.Index(endTag, posEndTag, TString::kIgnoreCase)))
         if (posEndTag == 0 || line[posEndTag - 1] != '"') 
            break;
      if (posEndTag != kNPOS)
         i = posEndTag;
      else {
         Ssiz_t start = 0;
         if (!InContext(kComment) || (InContext(kComment) & kCXXComment)) {
            
            while (isspace((UChar_t)fLineRaw[start])) ++start;
            if (fLineRaw[start] == '/' && fLineRaw[start + 1] == '/')
               start += 2;
            else start = 0;
         }
         directive->AddLine(fLineRaw(start, fLineRaw.Length()));
         while(i < line.Length())
            fDocOutput->ReplaceSpecialChars(line, i);
         copiedToCommentUpTo = i;
      }
   }
   for (; i < line.Length(); ++i) {
      if (!currentType.back())
         scoping = kNada;
      
      if (Context() == kCode 
         || Context() == kComment) {
         if (currentType.back())
            switch (line[i]) {
               case ':':
                  if (line[i + 1] == ':') {
                     scoping = kScope;
                     i += 1;
                     continue;
                  }
                  break;
               case '-':
                  if (line[i + 1] == '>') {
                     scoping = kMember;
                     i += 1;
                     continue;
                  }
                  break;
               case '.':
                  if (line[i + 1] != '.') {
                     
                     scoping = kMember;
                     continue;
                  }
                  break;
            }
         switch (line[i]) {
            case '(':
               currentType.push_back(0);
               scoping = kNada;
               continue;
               break;
            case ')':
               if (currentType.size() > 1)
                  currentType.pop_back();
               scoping = kMember;
               continue;
               break;
         }
         if (i >= line.Length()) 
            break;
      } else 
         currentType.back() = 0;
      if (!IsWord(line[i])){
         Bool_t haveHtmlEscapedChar = Context() == kString 
            && i > 2 && line[i] == '\'' && line[i-1] == ';';
         if (haveHtmlEscapedChar) {
            Ssiz_t posBegin = i - 2;
            while (posBegin > 0 && IsWord(line[posBegin])) 
               --posBegin;
            haveHtmlEscapedChar = posBegin > 0 && 
               line[posBegin] == '&' && line[posBegin - 1] == '\'';
         }
         EParseContext context = Context();
         Bool_t closeString = context == kString
            && (  line[i] == '"' 
               || line[i] == '\'' 
                  && (  i > 1 && line[i - 2] == '\'' 
                     || i > 3 && line[i - 2] == '\\' && line[i - 3] == '\'')
               || haveHtmlEscapedChar)
            && (i == 0 || line[i - 1] != '\\'); 
         if (context == kCode || context == kComment) {
            if (line[i] == '"' || line[i] == '\'' && (
                  
                  line.Length() > i + 2 && line[i + 2] == '\'' ||
                  
                  line.Length() > i + 3 && line[i + 1] == '\'' && line[i + 3] == '\'')) {
               fDocOutput->DecorateEntityBegin(line, i, kString);
               fParseContext.push_back(kString);
               currentType.back() = 0;
               closeString = kFALSE;
            } else if (context == kCode
               && line[i] == '/' && (line[i+1] == '/' || line[i+1] == '*')) {
               fParseContext.push_back(kComment);
               if (line[i+1] == '/')
                  fParseContext.back() |= kCXXComment;
               currentType.back() = 0;
               fDocOutput->DecorateEntityBegin(line, i, kComment);
               ++i;
            } else if (context == kComment 
               && !(fParseContext.back() & kCXXComment)
               && line.Length() > i + 1 
               && line[i] == '*' && line[i+1] == '/') {
               if (fParseContext.size()>1)
                  fParseContext.pop_back();
               currentType.back() = 0;
               i += 2;
               fDocOutput->DecorateEntityEnd(line, i, kComment);
               if (!fCommentAtBOL) {
                  if (InContext(kDirective))
                     ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(line(copiedToCommentUpTo, i));
                  else
                     fLineComment += line(copiedToCommentUpTo, i);
                  copiedToCommentUpTo = i;
               }
            } else if (startOfLine == i
               && line[i] == '#'
               && context == kCode) {
               ExpandCPPLine(line, i);
            }
         } 
         if (i < line.Length())
            fDocOutput->ReplaceSpecialChars(line, i);
         if (closeString) {
            fDocOutput->DecorateEntityEnd(line, i, kString);
            if (fParseContext.size()>1)
               fParseContext.pop_back();
            currentType.back() = 0;
         }
         --i; 
         continue;
      } 
      
      Ssiz_t endWord = i;
      while (endWord < line.Length() && IsName(line[endWord]))
         endWord++;
      if (Context() == kString || Context() == kCPP) {
         
         i = endWord - 1;
         continue;
      }
      TString word(line(i, endWord - i));
      
      if ((i == 0 || i > 0 && line[i - 1] != '"')
         && HandleDirective(line, i, word, copiedToCommentUpTo)) {
         
         currentType.back() = 0;
         continue;
      }
      
      if (Context() == kCode
         && fgKeywords.find(word.Data()) != fgKeywords.end()) {
         fDocOutput->DecorateEntityBegin(line, i, kKeyword);
         i += word.Length();
         fDocOutput->DecorateEntityEnd(line, i, kKeyword);
         --i; 
         currentType.back() = 0;
         continue;
      }
      
      
      
      
      
      TDataType* subType = 0;
      TClass* subClass = 0;
      TDataMember *datamem = 0;
      TMethod *meth = 0;
      const char* globalTypeName = 0;
      if (!currentType.size()) {
         Warning("DecorateKeywords", "type context is empty!");
         currentType.push_back(0);
      }
      TClass* lookupScope = currentType.back();
      if (scoping == kNada)
         lookupScope = fCurrentClass;
      if (scoping == kNada) {
         subType = gROOT->GetType(word);
         if (!subType)
            subClass = fHtml->GetClass(word);
         if (!subType && !subClass) {
            TGlobal *global = gROOT->GetGlobal(word);
            if (global) {
               
               globalTypeName = global->GetTypeName();
               subClass = fHtml->GetClass(globalTypeName);
               if (!subClass)
                  subType = gROOT->GetType(globalTypeName);
               else 
                  if (subClass == THtml::Class() && word != "gHtml")
                     subClass = 0;
            }
         }
         if (!subType && !subClass) {
            
            
            
         }
      }
      if (lookupScope && !subType && !subClass) {
         if (scoping == kScope) {
            TString subClassName(lookupScope->GetName());
            subClassName += "::";
            subClassName += word;
            subClass = fHtml->GetClass(subClassName);
         }
         if (!subClass) {
            
            datamem = lookupScope->GetDataMember(word);
            if (!datamem)
               meth = lookupScope->GetMethodAllAny(word);
         }
      }
      
      TString mangledWord(word);
      fDocOutput->ReplaceSpecialChars(mangledWord);
      line.Replace(i, word.Length(), mangledWord);
      TSubString substr(line(i, mangledWord.Length()));
      if (subType) {
         fDocOutput->ReferenceEntity(substr, subType,
            globalTypeName ? globalTypeName : subType->GetName());
         currentType.back() = 0;
      } else if (subClass) {
         fDocOutput->ReferenceEntity(substr, subClass,
            globalTypeName ? globalTypeName : subClass->GetName());
         currentType.back() = subClass;
      } else if (datamem || meth) {
            if (datamem) {
               fDocOutput->ReferenceEntity(substr, datamem);
               if (datamem->GetTypeName())
                  currentType.back() = fHtml->GetClass(datamem->GetTypeName());
            } else {
               fDocOutput->ReferenceEntity(substr, meth);
               TString retTypeName = meth->GetReturnTypeName();
               if (retTypeName.BeginsWith("const "))
                  retTypeName.Remove(0,6);
               Ssiz_t pos=0;
               while (IsWord(retTypeName[pos])) ++pos;
               retTypeName.Remove(pos, retTypeName.Length());
               if (retTypeName.Length())
                  currentType.back() = fHtml->GetClass(retTypeName);
            }
      } else
         currentType.back() = 0;
      
      i += substr.Length();
      --i; 
   } 
   if (i > line.Length())
      i = line.Length();
   
   if (Context() == kString) {
      fDocOutput->DecorateEntityEnd(line, i, kString);
      if (fParseContext.size()>1)
         fParseContext.pop_back();
      currentType.back() = 0;
   }
   
   
   
   
   if ((InContext(kComment) || fCommentAtBOL) && copiedToCommentUpTo < line.Length()) {
      if (InContext(kDirective))
         ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(line(copiedToCommentUpTo, line.Length()));
      else
         fLineComment += line(copiedToCommentUpTo, line.Length());
   }
   
   
   
   if (InContext(kComment) & kCXXComment) {
      fDocOutput->DecorateEntityEnd(line, i, kComment);
      if (fLineComment.Length()) {
         Ssiz_t pos = fLineComment.Length();
         fDocOutput->DecorateEntityEnd(fLineComment, pos, kComment);
      }
      RemoveCommentContext(kTRUE);
      currentType.back() = 0;
   }
}
void TDocParser::DecrementMethodCount(const char* name)
{
   
   
   typedef std::map<std::string , Int_t > MethodCount_t;
   MethodCount_t::iterator iMethodName = fMethodCounts.find(name);
   if (iMethodName != fMethodCounts.end()) {
      --(iMethodName->second);
      if (iMethodName->second <= 0)
         fMethodCounts.erase(iMethodName);
   }
}
void TDocParser::ExpandCPPLine(TString& line, Ssiz_t& pos)
{
   Bool_t linkExist    = kFALSE;
   Ssiz_t posEndOfLine = line.Length();
   Ssiz_t posHash      = pos;
   Ssiz_t posInclude = line.Index("include", pos);
   if (posInclude != kNPOS) {
      TString filename;
      Ssiz_t posStartFilename = posInclude + 7;
      if (line.Tokenize(filename, posStartFilename, "[<\"]")) {
         Ssiz_t posEndFilename = posStartFilename;
         if (line.Tokenize(filename, posEndFilename, "[>\"]")) {
            TString filesysFileName(filename);
            if (gSystem->FindFile(fHtml->GetSourceDir(), filesysFileName, kReadPermission)) {
               fDocOutput->CopyHtmlFile(filesysFileName);
               TString endOfLine(line(posEndFilename - 1, line.Length()));
               line.Remove(posStartFilename, line.Length());
               for (Ssiz_t i = pos; i < line.Length();)
                  fDocOutput->ReplaceSpecialChars(line, i);
               line += "<a href=\"../";
               line += fHtml->GetFileName(filename);
               line += "\">";
               line += filename + "</a>" + endOfLine[0]; 
               posEndOfLine = line.Length() - 1; 
               fDocOutput->ReplaceSpecialChars(line, posEndOfLine); 
               line += endOfLine(1, endOfLine.Length()); 
               linkExist = kTRUE;
            }
         }
      }
   }
   if (!linkExist) {
      fDocOutput->ReplaceSpecialChars(line);
      posEndOfLine = line.Length();
   }
   Ssiz_t posHashAfterDecoration = posHash;
   fDocOutput->DecorateEntityBegin(line, posHashAfterDecoration, kCPP);
   posEndOfLine += posHashAfterDecoration - posHash;
   fDocOutput->DecorateEntityEnd(line, posEndOfLine, kCPP);
   pos = posEndOfLine;
}
Bool_t TDocParser::HandleDirective(TString& line, Ssiz_t& pos, TString& word, 
                                   Ssiz_t& copiedToCommentUpTo)
{
   
   
   
   Bool_t begin = kTRUE;
   TClass* clDirective = IsDirective(line, pos, word, begin);
   if (!clDirective)
      return kFALSE;
   
   Bool_t end = !begin;
   TDocDirective* directive = 0; 
   if (begin) {
      
      if (InContext(kDirective))
         ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(fLineSource(copiedToCommentUpTo, pos - copiedToCommentUpTo));
      else
         fLineComment += fLineSource(copiedToCommentUpTo, pos - copiedToCommentUpTo);
      copiedToCommentUpTo = pos;
      pos += word.Length(); 
      directive = (TDocDirective*) clDirective->New();
      if (!directive)
         return kFALSE;
      directive->SetParser(this);
      if (fCurrentMethodTag.Length())
         directive->SetTag(fCurrentMethodTag);
      directive->SetCounter(fDirectiveCount++);
      
      TString params;
      if (begin && line[pos] == '(') {
         std::list<char> waitForClosing;
         Ssiz_t endParam = pos + 1;
         for (; endParam < line.Length() 
            && (line[endParam] != ')' || !waitForClosing.empty()); ++endParam) {
            const char c = line[endParam];
            if (!waitForClosing.empty() && waitForClosing.back() == c) {
               waitForClosing.pop_back();
               continue;
            }
            switch (c) {
               case '"':
                  if (waitForClosing.empty() || waitForClosing.back() != '\'')
                     waitForClosing.push_back('"');
                  break;
               case '\'':
                  if (waitForClosing.empty() || waitForClosing.back() != '"')
                     waitForClosing.push_back('\'');
                  break;
               case '(':
                  if (waitForClosing.empty() || waitForClosing.back() != '"' && waitForClosing.back() != '\'')
                     waitForClosing.push_back(')');
                  break;
               case '\\':
                  ++endParam; 
               default:
                  break;
            };
         }
         if (waitForClosing.empty()) {
            params = line(pos + 1, endParam - (pos + 1));
            pos += params.Length() + 2; 
         }
         directive->SetParameters(params);
      }
      
      Ssiz_t posEndTag = pos;
      const char* endTag = directive->GetEndTag();
      Ssiz_t lenEndTag = strlen(endTag);
      while (kNPOS != (posEndTag = line.Index(endTag, posEndTag, TString::kIgnoreCase))) {
         if (line[posEndTag - 1] == '"') {
            posEndTag += lenEndTag;
            continue; 
         }
         break;
      }
      if (posEndTag != kNPOS) {
         end = kTRUE; 
      } else {
         fDirectiveHandlers.AddLast(directive);
         fParseContext.push_back(kDirective);
         if (InContext(kComment) & kCXXComment)
            fParseContext.back() |= kCXXComment;
         posEndTag = line.Length();
      }
      directive->AddLine(line(pos, posEndTag - pos));
      TString remainder(line(posEndTag, line.Length()));
      line.Remove(posEndTag, line.Length());
      while (pos < line.Length())
         fDocOutput->ReplaceSpecialChars(line, pos);
      pos = line.Length();
      
      copiedToCommentUpTo = line.Length();
      line += remainder;
   }
   
   if (end) {
      if (!begin)
         pos += word.Length(); 
      else pos += word.Length() - 2; 
      if (!directive) directive = (TDocDirective*) fDirectiveHandlers.Last();
      if (!directive) {
         Warning("HandleDirective", "Cannot find directive handler object!", 
            fLineRaw.Data());
         return kFALSE;
      }
      if (!begin) {
         Ssiz_t start = 0;
         if (!InContext(kComment) || (InContext(kComment) & kCXXComment)) {
            
            while (isspace((UChar_t)fLineRaw[start])) ++start;
            if (fLineRaw[start] == '/' && fLineRaw[start + 1] == '/')
               start += 2;
            else start = 0;
         }
         directive->AddLine(line(start, pos - word.Length() - start));
         TString remainder(line(pos, line.Length()));
         line.Remove(pos, line.Length());
         fDocOutput->ReplaceSpecialChars(line);
         pos = line.Length();
         line += remainder;
      }
      copiedToCommentUpTo = pos;
      TString result;
      directive->GetResult(result);
      if (!begin)
         fDirectiveHandlers.Remove(fDirectiveHandlers.LastLink());
      delete directive;
      if (!begin) {
         
         Bool_t isInCxxComment = InContext(kDirective) & kCXXComment;
         if (fParseContext.size()>1)
            fParseContext.pop_back();
         if (isInCxxComment && !InContext(kComment)) {
            fParseContext.push_back(kComment | kCXXComment);
            fDocOutput->DecorateEntityBegin(line, pos, kComment);
         }
      }
      if (InContext(kDirective) && fDirectiveHandlers.Last())
         ((TDocDirective*)fDirectiveHandlers.Last())->AddLine(result(0, result.Length()));
      else 
         fLineComment += result;
      
   }
   return kTRUE;
}
UInt_t TDocParser::InContext(Int_t context) const
{
   
   
   
   
   UInt_t lowerContext = context & kParseContextMask;
   UInt_t contextFlag  = context & kParseContextFlagMask;
   for (std::list<UInt_t>::const_reverse_iterator iPC = fParseContext.rbegin();
      iPC != fParseContext.rend(); ++iPC)
      if (!lowerContext || (lowerContext && ((*iPC & kParseContextMask) == lowerContext))
         && (!contextFlag || contextFlag && (*iPC & contextFlag)))
         return *iPC;
   return 0;
}
void TDocParser::InitKeywords() const
{
   
   if (!fgKeywords.empty())
      return;
   fgKeywords.insert("asm");
   fgKeywords.insert("auto");
   fgKeywords.insert("bool");
   fgKeywords.insert("break");
   fgKeywords.insert("case");
   fgKeywords.insert("catch");
   fgKeywords.insert("char");
   fgKeywords.insert("class");
   fgKeywords.insert("const");
   fgKeywords.insert("const_cast");
   fgKeywords.insert("continue");
   fgKeywords.insert("default");
   fgKeywords.insert("delete");
   fgKeywords.insert("do");
   fgKeywords.insert("double");
   fgKeywords.insert("dynamic_cast");
   fgKeywords.insert("else");
   fgKeywords.insert("enum");
   fgKeywords.insert("explicit");
   fgKeywords.insert("export");
   fgKeywords.insert("extern");
   fgKeywords.insert("false");
   fgKeywords.insert("float");
   fgKeywords.insert("for");
   fgKeywords.insert("friend");
   fgKeywords.insert("goto");
   fgKeywords.insert("if");
   fgKeywords.insert("inline");
   fgKeywords.insert("int");
   fgKeywords.insert("long");
   fgKeywords.insert("mutable");
   fgKeywords.insert("namespace");
   fgKeywords.insert("new");
   fgKeywords.insert("operator");
   fgKeywords.insert("private");
   fgKeywords.insert("protected");
   fgKeywords.insert("public");
   fgKeywords.insert("register");
   fgKeywords.insert("reinterpret_cast");
   fgKeywords.insert("return");
   fgKeywords.insert("short");
   fgKeywords.insert("signed");
   fgKeywords.insert("sizeof");
   fgKeywords.insert("static");
   fgKeywords.insert("static_cast");
   fgKeywords.insert("struct");
   fgKeywords.insert("switch");
   fgKeywords.insert("template");
   fgKeywords.insert("this");
   fgKeywords.insert("throw");
   fgKeywords.insert("true");
   fgKeywords.insert("try");
   fgKeywords.insert("typedef");
   fgKeywords.insert("typeid");
   fgKeywords.insert("typename");
   fgKeywords.insert("union");
   fgKeywords.insert("unsigned");
   fgKeywords.insert("using");
   fgKeywords.insert("virtual");
   fgKeywords.insert("void");
   fgKeywords.insert("volatile");
   fgKeywords.insert("wchar_t");
   fgKeywords.insert("while");
}
TClass* TDocParser::IsDirective(const TString& line, Ssiz_t pos,
                                        const TString& word, Bool_t& begin) const
{
   
   
   
   
   
   
   
   if (pos > 0 &&  line[pos - 1] == '"')
      return 0;
   begin      = word.BeginsWith("begin_", TString::kIgnoreCase);
   Bool_t end = word.BeginsWith("end_", TString::kIgnoreCase);
   if (!begin && !end) 
      return 0;
   
   TString tag = word( begin ? 6 : 4, word.Length());
   if (!tag.Length())
      return 0;
   tag.ToLower();
   tag[0] -= 'a' - 'A'; 
   tag.Prepend("TDoc");
   tag += "Directive";
   TClass* clDirective = fHtml->GetClass(tag);
   if (!clDirective)
      Warning("IsDirective", "Unknown THtml directive %s in line %d!", word.Data(), fLineNo);
   return clDirective;
}
Bool_t TDocParser::IsName(UChar_t c)
{
   Bool_t ret = kFALSE;
   if (isalnum(c) || c == '_' || c == '~')
      ret = kTRUE;
   return ret;
}
Bool_t TDocParser::IsWord(UChar_t c)
{
   Bool_t ret = kFALSE;
   if (isalpha(c) || c == '_' || c == '~')
      ret = kTRUE;
   return ret;
}
TMethod* TDocParser::LocateMethodInCurrentLine(Ssiz_t &posMethodName, TString& ret, TString& name, TString& params,
                             std::ostream &srcOut, TString &anchor, std::ifstream& sourceFile, Bool_t allowPureVirtual)
{
   
   
   
   
   
   
   typedef std::map<std::string , Int_t > MethodCount_t;
   if (posMethodName == kNPOS) {
      name.Remove(0);
      TMethod * meth = 0;
      Ssiz_t posBlock = fLineRaw.Index('{');
      if (posBlock == kNPOS) 
         posBlock = fLineRaw.Length();
      for (MethodCount_t::iterator iMethodName = fMethodCounts.begin();
         !name.Length() && iMethodName != fMethodCounts.end(); ++iMethodName) {
         TString lookFor(iMethodName->first);
         posMethodName = fLineRaw.Index(lookFor);
         if (posMethodName != kNPOS && posMethodName < posBlock 
            && (posMethodName == 0 || !IsWord(fLineRaw[posMethodName - 1]))) {
            
            
            Ssiz_t posMethodEnd = posMethodName + lookFor.Length();
            while (isspace((UChar_t)fLineRaw[posMethodEnd])) ++posMethodEnd;
            if (fLineRaw[posMethodEnd] == '(') {
               meth = LocateMethodInCurrentLine(posMethodName, ret, name, params, srcOut, 
                                                anchor, sourceFile, allowPureVirtual);
               if (name.Length())
                  return meth;
            }
         }
      }
      return 0;
   }
   name = fLineRaw(posMethodName, fLineRaw.Length() - posMethodName);
   
   ret = fLineRaw(0, posMethodName);
   if (ret.Length()) {
      while (ret.Length() && (IsName(ret[ret.Length() - 1]) || ret[ret.Length()-1] == ':'))
         ret.Remove(ret.Length() - 1, 1);
      Strip(ret);
      Bool_t didSomething = kTRUE;
      while (didSomething) {
         didSomething = kFALSE;
         if (ret.BeginsWith("inline ")) {
            didSomething = kTRUE;
            ret.Remove(0, 7);
         }
         if (ret.BeginsWith("static ")) {
            didSomething = kTRUE;
            ret.Remove(0, 7);
         }
         if (ret.BeginsWith("virtual ")) {
            didSomething = kTRUE;
            ret.Remove(0, 8);
         }
      } 
      Strip(ret);
   }
   
   Ssiz_t posParam = name.First('(');
   if (posParam == kNPOS || 
      
      ret.Contains("{") || ret.Contains("}") || ret.Contains("(") || ret.Contains(")")
      || ret.Contains("=")) {
      ret.Remove(0);
      name.Remove(0);
      params.Remove(0);
      return 0;
   }
   if (name.BeginsWith("operator")) {
      
      Ssiz_t checkOpBracketParam = posParam + 1;
      while (isspace((UChar_t)name[checkOpBracketParam])) 
         ++checkOpBracketParam;
      if (name[checkOpBracketParam] == ')') {
         ++checkOpBracketParam;
         while (isspace((UChar_t)name[checkOpBracketParam]))
            ++checkOpBracketParam;
         if (name[checkOpBracketParam] == '(')
            posParam = checkOpBracketParam;
      }
   } 
   if (posParam == kNPOS) {
      ret.Remove(0);
      name.Remove(0);
      params.Remove(0);
      return 0;
   }
   params = name(posParam, name.Length() - posParam);
   name.Remove(posParam);
   while (isspace((UChar_t)name[name.Length() - 1]))
      name.Remove(name.Length() - 1);
   MethodCount_t::const_iterator iMethodName = fMethodCounts.find(name.Data());
   if (iMethodName == fMethodCounts.end() || iMethodName->second <= 0) {
      ret.Remove(0);
      name.Remove(0);
      params.Remove(0);
      return 0;
   }
   
   Ssiz_t posParamEnd = 1;
   Int_t bracketLevel = 1;
   while (bracketLevel) {
      const char* paramEnd = strpbrk(params.Data() + posParamEnd, ")(\"'");
      if (!paramEnd) {
         
         
         if (!anchor.Length()) {
            
            AnchorFromLine(anchor);
            if (srcOut)
               srcOut << "<a name=\"" << anchor << "\"></a>";
         }
         if (srcOut)
            WriteSourceLine(srcOut);
         fLineRaw.ReadLine(sourceFile, kFALSE);
         if (sourceFile.eof()) {
            Error("LocateMethodInCurrentLine", 
               "Cannot find end of signature for function %s!",
               name.Data());
            break;
         }
         fCommentAtBOL = kFALSE;
         
         fLineStripped = fLineRaw;
         Strip(fLineStripped);
         fLineSource = fLineRaw;
         DecorateKeywords(fLineSource);
         posParamEnd = params.Length();
         params += fLineRaw;
      } else
         posParamEnd = paramEnd - params.Data();
      switch (params[posParamEnd]) {
         case '(': ++bracketLevel; ++posParamEnd; break;
         case ')': --bracketLevel; ++posParamEnd; break;
         case '"': 
            ++posParamEnd;
            while (params.Length() > posParamEnd && params[posParamEnd] != '"') {
               
               if (params[posParamEnd] == '\\') ++posParamEnd;
               ++posParamEnd;
            }
            if (params.Length() <= posParamEnd) {
               
               ret.Remove(0);
               name.Remove(0);
               params.Remove(0);
               return 0;
            }
            ++posParamEnd; 
            break;
         case '\'': 
            ++posParamEnd;
            if (params[posParamEnd] == '\\') ++posParamEnd;
            posParamEnd += 2;
            break;
         default:
            ++posParamEnd;
      }
   } 
   Ssiz_t posBlock     = params.Index('{', posParamEnd);
   Ssiz_t posSemicolon = params.Index(';', posParamEnd);
   Ssiz_t posPureVirt  = params.Index('=', posParamEnd);
   if (posSemicolon != kNPOS)
      if ((posBlock == kNPOS || (posSemicolon < posBlock)) &&
         (posPureVirt == kNPOS || !allowPureVirtual)
         && !allowPureVirtual) 
         params.Remove(0);
   if (params.Length())
      params.Remove(posParamEnd);
   if (!params.Length()) {
      ret.Remove(0);
      name.Remove(0);
      return 0;
   }
   
   posMethodName = posParam + posParamEnd;
   if (fCurrentClass) {
      TMethod* meth = fCurrentClass->GetMethodAny(name);
      if (meth) {
         fDirectiveCount = 0;
         fCurrentMethodTag = name + "_";
         fCurrentMethodTag += fMethodCounts[name.Data()];
         return meth;
      }
   }
   return 0;
}
void TDocParser::Parse(std::ostream& out)
{
   
   
   
   LocateMethodsInSource(out);
   LocateMethodsInHeaderInline(out);
   LocateMethodsInHeaderClassDecl(out);
   if (!fSourceInfo[kInfoLastUpdate].Length()) {
      TDatime date;
      fSourceInfo[kInfoLastUpdate] = date.AsString();
   }
}
void TDocParser::LocateMethods(std::ostream& out, const char* filename,
                          Bool_t lookForSourceInfo , 
                          Bool_t useDocxxStyle , 
                          Bool_t lookForClassDescr ,
                          Bool_t allowPureVirtual ,
                          const char* methodPattern , 
                          const char* sourceExt )
{
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   
   TString sourceFileName(filename);
   fCurrentFile = filename;
   fHtml->GetSourceFileName(sourceFileName);
   if (!sourceFileName.Length()) {
      Error("LocateMethods", "Can't find source file '%s' for class %s!", 
         fHtml->GetImplFileName(fCurrentClass), fCurrentClass->GetName());
      return;
   }
   ifstream sourceFile(sourceFileName.Data());
   if (!sourceFile || !sourceFile.good()) {
      Error("LocateMethods", "Can't open file '%s' for reading!", sourceFileName.Data());
      return;
   }
   fLookForClassDescription = lookForClassDescr;
   TString pattern(methodPattern);
   TString codeOneLiner;
   TString methodRet;
   TString methodName;
   TString methodParam;
   TString anchor;
   Bool_t wroteMethodNowWaitingForOpenBlock = kFALSE;
   std::ofstream srcHtmlOut;
   TString srcHtmlOutName;
   if (sourceExt && sourceExt[0])
      dynamic_cast<TClassDocOutput*>(fDocOutput)->CreateSourceOutputStream(srcHtmlOut, sourceExt, srcHtmlOutName);
   else {
      sourceExt = 0;
      srcHtmlOutName = fCurrentClass->GetName();
      fDocOutput->NameSpace2FileName(srcHtmlOutName);
      gSystem->PrependPathName("src", srcHtmlOutName);
      srcHtmlOutName += ".h.html";
   }
   fParseContext.clear();
   fParseContext.push_back(kCode);
   fDocContext = kIgnore;
   fLineNo = 0;
   while (!sourceFile.eof()) {
      Bool_t needAnchor = kFALSE;
      ++fLineNo; 
      fLineRaw.ReadLine(sourceFile, kFALSE);
      if (sourceFile.eof()) break;
      fCommentAtBOL = InContext(kComment);
      
      fLineStripped = fLineRaw;
      Strip(fLineStripped);
      fLineSource = fLineRaw;
      fLineComment = "";
      DecorateKeywords(fLineSource);
      if (!ProcessComment()) {
         
         
         if (methodName.Length() && !wroteMethodNowWaitingForOpenBlock) {
            WriteMethod(out, methodRet, methodName, methodParam, 
               gSystem->BaseName(srcHtmlOutName), anchor, codeOneLiner);
         } else if (fDocContext == kDocClass) {
            
            dynamic_cast<TClassDocOutput*>(fDocOutput)->WriteClassDescription(out, fComment);
            fLookForClassDescription = kFALSE;
            fFoundClassDescription = kTRUE;
            fComment.Remove(0);
            fDocContext = kIgnore;
         }
         if (!wroteMethodNowWaitingForOpenBlock) {
            
            Ssiz_t posPattern = pattern.Length() ? fLineRaw.Index(pattern) : kNPOS;
            if (posPattern != kNPOS || !pattern.Length()) {
               posPattern += pattern.Length();
               LocateMethodInCurrentLine(posPattern, methodRet, methodName, 
                  methodParam, srcHtmlOut, anchor, sourceFile, allowPureVirtual);
               if (methodName.Length()) {
                  fDocContext = kDocFunc;
                  needAnchor = !anchor.Length();
                  if (!useDocxxStyle)
                     fComment.Remove(0);
                  codeOneLiner.Remove(0);
                  wroteMethodNowWaitingForOpenBlock = fLineRaw.Index("{", posPattern) == kNPOS;
                  wroteMethodNowWaitingForOpenBlock &= fLineRaw.Index(";", posPattern) == kNPOS;
               } else if (fLineRaw.First("{};") != kNPOS)
                  
                  fComment.Remove(0);
            } 
            else 
               fComment.Remove(0);
         } else {
            wroteMethodNowWaitingForOpenBlock &= fLineRaw.Index("{") == kNPOS;
            wroteMethodNowWaitingForOpenBlock &= fLineRaw.Index(";") == kNPOS;
         } 
         if (methodName.Length() && !wroteMethodNowWaitingForOpenBlock) {
            
            if (!codeOneLiner.Length() &&
                fLineSource.CountChar('{') == 1 && 
                fLineSource.CountChar('}') == 1) {
               
               codeOneLiner = fLineSource;
               codeOneLiner.Remove(0, codeOneLiner.Index('{'));
               codeOneLiner.Remove(codeOneLiner.Index('}') + 1);
            }
         } 
         if (needAnchor || fExtraLinesWithAnchor.find(fLineNo) != fExtraLinesWithAnchor.end()) {
            AnchorFromLine(anchor);
            if (sourceExt)
               srcHtmlOut << "<a name=\"" << anchor << "\"></a>";
         }
         
      } 
      
      Ssiz_t posTag = kNPOS;
      if (lookForSourceInfo)
         for (Int_t si = 0; si < (Int_t) kNumSourceInfos; ++si)
            if (!fSourceInfo[si].Length() && (posTag = fLineRaw.Index(fSourceInfoTags[si])) != kNPOS) {
               fSourceInfo[si] = fLineRaw(posTag + strlen(fSourceInfoTags[si]), fLineRaw.Length() - posTag);
               if (si == kInfoAuthor)
                  fDocOutput->FixupAuthorSourceInfo(fSourceInfo[kInfoAuthor]);
            }
      
      if (srcHtmlOut)
         WriteSourceLine(srcHtmlOut);
      else if (needAnchor)
         fExtraLinesWithAnchor.insert(fLineNo);
   } 
   
   if (methodName.Length()) {
      WriteMethod(out, methodRet, methodName, methodParam, 
         gSystem->BaseName(srcHtmlOutName), anchor, codeOneLiner);
   } else if (fDocContext == kDocClass) {
      
      out << fComment << "</div>" << std::endl;
   } else if (!fFoundClassDescription && fLookForClassDescription) {
      dynamic_cast<TClassDocOutput*>(fDocOutput)->WriteClassDescription(out, TString());
      fLookForClassDescription = kFALSE;
      fFoundClassDescription = kTRUE;
   }
   srcHtmlOut << "</pre>" << std::endl;
   fDocOutput->WriteHtmlFooter(srcHtmlOut, "../");
   fParseContext.clear();
   fParseContext.push_back(kCode);
   fDocContext = kIgnore;
   fCurrentFile = "";
}
void TDocParser::LocateMethodsInSource(std::ostream& out)
{
   
   
   
   
   Bool_t useDocxxStyle = (fHtml->GetDocStyle() == "Doc++");
   TString pattern(fCurrentClass->GetName());
   
   Ssiz_t posLastScope = kNPOS;
   while ((posLastScope = pattern.Index("::")) != kNPOS)
      pattern.Remove(0, posLastScope + 2);
   pattern += "::";
   
   const char* implFileName = fHtml->GetImplFileName(fCurrentClass);
   if (implFileName && implFileName[0])
      LocateMethods(out, implFileName, kTRUE, useDocxxStyle, kTRUE, 
         kFALSE, pattern, ".cxx.html");
   else out << "</div>" << endl; 
}
void TDocParser::LocateMethodsInHeaderInline(std::ostream& out)
{
   
   
   
   Bool_t useDocxxStyle = kTRUE; 
   TString pattern(fCurrentClass->GetName());
   
   Ssiz_t posLastScope = kNPOS;
   while ((posLastScope = pattern.Index("::")) != kNPOS)
      pattern.Remove(0, posLastScope + 1);
   pattern += "::";
   
   const char* declFileName = fHtml->GetDeclFileName(fCurrentClass);
   if (declFileName && declFileName[0])
      LocateMethods(out, declFileName, kFALSE, useDocxxStyle, fLookForClassDescription, 
         kFALSE, pattern, 0);
}
void TDocParser::LocateMethodsInHeaderClassDecl(std::ostream& out)
{
   
   
   
   const char* declFileName = fHtml->GetDeclFileName(fCurrentClass);
   if (declFileName && declFileName[0])
      LocateMethods(out, declFileName, kFALSE, kTRUE, kFALSE, kTRUE, 0, ".h.html");
}
Bool_t TDocParser::ProcessComment()
{
   
   
   
   
   
   if (!fCommentAtBOL
      && !(fLineStripped[0] == '/' 
         && (fLineStripped[1] == '/' || fLineStripped[1] == '*'))
      && !InContext(kComment) && !InContext(kDirective)) {
      fLineComment = "";
      return kFALSE;
   }
   
   
   
   if (InContext(kDirective) && !fLineComment.Length())
      return kTRUE;
   TString commentLine(fLineComment.Strip());
   
   Bool_t mustDealWithCommentAtBOL = fCommentAtBOL; 
   Ssiz_t posComment = kNPOS;
   if (!fCommentAtBOL) 
      posComment = commentLine.Index("<span class=\"comment\">", 0, TString::kIgnoreCase);
   Ssiz_t posSpanEnd = commentLine.Index("</span>", posComment == kNPOS?0:posComment, TString::kIgnoreCase);
   while (mustDealWithCommentAtBOL && posSpanEnd != kNPOS || posComment != kNPOS) {
      Int_t spanLevel = 1;
      Ssiz_t posSpan = commentLine.Index("<span", posComment + 1, TString::kIgnoreCase);
      while (spanLevel > 1 || posSpan != kNPOS && posSpan < posSpanEnd) {
         
         if (posSpan != kNPOS && posSpan < posSpanEnd) {
            ++spanLevel;
            posSpan = commentLine.Index("<span", posSpan + 1, TString::kIgnoreCase);
            
            continue;
         } 
         --spanLevel;
         
         posSpanEnd = commentLine.Index("</span>", posSpanEnd + 1, TString::kIgnoreCase);
      }
      if (posSpanEnd != kNPOS) {
          
         commentLine.Remove(posSpanEnd, 7);
         if (posComment != kNPOS) 
            commentLine.Remove(posComment, 22);
         else {
            mustDealWithCommentAtBOL = kFALSE;
            
            posComment = 0;
         }
         posComment = commentLine.Index("<span class=\"comment\">", posComment, TString::kIgnoreCase);
      } else break;
   }
   if (posComment != kNPOS)
      commentLine.Remove(posComment, 22);
   Strip(commentLine);
   
   if (!fFoundClassDescription && fLookForClassDescription && !fComment.Length() 
      && fDocContext == kIgnore && commentLine.Contains(fClassDescrTag)) {
      fDocContext = kDocClass;
      fFoundClassDescription = kTRUE;
      fLookForClassDescription = kFALSE;
   }
   char start_or_end = 0;
   
   if (commentLine.Length()>1 && commentLine[0] == '/' 
       && (commentLine[1] == '/' || commentLine[1] == '*')) {
      start_or_end = commentLine[1];
      commentLine.Remove(0, 2);
   }
   
   if (start_or_end != '/' && commentLine.Length()>1 
       && commentLine[commentLine.Length() - 2] == '*' 
       && commentLine[commentLine.Length() - 1] == '/') {
      start_or_end = commentLine[commentLine.Length() - 2];
      commentLine.Remove(commentLine.Length()-2);
   }
   
   if (start_or_end && commentLine.Length() > 3) {
      TString lineAllOneChar(commentLine.Strip());
      Ssiz_t len = lineAllOneChar.Length();
      if (len > 2) {
         Char_t c = lineAllOneChar[len - 1];
         if (c == lineAllOneChar[len - 2] && c == lineAllOneChar[len - 3]) {
            TString lineAllOneCharStripped = lineAllOneChar.Strip(TString::kTrailing, c);
            Strip(lineAllOneCharStripped);
            if (!lineAllOneCharStripped.Length()) {
               commentLine.Remove(0);
               
               if (!fFoundClassDescription && fLookForClassDescription && !fComment.Length() 
                   && fDocContext == kIgnore && start_or_end=='/') {
                  fDocContext = kDocClass;
                  fFoundClassDescription = kTRUE;
                  fLookForClassDescription = kFALSE;
               }
            }
         }
      }
   }
   
   if (commentLine.Length() > 0 && start_or_end == commentLine[commentLine.Length() - 1])
      
      commentLine = commentLine.Strip(TString::kTrailing, start_or_end);
   if (commentLine.Length() > 2 && Context() != kDirective)
      while (commentLine.Length() > 2
             && commentLine[0] == commentLine[commentLine.Length() - 1])
         commentLine = commentLine.Strip(TString::kBoth, commentLine[0]);
   
   
   while (start_or_end && commentLine[0] == start_or_end)
      commentLine.Remove(0, 1);
   fComment += commentLine + "\n";
   return kTRUE;
}
void TDocParser::RemoveCommentContext(Bool_t cxxcomment)
{
   
   UInt_t lookFor = kComment;
   if (cxxcomment) lookFor |= kCXXComment;
   std::list<UInt_t>::iterator iComment = fParseContext.end();
   for (std::list<UInt_t>::iterator iContext = fParseContext.begin();
      iContext != fParseContext.end(); ++ iContext)
      if (*iContext == lookFor) iComment =iContext;
   if (iComment != fParseContext.end())
      fParseContext.erase(iComment);
}
Bool_t TDocParser::Strip(TString& str)
{
   
   Bool_t changed = str[0] == ' ' || str[0] == '\t';
   changed |= str[str.Length()] == ' ' || str[str.Length()] == '\t';
   if (!changed) return kFALSE;
   Ssiz_t i = 0;
   while (str[i] == ' ' || str[i] == '\t')
      ++i;
   str.Remove(0,i);
   i = str.Length() - 1;
   while (i >= 0 && (str[i] == ' ' || str[i] == '\t'))
      --i;
   str.Remove(i + 1, str.Length());
   return kTRUE;
}
void TDocParser::WriteMethod(std::ostream& out, TString& ret, 
                        TString& name, TString& params,
                        const char* filename, TString& anchor, 
                        TString& codeOneLiner)
{
   
   
   if (!fFoundClassDescription && fLookForClassDescription) {
      dynamic_cast<TClassDocOutput*>(fDocOutput)->WriteClassDescription(out, TString());
      fLookForClassDescription = kFALSE;
      fFoundClassDescription = kTRUE;
   }
   TMethod* guessedMethod = 0;
   int nparams = params.CountChar(',');
   if (params.Length()) ++nparams;
   TMethod* method = 0;
   TIter nextMethod(fCurrentClass->GetListOfMethods());
   while ((method = (TMethod *) nextMethod()))
      if (name == method->GetName()
          && method->GetListOfMethodArgs()->GetSize() == nparams)
         if (guessedMethod) {
            
            guessedMethod = 0;
            break;
         } else
            guessedMethod = method;
   dynamic_cast<TClassDocOutput*>(fDocOutput)->WriteMethod(out, ret, name, params, filename, anchor,
                                                           fComment, codeOneLiner, guessedMethod);
   DecrementMethodCount(name);
   ret.Remove(0);
   name.Remove(0);
   params.Remove(0);
   anchor.Remove(0);
   fComment.Remove(0);
   fDocContext = kIgnore;
}
void TDocParser::WriteSourceLine(std::ostream& out)
{
   
   
   fDocOutput->AdjustSourcePath(fLineSource);
   out << fLineSource << std::endl;
}
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.