diff --git a/Makefile b/Makefile index 73c6e9e64512c142b04b767deae44757828b34ab..55e4beea83fc5320dc2e52c1174b9b7b8d620188 100644 --- a/Makefile +++ b/Makefile @@ -42,9 +42,9 @@ endif ##### Modules to build ##### -MODULES = build cint metautils utils base cont meta net auth zip clib \ - matrix newdelete hist tree freetype graf g3d gpad gui minuit \ - histpainter treeplayer treeviewer physics postscript \ +MODULES = build cint metautils pcre utils base cont meta net auth zip \ + clib matrix newdelete hist tree freetype graf g3d gpad gui \ + minuit histpainter treeplayer treeviewer physics postscript \ rint html eg geom geompainter vmc fumili mlp gedold ged quadp \ guibuilder xml foam splot smatrix @@ -441,15 +441,15 @@ G__%.d: G__%.cxx $(RMKDEP) %.d: %.cxx $(RMKDEP) $(MAKEDEP) $@ "$(CXXFLAGS)" $< > $@ -$(CORELIB): $(COREO) $(COREDO) $(CINTLIB) $(CORELIBDEP) +$(CORELIB): $(COREO) $(COREDO) $(CINTLIB) $(PCREDEP) $(CORELIBDEP) ifneq ($(ARCH),alphacxx6) @$(MAKELIB) $(PLATFORM) $(LD) "$(LDFLAGS)" \ "$(SOFLAGS)" libCore.$(SOEXT) $@ "$(COREO) $(COREDO)" \ - "$(CORELIBEXTRA) $(CRYPTLIBS)" + "$(CORELIBEXTRA) $(PCRELDFLAGS) $(PCRELIB) $(CRYPTLIBS)" else @$(MAKELIB) $(PLATFORM) $(LD) "$(CORELDFLAGS)" \ "$(SOFLAGS)" libCore.$(SOEXT) $@ "$(COREO) $(COREDO)" \ - "$(CORELIBEXTRA) $(CRYPTLIBS)" + "$(CORELIBEXTRA) $(PCRELDFLAGS) $(PCRELIB) $(CRYPTLIBS)" endif map:: $(RLIBMAP) diff --git a/base/Module.mk b/base/Module.mk index e2aab2a616e5422ae82af43daec8f6f55f1278c7..d323925b8d6ba5e0e3c5952e7a2357af263238c1 100644 --- a/base/Module.mk +++ b/base/Module.mk @@ -79,10 +79,10 @@ $(BASEDS4): @echo "Generating dictionary $@..." $(ROOTCINTTMP) -f $@ -c $(BASEH4) $(BASEL4) -$(BASEDO1): $(BASEDS1) - $(CXX) $(NOOPT) $(CXXFLAGS) -I. -o $@ -c $< -$(BASEDO2): $(BASEDS2) - $(CXX) $(NOOPT) $(CXXFLAGS) -I. -o $@ -c $< +$(BASEDO1): $(BASEDS1) $(PCREDEP) + $(CXX) $(NOOPT) $(PCREINC) $(CXXFLAGS) -I. -o $@ -c $< +$(BASEDO2): $(BASEDS2) $(PCREDEP) + $(CXX) $(NOOPT) $(PCREINC) $(CXXFLAGS) -I. -o $@ -c $< ifeq ($(ARCH),linuxicc) $(BASEDO3): $(BASEDS3) $(CXX) $(NOOPT) $(CXXFLAGS) -wd191 -I. -o $@ -c $< @@ -108,6 +108,9 @@ distclean-base: clean-base distclean:: distclean-base ##### extra rules ###### +base/src/TPRegexp.o: base/src/TPRegexp.cxx $(PCREDEP) + $(CXX) $(OPT) $(PCREINC) $(CXXFLAGS) -o $@ -c $< + ifeq ($(ARCH),alphacxx6) $(BASEDIRS)/TRandom.o: $(BASEDIRS)/TRandom.cxx $(CXX) $(NOOPT) $(CXXFLAGS) -o $@ -c $< diff --git a/base/inc/LinkDef2.h b/base/inc/LinkDef2.h index 6a1b4a5d72714aed055e06d9e39b51c513200673..dbbc99c33a6154bf482318d8befafffb4306a214 100644 --- a/base/inc/LinkDef2.h +++ b/base/inc/LinkDef2.h @@ -1,4 +1,4 @@ -/* @(#)root/base:$Name: $:$Id: LinkDef2.h,v 1.29 2004/11/03 11:05:12 rdm Exp $ */ +/* @(#)root/base:$Name: $:$Id: LinkDef2.h,v 1.30 2005/08/16 12:57:57 brun Exp $ */ /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * @@ -102,6 +102,7 @@ #pragma link C++ class TROOT; #pragma link C++ class TRealData+; #pragma link C++ class TRegexp; +#pragma link C++ class TPRegexp; #pragma link C++ class TRefCnt; #pragma link C++ class TSignalHandler; #pragma link C++ class TStopwatch+; diff --git a/base/inc/TPRegexp.h b/base/inc/TPRegexp.h new file mode 100644 index 0000000000000000000000000000000000000000..7d5a08a5c483127c39a4a878e7d4365e2df6661f --- /dev/null +++ b/base/inc/TPRegexp.h @@ -0,0 +1,85 @@ +// @(#)root/base:$Name: $:$Id: TRegexp.h,v 1.1.1.1 2000/05/16 17:00:39 rdm Exp $ +// 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. * + *************************************************************************/ + +#ifndef ROOT_TPRegexp +#define ROOT_TPRegexp + +////////////////////////////////////////////////////////////////////////// +// // +// 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 // +// // +////////////////////////////////////////////////////////////////////////// + +#ifndef ROOT_Rtypes +#include "Rtypes.h" +#endif +#ifndef ROOT_TString +#include "TString.h" +#endif +#ifndef ROOT_TArrayI +#include "TArrayI.h" +#endif + +struct PCREPriv_t; + + +class TPRegexp { + +private: + enum { + kPCRE_GLOBAL = 0x80000000, + kPCRE_OPTIMIZE = 0x40000000, + kPCRE_DEBUG_MSGS = 0x20000000, + kPCRE_INTMASK = 0x0FFF, + }; + + TString fPattern; + PCREPriv_t *fPriv; + UInt_t fPCREOpts; + + void Compile(); + void Optimize(); + UInt_t ParseMods(const TString &mods) const; + Int_t ReplaceSubs(const TString &s, TString &final, + const TString &replacePattern, + Int_t *ovec, Int_t nmatch) const; + +public: + TPRegexp(); + TPRegexp(const TString &pat); + TPRegexp(const TPRegexp &p); + virtual ~TPRegexp(); + + Int_t Match(const TString &s, const TString &mods="", + Int_t offset=0, Int_t nMatchMax=30, TArrayI *pos=0); + TObjArray *MatchS(const TString &s, const TString &mods="", + Int_t offset=0, Int_t nMaxMatch=30); + Bool_t MatchB(const TString &s, const TString &mods="", + Int_t offset=0, Int_t nMaxMatch=30) { + return (Match(s,mods,offset,nMaxMatch) > 0); } + Int_t Substitute(TString &s, const TString &replace, + const TString &mods="", Int_t offset=0, + Int_t nMatchMax=30); + + TPRegexp &operator=(const TPRegexp &p); + + ClassDef(TPRegexp,0) // Perl Compatible Regular Expression Class +}; + +#endif diff --git a/base/inc/TString.h b/base/inc/TString.h index 39394d5b7354e5ee1886b066e88e9d13f9ebe754..c70e1a15cba3670ea13364dc5480bcc3d30f2816 100644 --- a/base/inc/TString.h +++ b/base/inc/TString.h @@ -1,4 +1,4 @@ -// @(#)root/base:$Name: $:$Id: TString.h,v 1.40 2005/08/15 21:21:46 pcanal Exp $ +// @(#)root/base:$Name: $:$Id: TString.h,v 1.41 2005/11/21 11:17:18 rdm Exp $ // Author: Fons Rademakers 04/08/95 /************************************************************************* @@ -47,6 +47,7 @@ namespace std { using ::string; } #endif class TRegexp; +class TPRegexp; class TString; class TSubString; class TObjArray; @@ -272,6 +273,8 @@ public: TSubString operator()(Ssiz_t start, Ssiz_t len); // Sub-string operator TSubString operator()(const TRegexp &re); // Match the RE TSubString operator()(const TRegexp &re, Ssiz_t start); + TSubString operator()(TPRegexp &re); // Match the Perl compatible Regular Expression + TSubString operator()(TPRegexp &re, Ssiz_t start); TSubString SubString(const char *pat, Ssiz_t start = 0, ECaseCompare cmp = kExact); char operator[](Ssiz_t i) const; @@ -279,6 +282,8 @@ public: TSubString operator()(Ssiz_t start, Ssiz_t len) const; TSubString operator()(const TRegexp &re) const; // Match the RE TSubString operator()(const TRegexp &re, Ssiz_t start) const; + TSubString operator()(TPRegexp &re) const; // Match the Perl compatible Regular Expression + TSubString operator()(TPRegexp &re, Ssiz_t start) const; TSubString SubString(const char *pat, Ssiz_t start = 0, ECaseCompare cmp = kExact) const; @@ -300,6 +305,7 @@ public: Bool_t Contains(const char *pat, ECaseCompare cmp = kExact) const; Bool_t Contains(const TString &pat, ECaseCompare cmp = kExact) const; Bool_t Contains(const TRegexp &pat) const; + Bool_t Contains(TPRegexp &pat) const; Int_t CountChar(Int_t c) const; TString Copy() const; const char *Data() const { return fData; } @@ -318,6 +324,8 @@ public: ECaseCompare cmp) const; Ssiz_t Index(const TRegexp &pat, Ssiz_t i = 0) const; Ssiz_t Index(const TRegexp &pat, Ssiz_t *ext, Ssiz_t i = 0) const; + Ssiz_t Index(TPRegexp &pat, Ssiz_t i = 0) const; + Ssiz_t Index(TPRegexp &pat, Ssiz_t *ext, Ssiz_t i = 0) const; TString &Insert(Ssiz_t pos, const char *s); TString &Insert(Ssiz_t pos, const char *s, Ssiz_t extent); TString &Insert(Ssiz_t pos, const TString &s); @@ -326,6 +334,7 @@ public: Bool_t IsAlpha() const; Bool_t IsAlnum() const; Bool_t IsDigit() const; + Bool_t IsFloat() const; Bool_t IsHex() const; Bool_t IsNull() const { return Pref()->fNchars == 0; } Ssiz_t Last(char c) const { return Pref()->Last(c); } @@ -415,12 +424,6 @@ extern int strncasecmp(const char *str1, const char *str2, Ssiz_t n); inline void TStringRef::UnLink() { if (RemoveReference() == 0) delete [] (char*)this; } -inline Int_t TString::Atoi() const -{ return atoi(fData); } - -inline Double_t TString::Atof() const -{ return atof(fData); } - inline void TString::Cow() { if (Pref()->References() > 1) Clone(); } @@ -493,6 +496,9 @@ inline Bool_t TString::Contains(const char *s, ECaseCompare cmp) const inline Bool_t TString::Contains(const TRegexp &pat) const { return Index(pat, (Ssiz_t)0) != kNPOS; } +inline Bool_t TString::Contains(TPRegexp &pat) const +{ return Index(pat, (Ssiz_t)0) != kNPOS; } + inline Ssiz_t TString::Index(const char *s, Ssiz_t i, ECaseCompare cmp) const { return Index(s, s ? strlen(s) : 0, i, cmp); } diff --git a/base/src/TPRegexp.cxx b/base/src/TPRegexp.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1456973ac3ba39c1fe5f4fe594489230f3a1b45c --- /dev/null +++ b/base/src/TPRegexp.cxx @@ -0,0 +1,470 @@ +// @(#)root/base:$Name: $:$Id: TRegexp.h,v 1.1.1.1 2000/05/16 17:00:39 rdm Exp $ +// 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> + + +struct PCREPriv_t { + pcre *fPCRE; + pcre_extra *fPCREExtra; + + PCREPriv_t() { fPCRE = 0; fPCREExtra = 0; } +}; + + +ClassImp(TPRegexp) + +//______________________________________________________________________________ +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. + + 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; +} + +//______________________________________________________________________________ +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) { + Error("Compile", "compilation of TPRegexp(%s) failed at: %d because %s", + fPattern.Data(), patIndex, errstr); + } + + 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; + fPriv->fPCREExtra = pcre_study(fPriv->fPCRE, fPCREOpts & kPCRE_INTMASK, &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 +{ + // Return the number of substitutions. + + 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); + } + 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::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. + + UInt_t opts = ParseMods(mods); + + if (!fPriv->fPCRE || opts != fPCREOpts) { + fPCREOpts = opts; + Compile(); + } + + Int_t *offVec = new Int_t[nMaxMatch]; + Int_t nrMatch = pcre_exec(fPriv->fPCRE, fPriv->fPCREExtra, s.Data(), + s.Length(), start, fPCREOpts & kPCRE_INTMASK, + offVec, 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->Adopt(2*nrMatch, offVec); + else + delete [] offVec; + + return nrMatch; +} + +//______________________________________________________________________________ +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. 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" + + 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 start = pos[2*i]; + Int_t stop = pos[2*i+1]; + if (start >= 0 && stop >= 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::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" + + UInt_t opts = ParseMods(mods); + Int_t nrSubs = 0; + TString final; + + if (!fPriv->fPCRE || opts != fPCREOpts) { + fPCREOpts = opts; + Compile(); + } + + Int_t *offVec = new Int_t[nMaxMatch]; + + Int_t offset = start; + Int_t last = 0; + + while (kTRUE) { + + // find next matching subs + Int_t nrMatch = pcre_exec(fPriv->fPCRE, fPriv->fPCREExtra, s.Data(), + s.Length(), offset, fPCREOpts & kPCRE_INTMASK, + offVec, nMaxMatch); + + if (nrMatch == PCRE_ERROR_NOMATCH) { + nrMatch = 0; + break; + } else if (nrMatch <= 0) + Error("Substitute", "pcre_exec error = %d", nrMatch); + + // append anything previously unmatched, but not substituted + if (last <= offVec[0]) { + final += s(last,offVec[0]-last); + last = offVec[1]; + } + + // replace stuff in s + nrSubs += ReplaceSubs(s, final, replacePattern, offVec, nrMatch); + + // 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; +} + + +////////////////////////////////////////////////////////////////////////// +// // +// 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,30,&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,30,&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) +{ + // 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) +{ + // Return the substring found by applying the regexp. + + return (*this)(r,0); +} + +//______________________________________________________________________________ +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); +} diff --git a/base/src/TString.cxx b/base/src/TString.cxx index 85093f4790a22b9a9ecfd4d77f5c1c5514e92bba..91150a4c6d627fc27be5399484f983037f0a430c 100644 --- a/base/src/TString.cxx +++ b/base/src/TString.cxx @@ -1,4 +1,4 @@ -// @(#)root/base:$Name: $:$Id: TString.cxx,v 1.44 2005/11/16 20:04:11 pcanal Exp $ +// @(#)root/base:$Name: $:$Id: TString.cxx,v 1.45 2005/11/21 11:17:18 rdm Exp $ // Author: Fons Rademakers 04/08/95 /************************************************************************* @@ -1489,18 +1489,62 @@ Bool_t TString::IsAlnum() const //______________________________________________________________________________ Bool_t TString::IsDigit() const { - // Returns true if all characters in string are digits (0-9). - // Returns false in case string length is 0. + // Returns true if all characters in string are digits (0-9) or whitespaces, + // i.e. "123456" and "123 456" are both valid integer strings. + // Returns false in case string length is 0 or string contains other + // characters. const char *cp = Data(); Ssiz_t len = Length(); if (len == 0) return kFALSE; - for (Ssiz_t i = 0; i < len; ++i) - if (!isdigit(cp[i])) - return kFALSE; + for (Ssiz_t i = 0; i < len; ++i){ + if (cp[i]!=' ' && !isdigit(cp[i])) return kFALSE; + } return kTRUE; } +//______________________________________________________________________________ +Bool_t TString::IsFloat() const +{ + // Returns kTRUE if string contains a floating point or integer number. + // Examples of valid formats are: + // 64320 + // 64 320 + // 6 4 3 2 0 + // 6.4320 6,4320 + // 6.43e20 6.43E20 6,43e20 + // 6.43e-20 6.43E-20 6,43e-20 + + //we first check if we have an integer, in this case, IsDigit() will be true straight away + if (IsDigit()) return kTRUE; + + TString tmp = *this; + //now we look for occurrences of '.', ',', e', 'E', '+', '-' and replace each + //with '0'. if it is a floating point, IsDigit() will then return kTRUE + Int_t i_dot, i_e, i_plus, i_minus, i_comma; + i_dot = i_e = i_plus = i_minus = i_comma = -1; + + i_dot = tmp.First('.'); + if (i_dot > -1) tmp.Replace(i_dot, 1, "0", 1); + i_comma = tmp.First(','); + if (i_comma > -1) tmp.Replace(i_comma, 1, "0", 1); + i_e = tmp.First('e'); + if (i_e > -1) + tmp.Replace(i_e, 1, "0", 1); + else { + //try for a capital "E" + i_e = tmp.First('E'); + if (i_e > -1) tmp.Replace(i_e, 1, "0", 1); + } + i_plus = tmp.First('+'); + if (i_plus > -1) tmp.Replace(i_plus, 1, "0", 1); + i_minus = tmp.First('-'); + if (i_minus > -1) tmp.Replace(i_minus, 1, "0", 1); + + //test if it is now uniquely composed of numbers + return tmp.IsDigit(); +} + //______________________________________________________________________________ Bool_t TString::IsHex() const { @@ -1517,6 +1561,68 @@ Bool_t TString::IsHex() const return kTRUE; } +//______________________________________________________________________________ +Int_t TString::Atoi() const +{ + // Return integer value of string. + // Valid strings include only digits and whitespace (see IsDigit()), + // i.e. "123456", "123 456" and "1 2 3 4 56" are all valid + // integer strings whose Atoi() value is 123456. + + //any whitespace ? + Int_t end = Index(" "); + //if no whitespaces in string, just use atoi() + if (end == -1) return atoi(Data()); + //make temporary string, removing whitespace + Int_t start = 0; + TString tmp; + //loop over all whitespace + while (end > -1) { + tmp += (*this)(start, end-start); + start = end+1; end = Index(" ", start); + } + //finally add part from last whitespace to end of string + end = Length(); + tmp += (*this)(start, end-start); + return atoi(tmp.Data()); +} + +//______________________________________________________________________________ +Double_t TString::Atof() const +{ + // Return floating-point value contained in string. + // Examples of valid strings are: + // 64320 + // 64 320 + // 6 4 3 2 0 + // 6.4320 6,4320 + // 6.43e20 6.43E20 6,43e20 + // 6.43e-20 6.43E-20 6,43e-20 + + //look for a comma and some whitespace + Int_t comma = Index(","); + Int_t end = Index(" "); + //if no commas & no whitespace in string, just use atof() + if (comma == -1 && end == -1) return atof(Data()); + TString tmp = *this; + if (comma > -1) { + //replace comma with decimal point + tmp.Replace(comma, 1, "."); + } + //no whitespace ? + if (end == -1) return atof(tmp.Data()); + //remove whitespace + Int_t start = 0; + TString tmp2; + while (end > -1) { + tmp2 += tmp(start, end-start); + start = end+1; end = tmp.Index(" ", start); + } + end = tmp.Length(); + tmp2 += tmp(start, end-start); + return atof(tmp2.Data()); +} + //______________________________________________________________________________ Bool_t TString::EndsWith(const char *s, ECaseCompare cmp) const { diff --git a/config/Makefile.in b/config/Makefile.in index 5e6b91a4e89090c40ae1264f285f6cb18ad01861..ca7a5b51ecdbc9436015140729f412e40c5356f0 100644 --- a/config/Makefile.in +++ b/config/Makefile.in @@ -46,6 +46,8 @@ OSTHREADLIB := @threadlib@ BUILTINFREETYPE:= @builtinfreetype@ +BUILTINPCRE := @builtinpcre@ + BUILDGL := @buildgl@ OPENGLLIBDIR := @opengllibdir@ OPENGLULIB := @openglulib@ @@ -211,6 +213,8 @@ CLARENSLIBS := @clarenslibs@ BUILDPEAC := @buildpeac@ +GCCXML := @gccxml@ + INSTALL := cp -dpR INSTALLDATA := cp -dpR INSTALLDIR := mkdir -p diff --git a/configure b/configure index 9d310651ddbe9a858c1e1d88f56c132148f21415..467c3236509a51578f75347d29692d816e63cfba 100755 --- a/configure +++ b/configure @@ -27,6 +27,7 @@ options=" \ enable_asimage \ enable_builtin_afterimage \ enable_builtin_freetype \ + enable_builtin_pcre \ enable_cern \ enable_chirp \ enable_cintex \ @@ -719,6 +720,7 @@ enable/disable options, prefix with either --enable- or --disable- asimage Image processing support, requires libAfterImage builtin-afterimage Built included libAfterImage, or use system libAfterImage builtin-freetype Built included libfreetype, or use system libfreetype + builtin-pcre Built included libpcre, or use system libpcre cern CERNLIB usage, build h2root and g2root chirp Chirp support (Condor remote I/O), requires libchirp_client cintex Build the libCintex Reflex interface library @@ -769,6 +771,7 @@ with options, prefix with --with-, enables corresponding support dcap-incdir dCache support, location of dcap.h dcap-libdir dCache support, location of libdcap globus Globus support, path to what should be GLOBUS_LOCATION + gccxml Gccxml support, directory of the gccxml installation krb5 Kerberos5 support, location of Kerberos distribution krb5-incdir Kerberos5 support, location of krb5.h krb5-libdir Kerberos5 support, location of libkrb5 @@ -920,6 +923,7 @@ if test $# -gt 0 ; then --with-dcap-incdir=*) dcapincdir=$optarg ; enable_dcache="yes" ;; --with-dcap-libdir=*) dcaplibdir=$optarg ; enable_dcache="yes" ;; --with-globus=*) globusdir=$optarg ; enable_globus="yes" ;; + --with-gccxml=*) gccxml=$optarg ;; --with-krb5=*) krb5dir=$optarg ; enable_krb5="yes" ;; --with-krb5-incdir=*) krb5incdir=$optarg ; enable_krb5="yes" ;; --with-krb5-libdir=*) krb5libdir=$optarg ; enable_krb5="yes" ;; @@ -1171,9 +1175,9 @@ fi ###################################################################### # -### echo %%% libfreetype (builtin or system) - Mandatory lib on Unix +### echo %%% libfreetype (builtin or system) - Mandatory lib # -# Mandatory test, must succeed +# Mandatory test, must succeed (see http://www.freetype.org/) # if test "x$enable_builtin_freetype" = "x" || \ test "x$enable_builtin_freetype" = "xno" ; then @@ -1203,6 +1207,39 @@ fi message "Checking whether to build included libfreetype6" echo "$enable_builtin_freetype" +###################################################################### +# +### echo %%% libpcre (builtin or system) - Mandatory lib +# +# Mandatory test, must succeed (see http://www.pcre.org/) +# +if test "x$enable_builtin_pcre" = "x" || \ + test "x$enable_builtin_pcre" = "xno" ; then + + checking_msg "pcre-config" + if `which pcre-config > /dev/null 2>&1` ; then + which pcre-config + + message "Checking for libpcre version >= 3.9" + pcre_version=`pcre-config --version | \ + tr '.' ' ' | \ + awk 'BEGIN { FS = " "; } \ + { printf "%d", ($''1 * 1000 + $''2) * 1000 + $''3;}'` + # First good version is 3.9 + if test $pcre_version -lt 3009000 ; then + echo "no (`pcre-config --version`)" + enable_builtin_pcre="yes" + else + echo "ok" + enable_builtin_pcre="no" + fi + else + enable_builtin_pcre="no" + echo "not found" + fi +fi +message "Checking whether to build included libpcre" +echo "$enable_builtin_pcre" ###################################################################### # @@ -3258,6 +3295,7 @@ sed -e "s|@aclocaldir@|$aclocaldir|" \ -e "s|@buildasimage@|$enable_asimage|" \ -e "s|@builtinafterimage@|$enable_builtin_afterimage|" \ -e "s|@builtinfreetype@|$enable_builtin_freetype|" \ + -e "s|@builtinpcre@|$enable_builtin_pcre|" \ -e "s|@buildpeac@|$buildpeac|" \ -e "s|@buildxrd@|$buildxrd|" \ -e "s|@cernlibdir@|$cernlibdir|" \ @@ -3294,6 +3332,7 @@ sed -e "s|@aclocaldir@|$aclocaldir|" \ -e "s|@globuslibdir@|$globuslibdir|" \ -e "s|@glbextracflags@|$glbextracflags|" \ -e "s|@glbpatchcflags@|$glbpatchcflags|" \ + -e "s|@gccxml@|$gccxml|" \ -e "s|@iconpath@|$iconpath|" \ -e "s|@incdir@|$incdir|" \ -e "s|@krb5incdir@|$krb5incdir|" \ @@ -3470,6 +3509,7 @@ sed -e "s|@architecture@|$arch|" \ -e "s|@libdir@|$libdir2|" \ -e "s|@incdir@|$incdir2|" \ -e "s|@features@|$features|" \ + -e "s|@configargs@|$configargs|" \ < root-config.tmp > $RCONFOUT rm -f root-config.tmp chmod 755 $RCONFOUT diff --git a/test/tstring.cxx b/test/tstring.cxx index e8b5d1a05113f216bad9c756b116a81007245740..dce92c27dcc0a6e733d1390bb8f8de3d048b4ba1 100644 --- a/test/tstring.cxx +++ b/test/tstring.cxx @@ -1,4 +1,4 @@ -// @(#)root/test:$Name: $:$Id: tstring.cxx,v 1.3 2002/01/23 17:52:51 rdm Exp $ +// @(#)root/test:$Name: $:$Id: tstring.cxx,v 1.4 2002/01/24 11:39:31 rdm Exp $ // Author: Fons Rademakers 19/08/96 #include <stdlib.h> @@ -6,6 +6,7 @@ #include "Riostream.h" #include "TString.h" #include "TRegexp.h" +#include "TPRegexp.h" void Ok(int i, int b) @@ -129,6 +130,21 @@ int main() Ok(22, !s10.IsAscii()); Ok(23, s.IsAscii()); + // some excercises with the Perl Compatible Regular Expressions + TString s11("Food is on the foo table."); + TPRegexp("\\b(foo)\\s+(\\w+)").Substitute(s11, "round $2"); + Ok(24, s11=="Food is on the round table."); + + TString s12("pepernotenkoek"); + TPRegexp("peper(.*)koek").Substitute(s12, "wal$1boom"); + Ok(25, s12=="walnotenboom"); + + TString s13("hihi haha"); + TPRegexp("^([^ ]*) *([^ ]*)").Substitute(s13, "$2 $1"); + Ok(26, s13=="haha hihi"); + + Ok(27, TPRegexp("^(\\w+) *(\\w+)").Match(s13) == 3); + // test Resize and Strip s9.Prepend(" "); cout << s9 << endl;