ROOT logo
// @(#)root/base:$Id$
// Author: Eddy Offermann   24/06/05

/*************************************************************************
 * Copyright (C) 1995-2005, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TPRegexp                                                             //
//                                                                      //
// C++ Wrapper for the "Perl Compatible Regular Expressions" library    //
//  The PCRE lib can be found at:                                       //
//              http://www.pcre.org/                                    //
//                                                                      //
// Extensive documentation about Regular expressions in Perl can be     //
// found at :                                                           //
//              http://perldoc.perl.org/perlre.html                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "Riostream.h"
#include "TPRegexp.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TError.h"

#include <pcre.h>

#include <vector>
#include <stdexcept>

struct PCREPriv_t {
   pcre       *fPCRE;
   pcre_extra *fPCREExtra;

   PCREPriv_t() { fPCRE = 0; fPCREExtra = 0; }
};


ClassImp(TPRegexp)

Bool_t TPRegexp::fgThrowAtCompileError = kFALSE;

//______________________________________________________________________________
TPRegexp::TPRegexp()
{
   // Default ctor.

   fPriv     = new PCREPriv_t;
   fPCREOpts = 0;
}

//______________________________________________________________________________
TPRegexp::TPRegexp(const TString &pat)
{
   // Create and initialize with pat.

   fPattern  = pat;
   fPriv     = new PCREPriv_t;
   fPCREOpts = 0;
}

//______________________________________________________________________________
TPRegexp::TPRegexp(const TPRegexp &p)
{
   // Copy ctor.

   fPattern  = p.fPattern;
   fPriv     = new PCREPriv_t;
   fPCREOpts = p.fPCREOpts;
}

//______________________________________________________________________________
TPRegexp::~TPRegexp()
{
   // Cleanup.

   if (fPriv->fPCRE)
      pcre_free(fPriv->fPCRE);
   if (fPriv->fPCREExtra)
      pcre_free(fPriv->fPCREExtra);
   delete fPriv;
}

//______________________________________________________________________________
TPRegexp &TPRegexp::operator=(const TPRegexp &p)
{
   // Assignement operator.

   if (this != &p) {
      fPattern = p.fPattern;
      if (fPriv->fPCRE)
         pcre_free(fPriv->fPCRE);
      fPriv->fPCRE = 0;
      if (fPriv->fPCREExtra)
         pcre_free(fPriv->fPCREExtra);
      fPriv->fPCREExtra = 0;
      fPCREOpts  = p.fPCREOpts;
   }
   return *this;
}

//______________________________________________________________________________
UInt_t TPRegexp::ParseMods(const TString &modStr) const
{
   // Translate Perl modifier flags into pcre flags.
   // The supported modStr characters are: g, i, m, o, s, x, and the
   // special d for debug. The meaning of the letters is:
   // - m
   //   Treat string as multiple lines. That is, change "^" and "$" from
   //   matching the start or end of the string to matching the start or
   //   end of any line anywhere within the string.
   // - s
   //   Treat string as single line. That is, change "." to match any
   //   character whatsoever, even a newline, which normally it would not match.
   //   Used together, as /ms, they let the "." match any character whatsoever,
   //   while still allowing "^" and "$" to match, respectively, just after and
   //   just before newlines within the string.
   // - i
   //   Do case-insensitive pattern matching.
   // - x
   //   Extend your pattern's legibility by permitting whitespace and comments.
   // - p
   //   Preserve the string matched such that ${^PREMATCH}, ${^MATCH},
   //   and ${^POSTMATCH} are available for use after matching.
   // - g and c
   //   Global matching, and keep the Current position after failed matching.
   //   Unlike i, m, s and x, these two flags affect the way the regex is used
   //   rather than the regex itself. See Using regular expressions in Perl in
   //   perlretut for further explanation of the g and c modifiers.
   // For more detail see: http://perldoc.perl.org/perlre.html#Modifiers.

   UInt_t opts = 0;

   if (modStr.Length() <= 0)
      return fPCREOpts;

   //translate perl flags into pcre flags
   const char *m = modStr;
   while (*m) {
      switch (*m) {
         case 'g':
            opts |= kPCRE_GLOBAL;
            break;
         case 'i':
            opts |= PCRE_CASELESS;
            break;
         case 'm':
            opts |= PCRE_MULTILINE;
            break;
         case 'o':
            opts |= kPCRE_OPTIMIZE;
            break;
         case 's':
            opts |= PCRE_DOTALL;
            break;
         case 'x':
            opts |= PCRE_EXTENDED;
            break;
         case 'd': // special flag to enable debug printing (not Perl compat.)
            opts |= kPCRE_DEBUG_MSGS;
            break;
         default:
            Error("ParseMods", "illegal pattern modifier: %c", *m);
            opts = 0;
      }
      ++m;
   }
   return opts;
}

//______________________________________________________________________________
TString TPRegexp::GetModifiers() const
{
   // Return PCRE modifier options as string.
   // For meaning of mods see ParseMods().

   TString ret;

   if (fPCREOpts & kPCRE_GLOBAL)     ret += 'g';
   if (fPCREOpts & PCRE_CASELESS)    ret += 'i';
   if (fPCREOpts & PCRE_MULTILINE)   ret += 'm';
   if (fPCREOpts & PCRE_DOTALL)      ret += 's';
   if (fPCREOpts & PCRE_EXTENDED)    ret += 'x';
   if (fPCREOpts & kPCRE_OPTIMIZE)   ret += 'o';
   if (fPCREOpts & kPCRE_DEBUG_MSGS) ret += 'd';

   return ret;
}

//______________________________________________________________________________
void TPRegexp::Compile()
{
   // Compile the fPattern.

   if (fPriv->fPCRE)
      pcre_free(fPriv->fPCRE);

   if (fPCREOpts & kPCRE_DEBUG_MSGS)
      Info("Compile", "PREGEX compiling %s", fPattern.Data());

   const char *errstr;
   Int_t patIndex;
   fPriv->fPCRE = pcre_compile(fPattern.Data(), fPCREOpts & kPCRE_INTMASK,
                               &errstr, &patIndex, 0);

   if (!fPriv->fPCRE) {
      if (fgThrowAtCompileError) {
         throw std::runtime_error
            (TString::Format("TPRegexp::Compile() compilation of TPRegexp(%s) failed at: %d because %s",
                             fPattern.Data(), patIndex, errstr).Data());
      } else {
         Error("Compile", "compilation of TPRegexp(%s) failed at: %d because %s",
               fPattern.Data(), patIndex, errstr);
         return;
      }
   }

   if (fPriv->fPCREExtra || (fPCREOpts & kPCRE_OPTIMIZE))
      Optimize();
}

//______________________________________________________________________________
void TPRegexp::Optimize()
{
   // Send the pattern through the optimizer.

   if (fPriv->fPCREExtra)
      pcre_free(fPriv->fPCREExtra);

   if (fPCREOpts & kPCRE_DEBUG_MSGS)
      Info("Optimize", "PREGEX studying %s", fPattern.Data());

   const char *errstr;
   // pcre_study allows less options - see pcre_internal.h PUBLIC_STUDY_OPTIONS.
   fPriv->fPCREExtra = pcre_study(fPriv->fPCRE, 0, &errstr);

   if (!fPriv->fPCREExtra && errstr) {
      Error("Optimize", "Optimization of TPRegexp(%s) failed: %s",
            fPattern.Data(), errstr);
   }
}

//______________________________________________________________________________
Int_t TPRegexp::ReplaceSubs(const TString &s, TString &final,
                            const TString &replacePattern,
                            Int_t *offVec, Int_t nrMatch) const
{
   // Returns the number of expanded '$' constructs.

   Int_t nrSubs = 0;
   const char *p = replacePattern;

   Int_t state = 0;
   Int_t subnum = 0;
   while (state != -1) {
      switch (state) {
         case 0:
            if (!*p) {
               state = -1;
               break;
            }
            if (*p == '$') {
               state = 1;
               subnum = 0;
               if (p[1] == '&') {
                  p++;
                  if (isdigit(p[1]))
                     p++;
               } else if (!isdigit(p[1])) {
                  Error("ReplaceSubs", "badly formed replacement pattern: %s",
                        replacePattern.Data());
               }
            } else
               final += *p;
            break;
         case 1:
            if (isdigit(*p)) {
               subnum *= 10;
               subnum += (*p)-'0';
            } else {
               if (fPCREOpts & kPCRE_DEBUG_MSGS)
                  Info("ReplaceSubs", "PREGEX appending substr #%d", subnum);
               if (subnum < 0 || subnum > nrMatch-1) {
                  Error("ReplaceSubs","bad string number: %d",subnum);
               } else {
                  const TString subStr = s(offVec[2*subnum],offVec[2*subnum+1]-offVec[2*subnum]);
                  final += subStr;
                  nrSubs++;
               }
               state = 0;
               continue;  // send char to start state
            }
      }
      p++;
   }
   return nrSubs;
}

//______________________________________________________________________________
Int_t TPRegexp::MatchInternal(const TString &s, Int_t start,
                              Int_t nMaxMatch, TArrayI *pos)
{
   // Perform the actual matching - protected method.

   Int_t *offVec = new Int_t[3*nMaxMatch];
   // pcre_exec allows less options - see pcre_internal.h PUBLIC_EXEC_OPTIONS.
   Int_t nrMatch = pcre_exec(fPriv->fPCRE, fPriv->fPCREExtra, s.Data(),
                             s.Length(), start, 0,
                             offVec, 3*nMaxMatch);

   if (nrMatch == PCRE_ERROR_NOMATCH)
      nrMatch = 0;
   else if (nrMatch <= 0) {
      Error("Match","pcre_exec error = %d", nrMatch);
      delete [] offVec;
      return 0;
   }

   if (pos)
      pos->Set(2*nrMatch, offVec);
   delete [] offVec;

   return nrMatch;
}

//______________________________________________________________________________
Int_t TPRegexp::Match(const TString &s, const TString &mods, Int_t start,
                      Int_t nMaxMatch, TArrayI *pos)
{
   // The number of matches is returned, this equals the full match +
   // sub-pattern matches.
   // nMaxMatch is the maximum allowed number of matches.
   // pos contains the string indices of the matches. Its usage is
   // shown in the routine MatchS.
   // For meaning of mods see ParseMods().

   UInt_t opts = ParseMods(mods);

   if (!fPriv->fPCRE || opts != fPCREOpts) {
      fPCREOpts = opts;
      Compile();
   }

   return MatchInternal(s, start, nMaxMatch, pos);
}


//______________________________________________________________________________
TObjArray *TPRegexp::MatchS(const TString &s, const TString &mods,
                            Int_t start, Int_t nMaxMatch)
{
   // Returns a TObjArray of matched substrings as TObjString's.
   // The TObjArray is owner of the objects and must be deleted by the user.
   // The first entry is the full matched pattern, followed by the subpatterns.
   // If a pattern was not matched, it will return an empty substring:
   //
   // TObjArray *subStrL = TPRegexp("(a|(z))(bc)").MatchS("abc");
   // for (Int_t i = 0; i < subStrL->GetLast()+1; i++) {
   //    const TString subStr = ((TObjString *)subStrL->At(i))->GetString();
   //    cout << "\"" << subStr << "\" ";
   // }
   // cout << subStr << endl;
   //
   // produces:  "abc" "a" "" "bc"
   // For meaning of mods see ParseMods().

   TArrayI pos;
   Int_t nrMatch = Match(s, mods, start, nMaxMatch, &pos);

   TObjArray *subStrL = new TObjArray();
   subStrL->SetOwner();

   for (Int_t i = 0; i < nrMatch; i++) {
      Int_t startp = pos[2*i];
      Int_t stopp  = pos[2*i+1];
      if (startp >= 0 && stopp >= 0) {
         const TString subStr = s(pos[2*i], pos[2*i+1]-pos[2*i]);
         subStrL->Add(new TObjString(subStr));
      } else
         subStrL->Add(new TObjString());
   }

   return subStrL;
}

//______________________________________________________________________________
Int_t TPRegexp::SubstituteInternal(TString &s, const TString &replacePattern,
                                   Int_t start, Int_t nMaxMatch,
                                   Bool_t doDollarSubst)
{
   // Perform pattern substitution with optional back-ref replacement
   // - protected method.

   Int_t *offVec = new Int_t[3*nMaxMatch];

   TString final;
   Int_t nrSubs = 0;
   Int_t offset = start;
   Int_t last = 0;

   while (kTRUE) {

      // find next matching subs
      // pcre_exec allows less options - see pcre_internal.h PUBLIC_EXEC_OPTIONS.
      Int_t nrMatch = pcre_exec(fPriv->fPCRE, fPriv->fPCREExtra, s.Data(),
                                s.Length(), offset, 0,
                                offVec, 3*nMaxMatch);

      if (nrMatch == PCRE_ERROR_NOMATCH) {
         nrMatch = 0;
         break;
      } else if (nrMatch <= 0) {
         Error("Substitute", "pcre_exec error = %d", nrMatch);
         break;
      }

      // append anything previously unmatched, but not substituted
      if (last <= offVec[0]) {
         final += s(last,offVec[0]-last);
         last = offVec[1];
      }

      // replace stuff in s
      if (doDollarSubst) {
         ReplaceSubs(s, final, replacePattern, offVec, nrMatch);
      } else {
         final += replacePattern;
      }
      ++nrSubs;

      // if global gotta check match at every pos
      if (!(fPCREOpts & kPCRE_GLOBAL))
         break;

      if (offVec[0] != offVec[1])
         offset = offVec[1];
      else {
         // matched empty string
         if (offVec[1] == s.Length())
         break;
         offset = offVec[1]+1;
      }
   }

   delete [] offVec;

   final += s(last,s.Length()-last);
   s = final;

   return nrSubs;
}

//______________________________________________________________________________
Int_t TPRegexp::Substitute(TString &s, const TString &replacePattern,
                           const TString &mods, Int_t start, Int_t nMaxMatch)
{
   // Substitute replaces the string s by a new string in which matching
   // patterns are replaced by the replacePattern string. The number of
   // substitutions are returned.
   //
   // TString s("aap noot mies");
   // const Int_t nrSub = TPRegexp("(\\w*) noot (\\w*)").Substitute(s,"$2 noot $1");
   // cout << nrSub << " \"" << s << "\"" <<endl;
   //
   // produces: 2 "mies noot aap"
   // For meaning of mods see ParseMods().

   UInt_t opts = ParseMods(mods);

   if (!fPriv->fPCRE || opts != fPCREOpts) {
      fPCREOpts = opts;
      Compile();
   }

   return SubstituteInternal(s, replacePattern, start, nMaxMatch, kTRUE);
}


//______________________________________________________________________________
Bool_t TPRegexp::IsValid() const
{
   // Returns true if underlying PCRE structure has been successfully
   // generated via regexp compilation.

   return fPriv->fPCRE != 0;
}

//______________________________________________________________________________
Bool_t TPRegexp::GetThrowAtCompileError()
{
   // Get value of static flag controlling whether exception should be thrown upon an
   // error during regular expression compilation by the PCRE engine.

   return fgThrowAtCompileError;
}

//______________________________________________________________________________
void TPRegexp::SetThrowAtCompileError(Bool_t throwp)
{
   // Set static flag controlling whether exception should be thrown upon an
   // error during regular expression compilation by the PCRE engine.

   fgThrowAtCompileError = throwp;
}

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TString member functions, put here so the linker will include        //
// them only if regular expressions are used.                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
Ssiz_t TString::Index(TPRegexp& r, Ssiz_t start) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Start is the offset at which the search should start.

   TArrayI pos;
   Int_t nrMatch = r.Match(*this,"",start,10,&pos);
   if (nrMatch > 0)
      return pos[0];
   else
      return -1;
}

//______________________________________________________________________________
Ssiz_t TString::Index(TPRegexp& r, Ssiz_t* extent, Ssiz_t start) const
{
   // Find the first occurance of the regexp in string and return the position.
   // Extent is length of the matched string and start is the offset at which
   // the matching should start.

   TArrayI pos;
   const Int_t nrMatch = r.Match(*this,"",start,10,&pos);
   if (nrMatch > 0) {
      *extent = pos[1]-pos[0];
      return pos[0];
   } else {
      *extent = 0;
      return -1;
   }
}

//______________________________________________________________________________
TSubString TString::operator()(TPRegexp& r, Ssiz_t start) const
{
   // Return the substring found by applying the regexp starting at start.

   Ssiz_t len;
   Ssiz_t begin = Index(r, &len, start);
   return TSubString(*this, begin, len);
}

//______________________________________________________________________________
TSubString TString::operator()(TPRegexp& r) const
{
   // Return the substring found by applying the regexp.

   return (*this)(r, 0);
}


//////////////////////////////////////////////////////////////////////////
// TPMERegexp
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
//
// Wrapper for PCRE library (Perl Compatible Regular Expressions).
// Based on PME - PCRE Made Easy by Zachary Hansen.
//
// Supports main Perl operations using regular expressions (Match,
// Substitute and Split). To retrieve the results one can simply use
// operator[] returning a TString.
//
// See $ROOTSYS/tutorials/regexp_pme.C for examples.

ClassImp(TPMERegexp);

//______________________________________________________________________________
TPMERegexp::TPMERegexp() :
   TPRegexp(),
   fNMaxMatches(10),
   fNMatches(0),
   fAddressOfLastString(0),
   fLastGlobalPosition(0)
{
   // Default constructor. This regexp will match an empty string.

   Compile();
}

//______________________________________________________________________________
TPMERegexp::TPMERegexp(const TString& s, const TString& opts, Int_t nMatchMax) :
   TPRegexp(s),
   fNMaxMatches(nMatchMax),
   fNMatches(0),
   fAddressOfLastString(0),
   fLastGlobalPosition(0)
{
   // Constructor:
   //  s    - string to compile into regular expression
   //  opts - perl-style character flags to be set on TPME object

   fPCREOpts = ParseMods(opts);
   Compile();
}

//______________________________________________________________________________
TPMERegexp::TPMERegexp(const TString& s, UInt_t opts, Int_t nMatchMax) :
   TPRegexp(s),
   fNMaxMatches(nMatchMax),
   fNMatches(0),
   fAddressOfLastString(0),
   fLastGlobalPosition(0)
{
   // Constructor:
   //  s    - string to copmile into regular expression
   //  opts - PCRE-style option flags to be set on TPME object

   fPCREOpts = opts;
   Compile();
}

//______________________________________________________________________________
TPMERegexp::TPMERegexp(const TPMERegexp& r) :
   TPRegexp(r),
   fNMaxMatches(r.fNMaxMatches),
   fNMatches(0),
   fAddressOfLastString(0),
   fLastGlobalPosition(0)
{
   // Copy constructor.
   // Only PCRE specifics are copied, not last-match or global-matech
   // information.

   Compile();
}

//______________________________________________________________________________
void TPMERegexp::Reset(const TString& s, const TString& opts, Int_t nMatchMax)
{
   // Reset the patteren and options.
   // If 'nMatchMax' other than -1 (the default) is passed, it is also set.

   Reset(s, ParseMods(opts), nMatchMax);
}

//______________________________________________________________________________
void TPMERegexp::Reset(const TString& s, UInt_t opts, Int_t nMatchMax)
{
   // Reset the patteren and options.
   // If 'nMatchMax' other than -1 (the default) is passed, it is also set.

   fPattern = s;
   fPCREOpts = opts;
   Compile();

   if (nMatchMax != -1)
      fNMatches = nMatchMax;
   fNMatches = 0;
   fLastGlobalPosition = 0;
}

//______________________________________________________________________________
void TPMERegexp::AssignGlobalState(const TPMERegexp& re)
{
   // Copy global-match state from 're; so that this regexp can continue
   // parsing the string from where 're' left off.
   //
   // Alternatively, GetGlobalPosition() get be used to retrieve the
   // last match position so that it can passed to Match().
   //
   // Ideally, as it is done in PERL, the last match position would be
   // stored in the TString itself.

   fLastStringMatched  = re.fLastStringMatched;
   fLastGlobalPosition = re.fLastGlobalPosition;
}

//______________________________________________________________________________
void TPMERegexp::ResetGlobalState()
{
   // Reset state of global match.
   // This happens automatically when a new string is passed for matching.
   // But be carefull, as the address of last TString object is used
   // to make this decision.

   fLastGlobalPosition = 0;
}

//______________________________________________________________________________
Int_t TPMERegexp::Match(const TString& s, UInt_t start)
{
   // Runs a match on s against the regex 'this' was created with.
   //
   // Args:
   //  s        - string to match against
   //  start    - offset at which to start matching
   // Returns:  - number of matches found

   // If we got a new string, reset the global position counter.
   if (fAddressOfLastString != (void*) &s) {
      fLastGlobalPosition = 0;
   }

   if (fPCREOpts & kPCRE_GLOBAL) {
      start += fLastGlobalPosition;
   }

   //fprintf(stderr, "string: '%s' length: %d offset: %d\n", s.Data(), s.length(), offset);
   fNMatches = MatchInternal(s, start, fNMaxMatches, &fMarkers);

   //fprintf(stderr, "MatchInternal_exec result = %d\n", fNMatches);

   fLastStringMatched   = s;
   fAddressOfLastString = (void*) &s;

   if (fPCREOpts & kPCRE_GLOBAL) {
      if (fNMatches == PCRE_ERROR_NOMATCH) {
         // fprintf(stderr, "TPME RESETTING: reset for no match\n");
         fLastGlobalPosition = 0; // reset the position for next match (perl does this)
      } else if (fNMatches > 0) {
         // fprintf(stderr, "TPME RESETTING: setting to %d\n", marks[0].second);
         fLastGlobalPosition = fMarkers[1]; // set to the end of the match
      } else {
         // fprintf(stderr, "TPME RESETTING: reset for no unknown\n");
         fLastGlobalPosition = 0;
      }
   }

   return fNMatches;
}

//______________________________________________________________________________
Int_t TPMERegexp::Split(const TString& s, Int_t maxfields)
{
   // Splits into at most maxfields. If maxfields is unspecified or
   // 0, trailing empty matches are discarded. If maxfields is
   // positive, no more than maxfields fields will be returned and
   // trailing empty matches are preserved. If maxfields is empty,
   // all fields (including trailing empty ones) are returned. This
   // *should* be the same as the perl behaviour.
   //
   // If pattern produces sub-matches, these are also stored in
   // the result.
   //
   // A pattern matching the null string will split the value of EXPR
   // into separate characters at each point it matches that way.
   //
   // Args:
   //  s         - string to split
   //  maxfields - maximum number of fields to be split out.  0 means
   //              split all fields, but discard any trailing empty bits.
   //              Negative means split all fields and keep trailing empty bits.
   //              Positive means keep up to N fields including any empty fields
   //              less than N. Anything remaining is in the last field.
   // Returns:   - number of fields found

   typedef std::pair<int, int>   MarkerLoc_t;
   typedef std::vector<MarkerLoc_t> MarkerLocVec_t;

   // stores the marks for the split
   MarkerLocVec_t oMarks;

   // this is a list of current trailing empty matches if maxfields is
   //   unspecified or 0.  If there is stuff in it and a non-empty match
   //   is found, then everything in here is pushed into oMarks and then
   //   the new match is pushed on.  If the end of the string is reached
   //   and there are empty matches in here, they are discarded.
   MarkerLocVec_t oCurrentTrailingEmpties;

   Int_t nOffset = 0;
   Int_t nMatchesFound = 0;

   // while we are still finding matches and maxfields is 0 or negative
   //   (meaning we get all matches), or we haven't gotten to the number
   //   of specified matches
   Int_t matchRes;
   while ((matchRes = Match(s, nOffset)) &&
          ((maxfields < 1) || nMatchesFound < maxfields)) {
      ++nMatchesFound;

      if (fMarkers[1] - fMarkers[0] == 0) {
         oMarks.push_back(MarkerLoc_t(nOffset, nOffset + 1));
         ++nOffset;
         if (nOffset >= s.Length())
            break;
         else
            continue;
      }

      // match can be empty
      if (nOffset != fMarkers[0]) {
         if (!oCurrentTrailingEmpties.empty()) {
            oMarks.insert(oMarks.end(),
                          oCurrentTrailingEmpties.begin(),
                          oCurrentTrailingEmpties.end());
            oCurrentTrailingEmpties.clear();
         }
         oMarks.push_back(MarkerLoc_t(nOffset, fMarkers[0]));
      } else {
         // empty match
         if (maxfields == 0) {
            // store for possible later inclusion
            oCurrentTrailingEmpties.push_back(MarkerLoc_t(nOffset, nOffset));
         } else {
            oMarks.push_back(MarkerLoc_t(nOffset, nOffset));
         }
      }

      nOffset = fMarkers[1];

      if (matchRes > 1) {
         for (Int_t i = 1; i < matchRes; ++i)
            oMarks.push_back(MarkerLoc_t(fMarkers[2*i], fMarkers[2*i + 1]));
      }
   }


   // if there were no matches found, push the whole thing on
   if (nMatchesFound == 0) {
      oMarks.push_back(MarkerLoc_t(0, s.Length()));
   }
   // if we ran out of matches, then append the rest of the string
   //   onto the end of the last split field
   else if (maxfields > 0 && nMatchesFound >= maxfields) {
      oMarks[oMarks.size() - 1].second = s.Length();
   }
   // else we have to add another entry for the end of the string
   else {
      Bool_t last_empty = (nOffset == s.Length());
      if (!last_empty || maxfields < 0) {
         if (!oCurrentTrailingEmpties.empty()) {
            oMarks.insert(oMarks.end(),
                          oCurrentTrailingEmpties.begin(),
                          oCurrentTrailingEmpties.end());
         }
         oMarks.push_back(MarkerLoc_t(nOffset, s.Length()));
      }
   }

   fNMatches = oMarks.size();
   fMarkers.Set(2*fNMatches);
   for (Int_t i = 0; i < fNMatches; ++i) {
      fMarkers[2*i]     = oMarks[i].first;
      fMarkers[2*i + 1] = oMarks[i].second;
   }

   // fprintf(stderr, "match returning %d\n", fNMatches);
   return fNMatches;
}

//______________________________________________________________________________
Int_t TPMERegexp::Substitute(TString& s, const TString& r, Bool_t doDollarSubst)
{
   // Substitute matching part of s with r, dollar back-ref
   // substitution is performed if doDollarSubst is true (default).
   // Returns the number of substitutions made.
   //
   // After the substitution, another pass is made over the resulting
   // string and the following special tokens are interpreted:
   // \l - lowercase next char,
   // \u - uppercase next char,
   // \L - lowercase till \E,
   // \U - uppercase till \E, and
   // \E - end case modification.

   Int_t cnt = SubstituteInternal(s, r, 0, fNMaxMatches, doDollarSubst);

   TString ret;
   Int_t   state = 0;
   Ssiz_t  pos = 0, len = s.Length();
   const Char_t *data = s.Data();
   while (pos < len) {
      Char_t c = data[pos];
      if (c == '\\') {
         c = data[pos+1]; // Rely on string-data being null-terminated.
         switch (c) {
            case  0 : ret += '\\'; break;
            case 'l': state = 1;   break;
            case 'u': state = 2;   break;
            case 'L': state = 3;   break;
            case 'U': state = 4;   break;
            case 'E': state = 0;   break;
            default : ret += '\\'; ret += c; break;
         }
         pos += 2;
      } else {
         switch (state) {
            case 0:  ret += c; break;
            case 1:  ret += (Char_t) tolower(c); state = 0; break;
            case 2:  ret += (Char_t) toupper(c); state = 0; break;
            case 3:  ret += (Char_t) tolower(c); break;
            case 4:  ret += (Char_t) toupper(c); break;
            default: Error("TPMERegexp::Substitute", "invalid state.");
         }
         ++pos;
      }
   }

   s = ret;

   return cnt;
}

//______________________________________________________________________________
TString TPMERegexp::operator[](int index)
{
   // Returns the sub-string from the internal fMarkers vector.
   // Requires having run match or split first.

   if (index >= fNMatches)
      return "";

   Int_t begin = fMarkers[2*index];
   Int_t end   = fMarkers[2*index + 1];
   return fLastStringMatched(begin, end-begin);
}

//______________________________________________________________________________
void TPMERegexp::Print(Option_t* option)
{
   // Print the regular expression and modifier options.
   // If 'option' contains "all", prints also last string match and
   // match results.

   TString opt = option;
   opt.ToLower();

   Printf("Regexp='%s', Opts='%s'", fPattern.Data(), GetModifiers().Data());
   if (opt.Contains("all")) {
      Printf("  last string='%s'", fLastStringMatched.Data());
      Printf("  number of matches = %d", fNMatches);
      for (Int_t i=0; i<fNMatches; ++i)
         Printf("  %d - %s", i, operator[](i).Data());
   }
}


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStringToken                                                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

//______________________________________________________________________________
//
// Provides iteration through tokens of a given string:
//
// - fFullStr     stores the string to be split. It is never modified.
// - fSplitRe     is the perl-re that is used to separete the tokens.
// - fReturnVoid  if true, empty strings will be returned.
//
// Current token is stored in the TString base-class.
// During construction no match is done, use NextToken() to get the first
// and all subsequent tokens.
//

ClassImp(TStringToken)

//______________________________________________________________________________
TStringToken::TStringToken(const TString& fullStr, const TString& splitRe, Bool_t retVoid) :
   fFullStr    (fullStr),
   fSplitRe    (splitRe),
   fReturnVoid (retVoid),
   fPos        (0)
{
   // Constructor.
}

//______________________________________________________________________________
Bool_t TStringToken::NextToken()
{
   // Get the next token, it is stored in this TString.
   // Returns true if new token is available, false otherwise.

   TArrayI x;
   while (fPos < fFullStr.Length()) {
      if (fSplitRe.Match(fFullStr, "", fPos, 2, &x)) {
         TString::operator=(fFullStr(fPos, x[0] - fPos));
         fPos = x[1];
      } else {
         TString::operator=(fFullStr(fPos, fFullStr.Length() - fPos));
         fPos = fFullStr.Length() + 1;
      }
      if (Length() || fReturnVoid)
         return kTRUE;
   }

   // Special case: void-strings are requested and the full-string
   // ends with the separator. Thus we return another empty string.
   if (fPos == fFullStr.Length() && fReturnVoid) {
      TString::operator=("");
      fPos = fFullStr.Length() + 1;
      return kTRUE;
   }

   return kFALSE;
}
 TPRegexp.cxx:1
 TPRegexp.cxx:2
 TPRegexp.cxx:3
 TPRegexp.cxx:4
 TPRegexp.cxx:5
 TPRegexp.cxx:6
 TPRegexp.cxx:7
 TPRegexp.cxx:8
 TPRegexp.cxx:9
 TPRegexp.cxx:10
 TPRegexp.cxx:11
 TPRegexp.cxx:12
 TPRegexp.cxx:13
 TPRegexp.cxx:14
 TPRegexp.cxx:15
 TPRegexp.cxx:16
 TPRegexp.cxx:17
 TPRegexp.cxx:18
 TPRegexp.cxx:19
 TPRegexp.cxx:20
 TPRegexp.cxx:21
 TPRegexp.cxx:22
 TPRegexp.cxx:23
 TPRegexp.cxx:24
 TPRegexp.cxx:25
 TPRegexp.cxx:26
 TPRegexp.cxx:27
 TPRegexp.cxx:28
 TPRegexp.cxx:29
 TPRegexp.cxx:30
 TPRegexp.cxx:31
 TPRegexp.cxx:32
 TPRegexp.cxx:33
 TPRegexp.cxx:34
 TPRegexp.cxx:35
 TPRegexp.cxx:36
 TPRegexp.cxx:37
 TPRegexp.cxx:38
 TPRegexp.cxx:39
 TPRegexp.cxx:40
 TPRegexp.cxx:41
 TPRegexp.cxx:42
 TPRegexp.cxx:43
 TPRegexp.cxx:44
 TPRegexp.cxx:45
 TPRegexp.cxx:46
 TPRegexp.cxx:47
 TPRegexp.cxx:48
 TPRegexp.cxx:49
 TPRegexp.cxx:50
 TPRegexp.cxx:51
 TPRegexp.cxx:52
 TPRegexp.cxx:53
 TPRegexp.cxx:54
 TPRegexp.cxx:55
 TPRegexp.cxx:56
 TPRegexp.cxx:57
 TPRegexp.cxx:58
 TPRegexp.cxx:59
 TPRegexp.cxx:60
 TPRegexp.cxx:61
 TPRegexp.cxx:62
 TPRegexp.cxx:63
 TPRegexp.cxx:64
 TPRegexp.cxx:65
 TPRegexp.cxx:66
 TPRegexp.cxx:67
 TPRegexp.cxx:68
 TPRegexp.cxx:69
 TPRegexp.cxx:70
 TPRegexp.cxx:71
 TPRegexp.cxx:72
 TPRegexp.cxx:73
 TPRegexp.cxx:74
 TPRegexp.cxx:75
 TPRegexp.cxx:76
 TPRegexp.cxx:77
 TPRegexp.cxx:78
 TPRegexp.cxx:79
 TPRegexp.cxx:80
 TPRegexp.cxx:81
 TPRegexp.cxx:82
 TPRegexp.cxx:83
 TPRegexp.cxx:84
 TPRegexp.cxx:85
 TPRegexp.cxx:86
 TPRegexp.cxx:87
 TPRegexp.cxx:88
 TPRegexp.cxx:89
 TPRegexp.cxx:90
 TPRegexp.cxx:91
 TPRegexp.cxx:92
 TPRegexp.cxx:93
 TPRegexp.cxx:94
 TPRegexp.cxx:95
 TPRegexp.cxx:96
 TPRegexp.cxx:97
 TPRegexp.cxx:98
 TPRegexp.cxx:99
 TPRegexp.cxx:100
 TPRegexp.cxx:101
 TPRegexp.cxx:102
 TPRegexp.cxx:103
 TPRegexp.cxx:104
 TPRegexp.cxx:105
 TPRegexp.cxx:106
 TPRegexp.cxx:107
 TPRegexp.cxx:108
 TPRegexp.cxx:109
 TPRegexp.cxx:110
 TPRegexp.cxx:111
 TPRegexp.cxx:112
 TPRegexp.cxx:113
 TPRegexp.cxx:114
 TPRegexp.cxx:115
 TPRegexp.cxx:116
 TPRegexp.cxx:117
 TPRegexp.cxx:118
 TPRegexp.cxx:119
 TPRegexp.cxx:120
 TPRegexp.cxx:121
 TPRegexp.cxx:122
 TPRegexp.cxx:123
 TPRegexp.cxx:124
 TPRegexp.cxx:125
 TPRegexp.cxx:126
 TPRegexp.cxx:127
 TPRegexp.cxx:128
 TPRegexp.cxx:129
 TPRegexp.cxx:130
 TPRegexp.cxx:131
 TPRegexp.cxx:132
 TPRegexp.cxx:133
 TPRegexp.cxx:134
 TPRegexp.cxx:135
 TPRegexp.cxx:136
 TPRegexp.cxx:137
 TPRegexp.cxx:138
 TPRegexp.cxx:139
 TPRegexp.cxx:140
 TPRegexp.cxx:141
 TPRegexp.cxx:142
 TPRegexp.cxx:143
 TPRegexp.cxx:144
 TPRegexp.cxx:145
 TPRegexp.cxx:146
 TPRegexp.cxx:147
 TPRegexp.cxx:148
 TPRegexp.cxx:149
 TPRegexp.cxx:150
 TPRegexp.cxx:151
 TPRegexp.cxx:152
 TPRegexp.cxx:153
 TPRegexp.cxx:154
 TPRegexp.cxx:155
 TPRegexp.cxx:156
 TPRegexp.cxx:157
 TPRegexp.cxx:158
 TPRegexp.cxx:159
 TPRegexp.cxx:160
 TPRegexp.cxx:161
 TPRegexp.cxx:162
 TPRegexp.cxx:163
 TPRegexp.cxx:164
 TPRegexp.cxx:165
 TPRegexp.cxx:166
 TPRegexp.cxx:167
 TPRegexp.cxx:168
 TPRegexp.cxx:169
 TPRegexp.cxx:170
 TPRegexp.cxx:171
 TPRegexp.cxx:172
 TPRegexp.cxx:173
 TPRegexp.cxx:174
 TPRegexp.cxx:175
 TPRegexp.cxx:176
 TPRegexp.cxx:177
 TPRegexp.cxx:178
 TPRegexp.cxx:179
 TPRegexp.cxx:180
 TPRegexp.cxx:181
 TPRegexp.cxx:182
 TPRegexp.cxx:183
 TPRegexp.cxx:184
 TPRegexp.cxx:185
 TPRegexp.cxx:186
 TPRegexp.cxx:187
 TPRegexp.cxx:188
 TPRegexp.cxx:189
 TPRegexp.cxx:190
 TPRegexp.cxx:191
 TPRegexp.cxx:192
 TPRegexp.cxx:193
 TPRegexp.cxx:194
 TPRegexp.cxx:195
 TPRegexp.cxx:196
 TPRegexp.cxx:197
 TPRegexp.cxx:198
 TPRegexp.cxx:199
 TPRegexp.cxx:200
 TPRegexp.cxx:201
 TPRegexp.cxx:202
 TPRegexp.cxx:203
 TPRegexp.cxx:204
 TPRegexp.cxx:205
 TPRegexp.cxx:206
 TPRegexp.cxx:207
 TPRegexp.cxx:208
 TPRegexp.cxx:209
 TPRegexp.cxx:210
 TPRegexp.cxx:211
 TPRegexp.cxx:212
 TPRegexp.cxx:213
 TPRegexp.cxx:214
 TPRegexp.cxx:215
 TPRegexp.cxx:216
 TPRegexp.cxx:217
 TPRegexp.cxx:218
 TPRegexp.cxx:219
 TPRegexp.cxx:220
 TPRegexp.cxx:221
 TPRegexp.cxx:222
 TPRegexp.cxx:223
 TPRegexp.cxx:224
 TPRegexp.cxx:225
 TPRegexp.cxx:226
 TPRegexp.cxx:227
 TPRegexp.cxx:228
 TPRegexp.cxx:229
 TPRegexp.cxx:230
 TPRegexp.cxx:231
 TPRegexp.cxx:232
 TPRegexp.cxx:233
 TPRegexp.cxx:234
 TPRegexp.cxx:235
 TPRegexp.cxx:236
 TPRegexp.cxx:237
 TPRegexp.cxx:238
 TPRegexp.cxx:239
 TPRegexp.cxx:240
 TPRegexp.cxx:241
 TPRegexp.cxx:242
 TPRegexp.cxx:243
 TPRegexp.cxx:244
 TPRegexp.cxx:245
 TPRegexp.cxx:246
 TPRegexp.cxx:247
 TPRegexp.cxx:248
 TPRegexp.cxx:249
 TPRegexp.cxx:250
 TPRegexp.cxx:251
 TPRegexp.cxx:252
 TPRegexp.cxx:253
 TPRegexp.cxx:254
 TPRegexp.cxx:255
 TPRegexp.cxx:256
 TPRegexp.cxx:257
 TPRegexp.cxx:258
 TPRegexp.cxx:259
 TPRegexp.cxx:260
 TPRegexp.cxx:261
 TPRegexp.cxx:262
 TPRegexp.cxx:263
 TPRegexp.cxx:264
 TPRegexp.cxx:265
 TPRegexp.cxx:266
 TPRegexp.cxx:267
 TPRegexp.cxx:268
 TPRegexp.cxx:269
 TPRegexp.cxx:270
 TPRegexp.cxx:271
 TPRegexp.cxx:272
 TPRegexp.cxx:273
 TPRegexp.cxx:274
 TPRegexp.cxx:275
 TPRegexp.cxx:276
 TPRegexp.cxx:277
 TPRegexp.cxx:278
 TPRegexp.cxx:279
 TPRegexp.cxx:280
 TPRegexp.cxx:281
 TPRegexp.cxx:282
 TPRegexp.cxx:283
 TPRegexp.cxx:284
 TPRegexp.cxx:285
 TPRegexp.cxx:286
 TPRegexp.cxx:287
 TPRegexp.cxx:288
 TPRegexp.cxx:289
 TPRegexp.cxx:290
 TPRegexp.cxx:291
 TPRegexp.cxx:292
 TPRegexp.cxx:293
 TPRegexp.cxx:294
 TPRegexp.cxx:295
 TPRegexp.cxx:296
 TPRegexp.cxx:297
 TPRegexp.cxx:298
 TPRegexp.cxx:299
 TPRegexp.cxx:300
 TPRegexp.cxx:301
 TPRegexp.cxx:302
 TPRegexp.cxx:303
 TPRegexp.cxx:304
 TPRegexp.cxx:305
 TPRegexp.cxx:306
 TPRegexp.cxx:307
 TPRegexp.cxx:308
 TPRegexp.cxx:309
 TPRegexp.cxx:310
 TPRegexp.cxx:311
 TPRegexp.cxx:312
 TPRegexp.cxx:313
 TPRegexp.cxx:314
 TPRegexp.cxx:315
 TPRegexp.cxx:316
 TPRegexp.cxx:317
 TPRegexp.cxx:318
 TPRegexp.cxx:319
 TPRegexp.cxx:320
 TPRegexp.cxx:321
 TPRegexp.cxx:322
 TPRegexp.cxx:323
 TPRegexp.cxx:324
 TPRegexp.cxx:325
 TPRegexp.cxx:326
 TPRegexp.cxx:327
 TPRegexp.cxx:328
 TPRegexp.cxx:329
 TPRegexp.cxx:330
 TPRegexp.cxx:331
 TPRegexp.cxx:332
 TPRegexp.cxx:333
 TPRegexp.cxx:334
 TPRegexp.cxx:335
 TPRegexp.cxx:336
 TPRegexp.cxx:337
 TPRegexp.cxx:338
 TPRegexp.cxx:339
 TPRegexp.cxx:340
 TPRegexp.cxx:341
 TPRegexp.cxx:342
 TPRegexp.cxx:343
 TPRegexp.cxx:344
 TPRegexp.cxx:345
 TPRegexp.cxx:346
 TPRegexp.cxx:347
 TPRegexp.cxx:348
 TPRegexp.cxx:349
 TPRegexp.cxx:350
 TPRegexp.cxx:351
 TPRegexp.cxx:352
 TPRegexp.cxx:353
 TPRegexp.cxx:354
 TPRegexp.cxx:355
 TPRegexp.cxx:356
 TPRegexp.cxx:357
 TPRegexp.cxx:358
 TPRegexp.cxx:359
 TPRegexp.cxx:360
 TPRegexp.cxx:361
 TPRegexp.cxx:362
 TPRegexp.cxx:363
 TPRegexp.cxx:364
 TPRegexp.cxx:365
 TPRegexp.cxx:366
 TPRegexp.cxx:367
 TPRegexp.cxx:368
 TPRegexp.cxx:369
 TPRegexp.cxx:370
 TPRegexp.cxx:371
 TPRegexp.cxx:372
 TPRegexp.cxx:373
 TPRegexp.cxx:374
 TPRegexp.cxx:375
 TPRegexp.cxx:376
 TPRegexp.cxx:377
 TPRegexp.cxx:378
 TPRegexp.cxx:379
 TPRegexp.cxx:380
 TPRegexp.cxx:381
 TPRegexp.cxx:382
 TPRegexp.cxx:383
 TPRegexp.cxx:384
 TPRegexp.cxx:385
 TPRegexp.cxx:386
 TPRegexp.cxx:387
 TPRegexp.cxx:388
 TPRegexp.cxx:389
 TPRegexp.cxx:390
 TPRegexp.cxx:391
 TPRegexp.cxx:392
 TPRegexp.cxx:393
 TPRegexp.cxx:394
 TPRegexp.cxx:395
 TPRegexp.cxx:396
 TPRegexp.cxx:397
 TPRegexp.cxx:398
 TPRegexp.cxx:399
 TPRegexp.cxx:400
 TPRegexp.cxx:401
 TPRegexp.cxx:402
 TPRegexp.cxx:403
 TPRegexp.cxx:404
 TPRegexp.cxx:405
 TPRegexp.cxx:406
 TPRegexp.cxx:407
 TPRegexp.cxx:408
 TPRegexp.cxx:409
 TPRegexp.cxx:410
 TPRegexp.cxx:411
 TPRegexp.cxx:412
 TPRegexp.cxx:413
 TPRegexp.cxx:414
 TPRegexp.cxx:415
 TPRegexp.cxx:416
 TPRegexp.cxx:417
 TPRegexp.cxx:418
 TPRegexp.cxx:419
 TPRegexp.cxx:420
 TPRegexp.cxx:421
 TPRegexp.cxx:422
 TPRegexp.cxx:423
 TPRegexp.cxx:424
 TPRegexp.cxx:425
 TPRegexp.cxx:426
 TPRegexp.cxx:427
 TPRegexp.cxx:428
 TPRegexp.cxx:429
 TPRegexp.cxx:430
 TPRegexp.cxx:431
 TPRegexp.cxx:432
 TPRegexp.cxx:433
 TPRegexp.cxx:434
 TPRegexp.cxx:435
 TPRegexp.cxx:436
 TPRegexp.cxx:437
 TPRegexp.cxx:438
 TPRegexp.cxx:439
 TPRegexp.cxx:440
 TPRegexp.cxx:441
 TPRegexp.cxx:442
 TPRegexp.cxx:443
 TPRegexp.cxx:444
 TPRegexp.cxx:445
 TPRegexp.cxx:446
 TPRegexp.cxx:447
 TPRegexp.cxx:448
 TPRegexp.cxx:449
 TPRegexp.cxx:450
 TPRegexp.cxx:451
 TPRegexp.cxx:452
 TPRegexp.cxx:453
 TPRegexp.cxx:454
 TPRegexp.cxx:455
 TPRegexp.cxx:456
 TPRegexp.cxx:457
 TPRegexp.cxx:458
 TPRegexp.cxx:459
 TPRegexp.cxx:460
 TPRegexp.cxx:461
 TPRegexp.cxx:462
 TPRegexp.cxx:463
 TPRegexp.cxx:464
 TPRegexp.cxx:465
 TPRegexp.cxx:466
 TPRegexp.cxx:467
 TPRegexp.cxx:468
 TPRegexp.cxx:469
 TPRegexp.cxx:470
 TPRegexp.cxx:471
 TPRegexp.cxx:472
 TPRegexp.cxx:473
 TPRegexp.cxx:474
 TPRegexp.cxx:475
 TPRegexp.cxx:476
 TPRegexp.cxx:477
 TPRegexp.cxx:478
 TPRegexp.cxx:479
 TPRegexp.cxx:480
 TPRegexp.cxx:481
 TPRegexp.cxx:482
 TPRegexp.cxx:483
 TPRegexp.cxx:484
 TPRegexp.cxx:485
 TPRegexp.cxx:486
 TPRegexp.cxx:487
 TPRegexp.cxx:488
 TPRegexp.cxx:489
 TPRegexp.cxx:490
 TPRegexp.cxx:491
 TPRegexp.cxx:492
 TPRegexp.cxx:493
 TPRegexp.cxx:494
 TPRegexp.cxx:495
 TPRegexp.cxx:496
 TPRegexp.cxx:497
 TPRegexp.cxx:498
 TPRegexp.cxx:499
 TPRegexp.cxx:500
 TPRegexp.cxx:501
 TPRegexp.cxx:502
 TPRegexp.cxx:503
 TPRegexp.cxx:504
 TPRegexp.cxx:505
 TPRegexp.cxx:506
 TPRegexp.cxx:507
 TPRegexp.cxx:508
 TPRegexp.cxx:509
 TPRegexp.cxx:510
 TPRegexp.cxx:511
 TPRegexp.cxx:512
 TPRegexp.cxx:513
 TPRegexp.cxx:514
 TPRegexp.cxx:515
 TPRegexp.cxx:516
 TPRegexp.cxx:517
 TPRegexp.cxx:518
 TPRegexp.cxx:519
 TPRegexp.cxx:520
 TPRegexp.cxx:521
 TPRegexp.cxx:522
 TPRegexp.cxx:523
 TPRegexp.cxx:524
 TPRegexp.cxx:525
 TPRegexp.cxx:526
 TPRegexp.cxx:527
 TPRegexp.cxx:528
 TPRegexp.cxx:529
 TPRegexp.cxx:530
 TPRegexp.cxx:531
 TPRegexp.cxx:532
 TPRegexp.cxx:533
 TPRegexp.cxx:534
 TPRegexp.cxx:535
 TPRegexp.cxx:536
 TPRegexp.cxx:537
 TPRegexp.cxx:538
 TPRegexp.cxx:539
 TPRegexp.cxx:540
 TPRegexp.cxx:541
 TPRegexp.cxx:542
 TPRegexp.cxx:543
 TPRegexp.cxx:544
 TPRegexp.cxx:545
 TPRegexp.cxx:546
 TPRegexp.cxx:547
 TPRegexp.cxx:548
 TPRegexp.cxx:549
 TPRegexp.cxx:550
 TPRegexp.cxx:551
 TPRegexp.cxx:552
 TPRegexp.cxx:553
 TPRegexp.cxx:554
 TPRegexp.cxx:555
 TPRegexp.cxx:556
 TPRegexp.cxx:557
 TPRegexp.cxx:558
 TPRegexp.cxx:559
 TPRegexp.cxx:560
 TPRegexp.cxx:561
 TPRegexp.cxx:562
 TPRegexp.cxx:563
 TPRegexp.cxx:564
 TPRegexp.cxx:565
 TPRegexp.cxx:566
 TPRegexp.cxx:567
 TPRegexp.cxx:568
 TPRegexp.cxx:569
 TPRegexp.cxx:570
 TPRegexp.cxx:571
 TPRegexp.cxx:572
 TPRegexp.cxx:573
 TPRegexp.cxx:574
 TPRegexp.cxx:575
 TPRegexp.cxx:576
 TPRegexp.cxx:577
 TPRegexp.cxx:578
 TPRegexp.cxx:579
 TPRegexp.cxx:580
 TPRegexp.cxx:581
 TPRegexp.cxx:582
 TPRegexp.cxx:583
 TPRegexp.cxx:584
 TPRegexp.cxx:585
 TPRegexp.cxx:586
 TPRegexp.cxx:587
 TPRegexp.cxx:588
 TPRegexp.cxx:589
 TPRegexp.cxx:590
 TPRegexp.cxx:591
 TPRegexp.cxx:592
 TPRegexp.cxx:593
 TPRegexp.cxx:594
 TPRegexp.cxx:595
 TPRegexp.cxx:596
 TPRegexp.cxx:597
 TPRegexp.cxx:598
 TPRegexp.cxx:599
 TPRegexp.cxx:600
 TPRegexp.cxx:601
 TPRegexp.cxx:602
 TPRegexp.cxx:603
 TPRegexp.cxx:604
 TPRegexp.cxx:605
 TPRegexp.cxx:606
 TPRegexp.cxx:607
 TPRegexp.cxx:608
 TPRegexp.cxx:609
 TPRegexp.cxx:610
 TPRegexp.cxx:611
 TPRegexp.cxx:612
 TPRegexp.cxx:613
 TPRegexp.cxx:614
 TPRegexp.cxx:615
 TPRegexp.cxx:616
 TPRegexp.cxx:617
 TPRegexp.cxx:618
 TPRegexp.cxx:619
 TPRegexp.cxx:620
 TPRegexp.cxx:621
 TPRegexp.cxx:622
 TPRegexp.cxx:623
 TPRegexp.cxx:624
 TPRegexp.cxx:625
 TPRegexp.cxx:626
 TPRegexp.cxx:627
 TPRegexp.cxx:628
 TPRegexp.cxx:629
 TPRegexp.cxx:630
 TPRegexp.cxx:631
 TPRegexp.cxx:632
 TPRegexp.cxx:633
 TPRegexp.cxx:634
 TPRegexp.cxx:635
 TPRegexp.cxx:636
 TPRegexp.cxx:637
 TPRegexp.cxx:638
 TPRegexp.cxx:639
 TPRegexp.cxx:640
 TPRegexp.cxx:641
 TPRegexp.cxx:642
 TPRegexp.cxx:643
 TPRegexp.cxx:644
 TPRegexp.cxx:645
 TPRegexp.cxx:646
 TPRegexp.cxx:647
 TPRegexp.cxx:648
 TPRegexp.cxx:649
 TPRegexp.cxx:650
 TPRegexp.cxx:651
 TPRegexp.cxx:652
 TPRegexp.cxx:653
 TPRegexp.cxx:654
 TPRegexp.cxx:655
 TPRegexp.cxx:656
 TPRegexp.cxx:657
 TPRegexp.cxx:658
 TPRegexp.cxx:659
 TPRegexp.cxx:660
 TPRegexp.cxx:661
 TPRegexp.cxx:662
 TPRegexp.cxx:663
 TPRegexp.cxx:664
 TPRegexp.cxx:665
 TPRegexp.cxx:666
 TPRegexp.cxx:667
 TPRegexp.cxx:668
 TPRegexp.cxx:669
 TPRegexp.cxx:670
 TPRegexp.cxx:671
 TPRegexp.cxx:672
 TPRegexp.cxx:673
 TPRegexp.cxx:674
 TPRegexp.cxx:675
 TPRegexp.cxx:676
 TPRegexp.cxx:677
 TPRegexp.cxx:678
 TPRegexp.cxx:679
 TPRegexp.cxx:680
 TPRegexp.cxx:681
 TPRegexp.cxx:682
 TPRegexp.cxx:683
 TPRegexp.cxx:684
 TPRegexp.cxx:685
 TPRegexp.cxx:686
 TPRegexp.cxx:687
 TPRegexp.cxx:688
 TPRegexp.cxx:689
 TPRegexp.cxx:690
 TPRegexp.cxx:691
 TPRegexp.cxx:692
 TPRegexp.cxx:693
 TPRegexp.cxx:694
 TPRegexp.cxx:695
 TPRegexp.cxx:696
 TPRegexp.cxx:697
 TPRegexp.cxx:698
 TPRegexp.cxx:699
 TPRegexp.cxx:700
 TPRegexp.cxx:701
 TPRegexp.cxx:702
 TPRegexp.cxx:703
 TPRegexp.cxx:704
 TPRegexp.cxx:705
 TPRegexp.cxx:706
 TPRegexp.cxx:707
 TPRegexp.cxx:708
 TPRegexp.cxx:709
 TPRegexp.cxx:710
 TPRegexp.cxx:711
 TPRegexp.cxx:712
 TPRegexp.cxx:713
 TPRegexp.cxx:714
 TPRegexp.cxx:715
 TPRegexp.cxx:716
 TPRegexp.cxx:717
 TPRegexp.cxx:718
 TPRegexp.cxx:719
 TPRegexp.cxx:720
 TPRegexp.cxx:721
 TPRegexp.cxx:722
 TPRegexp.cxx:723
 TPRegexp.cxx:724
 TPRegexp.cxx:725
 TPRegexp.cxx:726
 TPRegexp.cxx:727
 TPRegexp.cxx:728
 TPRegexp.cxx:729
 TPRegexp.cxx:730
 TPRegexp.cxx:731
 TPRegexp.cxx:732
 TPRegexp.cxx:733
 TPRegexp.cxx:734
 TPRegexp.cxx:735
 TPRegexp.cxx:736
 TPRegexp.cxx:737
 TPRegexp.cxx:738
 TPRegexp.cxx:739
 TPRegexp.cxx:740
 TPRegexp.cxx:741
 TPRegexp.cxx:742
 TPRegexp.cxx:743
 TPRegexp.cxx:744
 TPRegexp.cxx:745
 TPRegexp.cxx:746
 TPRegexp.cxx:747
 TPRegexp.cxx:748
 TPRegexp.cxx:749
 TPRegexp.cxx:750
 TPRegexp.cxx:751
 TPRegexp.cxx:752
 TPRegexp.cxx:753
 TPRegexp.cxx:754
 TPRegexp.cxx:755
 TPRegexp.cxx:756
 TPRegexp.cxx:757
 TPRegexp.cxx:758
 TPRegexp.cxx:759
 TPRegexp.cxx:760
 TPRegexp.cxx:761
 TPRegexp.cxx:762
 TPRegexp.cxx:763
 TPRegexp.cxx:764
 TPRegexp.cxx:765
 TPRegexp.cxx:766
 TPRegexp.cxx:767
 TPRegexp.cxx:768
 TPRegexp.cxx:769
 TPRegexp.cxx:770
 TPRegexp.cxx:771
 TPRegexp.cxx:772
 TPRegexp.cxx:773
 TPRegexp.cxx:774
 TPRegexp.cxx:775
 TPRegexp.cxx:776
 TPRegexp.cxx:777
 TPRegexp.cxx:778
 TPRegexp.cxx:779
 TPRegexp.cxx:780
 TPRegexp.cxx:781
 TPRegexp.cxx:782
 TPRegexp.cxx:783
 TPRegexp.cxx:784
 TPRegexp.cxx:785
 TPRegexp.cxx:786
 TPRegexp.cxx:787
 TPRegexp.cxx:788
 TPRegexp.cxx:789
 TPRegexp.cxx:790
 TPRegexp.cxx:791
 TPRegexp.cxx:792
 TPRegexp.cxx:793
 TPRegexp.cxx:794
 TPRegexp.cxx:795
 TPRegexp.cxx:796
 TPRegexp.cxx:797
 TPRegexp.cxx:798
 TPRegexp.cxx:799
 TPRegexp.cxx:800
 TPRegexp.cxx:801
 TPRegexp.cxx:802
 TPRegexp.cxx:803
 TPRegexp.cxx:804
 TPRegexp.cxx:805
 TPRegexp.cxx:806
 TPRegexp.cxx:807
 TPRegexp.cxx:808
 TPRegexp.cxx:809
 TPRegexp.cxx:810
 TPRegexp.cxx:811
 TPRegexp.cxx:812
 TPRegexp.cxx:813
 TPRegexp.cxx:814
 TPRegexp.cxx:815
 TPRegexp.cxx:816
 TPRegexp.cxx:817
 TPRegexp.cxx:818
 TPRegexp.cxx:819
 TPRegexp.cxx:820
 TPRegexp.cxx:821
 TPRegexp.cxx:822
 TPRegexp.cxx:823
 TPRegexp.cxx:824
 TPRegexp.cxx:825
 TPRegexp.cxx:826
 TPRegexp.cxx:827
 TPRegexp.cxx:828
 TPRegexp.cxx:829
 TPRegexp.cxx:830
 TPRegexp.cxx:831
 TPRegexp.cxx:832
 TPRegexp.cxx:833
 TPRegexp.cxx:834
 TPRegexp.cxx:835
 TPRegexp.cxx:836
 TPRegexp.cxx:837
 TPRegexp.cxx:838
 TPRegexp.cxx:839
 TPRegexp.cxx:840
 TPRegexp.cxx:841
 TPRegexp.cxx:842
 TPRegexp.cxx:843
 TPRegexp.cxx:844
 TPRegexp.cxx:845
 TPRegexp.cxx:846
 TPRegexp.cxx:847
 TPRegexp.cxx:848
 TPRegexp.cxx:849
 TPRegexp.cxx:850
 TPRegexp.cxx:851
 TPRegexp.cxx:852
 TPRegexp.cxx:853
 TPRegexp.cxx:854
 TPRegexp.cxx:855
 TPRegexp.cxx:856
 TPRegexp.cxx:857
 TPRegexp.cxx:858
 TPRegexp.cxx:859
 TPRegexp.cxx:860
 TPRegexp.cxx:861
 TPRegexp.cxx:862
 TPRegexp.cxx:863
 TPRegexp.cxx:864
 TPRegexp.cxx:865
 TPRegexp.cxx:866
 TPRegexp.cxx:867
 TPRegexp.cxx:868
 TPRegexp.cxx:869
 TPRegexp.cxx:870
 TPRegexp.cxx:871
 TPRegexp.cxx:872
 TPRegexp.cxx:873
 TPRegexp.cxx:874
 TPRegexp.cxx:875
 TPRegexp.cxx:876
 TPRegexp.cxx:877
 TPRegexp.cxx:878
 TPRegexp.cxx:879
 TPRegexp.cxx:880
 TPRegexp.cxx:881
 TPRegexp.cxx:882
 TPRegexp.cxx:883
 TPRegexp.cxx:884
 TPRegexp.cxx:885
 TPRegexp.cxx:886
 TPRegexp.cxx:887
 TPRegexp.cxx:888
 TPRegexp.cxx:889
 TPRegexp.cxx:890
 TPRegexp.cxx:891
 TPRegexp.cxx:892
 TPRegexp.cxx:893
 TPRegexp.cxx:894
 TPRegexp.cxx:895
 TPRegexp.cxx:896
 TPRegexp.cxx:897
 TPRegexp.cxx:898
 TPRegexp.cxx:899
 TPRegexp.cxx:900
 TPRegexp.cxx:901
 TPRegexp.cxx:902
 TPRegexp.cxx:903
 TPRegexp.cxx:904
 TPRegexp.cxx:905
 TPRegexp.cxx:906
 TPRegexp.cxx:907
 TPRegexp.cxx:908
 TPRegexp.cxx:909
 TPRegexp.cxx:910
 TPRegexp.cxx:911
 TPRegexp.cxx:912
 TPRegexp.cxx:913
 TPRegexp.cxx:914
 TPRegexp.cxx:915
 TPRegexp.cxx:916
 TPRegexp.cxx:917
 TPRegexp.cxx:918
 TPRegexp.cxx:919
 TPRegexp.cxx:920
 TPRegexp.cxx:921
 TPRegexp.cxx:922
 TPRegexp.cxx:923
 TPRegexp.cxx:924
 TPRegexp.cxx:925
 TPRegexp.cxx:926
 TPRegexp.cxx:927
 TPRegexp.cxx:928
 TPRegexp.cxx:929
 TPRegexp.cxx:930
 TPRegexp.cxx:931
 TPRegexp.cxx:932
 TPRegexp.cxx:933
 TPRegexp.cxx:934
 TPRegexp.cxx:935
 TPRegexp.cxx:936
 TPRegexp.cxx:937
 TPRegexp.cxx:938
 TPRegexp.cxx:939
 TPRegexp.cxx:940
 TPRegexp.cxx:941
 TPRegexp.cxx:942
 TPRegexp.cxx:943
 TPRegexp.cxx:944
 TPRegexp.cxx:945
 TPRegexp.cxx:946
 TPRegexp.cxx:947
 TPRegexp.cxx:948
 TPRegexp.cxx:949
 TPRegexp.cxx:950
 TPRegexp.cxx:951
 TPRegexp.cxx:952
 TPRegexp.cxx:953
 TPRegexp.cxx:954
 TPRegexp.cxx:955
 TPRegexp.cxx:956
 TPRegexp.cxx:957
 TPRegexp.cxx:958
 TPRegexp.cxx:959
 TPRegexp.cxx:960
 TPRegexp.cxx:961
 TPRegexp.cxx:962
 TPRegexp.cxx:963
 TPRegexp.cxx:964
 TPRegexp.cxx:965
 TPRegexp.cxx:966
 TPRegexp.cxx:967
 TPRegexp.cxx:968
 TPRegexp.cxx:969
 TPRegexp.cxx:970
 TPRegexp.cxx:971
 TPRegexp.cxx:972
 TPRegexp.cxx:973
 TPRegexp.cxx:974
 TPRegexp.cxx:975
 TPRegexp.cxx:976
 TPRegexp.cxx:977
 TPRegexp.cxx:978
 TPRegexp.cxx:979
 TPRegexp.cxx:980
 TPRegexp.cxx:981
 TPRegexp.cxx:982
 TPRegexp.cxx:983
 TPRegexp.cxx:984
 TPRegexp.cxx:985
 TPRegexp.cxx:986
 TPRegexp.cxx:987
 TPRegexp.cxx:988
 TPRegexp.cxx:989
 TPRegexp.cxx:990
 TPRegexp.cxx:991
 TPRegexp.cxx:992
 TPRegexp.cxx:993
 TPRegexp.cxx:994
 TPRegexp.cxx:995
 TPRegexp.cxx:996
 TPRegexp.cxx:997
 TPRegexp.cxx:998
 TPRegexp.cxx:999
 TPRegexp.cxx:1000
 TPRegexp.cxx:1001
 TPRegexp.cxx:1002
 TPRegexp.cxx:1003
 TPRegexp.cxx:1004
 TPRegexp.cxx:1005
 TPRegexp.cxx:1006
 TPRegexp.cxx:1007