X-Git-Url: https://scm.cri.ensmp.fr/git/Faustine.git/blobdiff_plain/1059e1cc0c2ecfa237406949aa26155b6a5b9154..66f23d4fabf89ad09adbd4dfc15ac6b5b2b7da83:/interpreter/preprocessor/faust-0.9.47mr3/architecture/osclib/faust/src/lib/deelx.h diff --git a/interpreter/preprocessor/faust-0.9.47mr3/architecture/osclib/faust/src/lib/deelx.h b/interpreter/preprocessor/faust-0.9.47mr3/architecture/osclib/faust/src/lib/deelx.h new file mode 100755 index 0000000..c50ed88 --- /dev/null +++ b/interpreter/preprocessor/faust-0.9.47mr3/architecture/osclib/faust/src/lib/deelx.h @@ -0,0 +1,4178 @@ +// deelx.h +// +// DEELX Regular Expression Engine (v1.2) +// +// Copyright 2006 (c) RegExLab.com +// All Rights Reserved. +// +// http://www.regexlab.com/deelx/ +// +// Author: Ê·ÊÙΰ (sswater shi) +// sswater@gmail.com +// +// $Revision: 1.1.2.26 $ +// + +#ifndef __DEELX_REGEXP__H__ +#define __DEELX_REGEXP__H__ + +#include +#include +#include +#include +#include + +// +// Data Reference +// +template class CBufferRefT +{ +public: + CBufferRefT(const ELT * pcsz, int length); + CBufferRefT(const ELT * pcsz); + +public: + int nCompare (const ELT * pcsz) const; + int nCompareNoCase(const ELT * pcsz) const; + int Compare (const ELT * pcsz) const; + int CompareNoCase(const ELT * pcsz) const; + int Compare (const CBufferRefT &) const; + int CompareNoCase(const CBufferRefT &) const; + + ELT At (int nIndex, ELT def = 0) const; + ELT operator [] (int nIndex) const; + + const ELT * GetBuffer() const; + int GetSize() const; + +public: + virtual ~CBufferRefT(); + +// Content +protected: + const ELT * m_pRef; + int m_nSize; +}; + +// +// Implemenation +// +template CBufferRefT :: CBufferRefT(const ELT * pcsz, int length) +{ + m_pRef = pcsz; + m_nSize = length; +} + +template CBufferRefT :: CBufferRefT(const ELT * pcsz) +{ + m_pRef = pcsz; + m_nSize = 0; + + if(pcsz != 0) while(m_pRef[m_nSize] != 0) m_nSize ++; +} + +template int CBufferRefT :: nCompare(const ELT * pcsz) const +{ + for(int i=0; i int CBufferRefT :: nCompareNoCase(const ELT * pcsz) const +{ + for(int i=0; i inline int CBufferRefT :: Compare(const ELT * pcsz) const +{ + return nCompare(pcsz) ? 1 : (int)pcsz[m_nSize]; +} + +template inline int CBufferRefT :: CompareNoCase(const ELT * pcsz) const +{ + return nCompareNoCase(pcsz) ? 1 : (int)pcsz[m_nSize]; +} + +template inline int CBufferRefT :: Compare(const CBufferRefT & cref) const +{ + return m_nSize == cref.m_nSize ? nCompare(cref.GetBuffer()) : 1; +} + +template inline int CBufferRefT :: CompareNoCase(const CBufferRefT & cref) const +{ + return m_nSize == cref.m_nSize ? nCompareNoCase(cref.GetBuffer()) : 1; +} + +template inline ELT CBufferRefT :: At(int nIndex, ELT def) const +{ + return nIndex >= m_nSize ? def : m_pRef[nIndex]; +} + +template inline ELT CBufferRefT :: operator [] (int nIndex) const +{ + return nIndex >= m_nSize ? 0 : m_pRef[nIndex]; +} + +template const ELT * CBufferRefT :: GetBuffer() const +{ + static const ELT _def[] = {0}; return m_pRef ? m_pRef : _def; +} + +template inline int CBufferRefT :: GetSize() const +{ + return m_nSize; +} + +template CBufferRefT :: ~CBufferRefT() +{ +} + +// +// Data Buffer +// +template class CBufferT : public CBufferRefT +{ +public: + CBufferT(const ELT * pcsz, int length); + CBufferT(const ELT * pcsz); + CBufferT(); + +public: + ELT & operator [] (int nIndex); + const ELT & operator [] (int nIndex) const; + void Append(const ELT * pcsz, int length, int eol = 0); + void Append(ELT el, int eol = 0); + +public: + void Push(ELT el); + int Pop (ELT & el); + int Peek(ELT & el) const; + +public: + const ELT * GetBuffer() const; + ELT * GetBuffer(); + ELT * Detach(); + void Release(); + void Prepare(int index, int fill = 0); + void Restore(int size); + +public: + virtual ~CBufferT(); + +// Content +protected: + ELT * m_pBuffer; + int m_nMaxLength; +}; + +// +// Implemenation +// +template CBufferT :: CBufferT(const ELT * pcsz, int length) : CBufferRefT (0, length) +{ + m_nMaxLength = CBufferRefT :: m_nSize + 1; + + CBufferRefT :: m_pRef = m_pBuffer = new ELT[m_nMaxLength]; + memcpy(m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT :: m_nSize); + m_pBuffer[CBufferRefT :: m_nSize] = 0; +} + +template CBufferT :: CBufferT(const ELT * pcsz) : CBufferRefT (pcsz) +{ + m_nMaxLength = CBufferRefT :: m_nSize + 1; + + CBufferRefT :: m_pRef = m_pBuffer = new ELT[m_nMaxLength]; + memcpy(m_pBuffer, pcsz, sizeof(ELT) * CBufferRefT :: m_nSize); + m_pBuffer[CBufferRefT :: m_nSize] = 0; +} + +template CBufferT :: CBufferT() : CBufferRefT (0, 0) +{ + m_nMaxLength = 0; + m_pBuffer = 0; +} + +template inline ELT & CBufferT :: operator [] (int nIndex) +{ + return m_pBuffer[nIndex]; +} + +template inline const ELT & CBufferT :: operator [] (int nIndex) const +{ + return m_pBuffer[nIndex]; +} + +template void CBufferT :: Append(const ELT * pcsz, int length, int eol) +{ + int nNewLength = m_nMaxLength; + + // Check length + if(nNewLength < 8) + nNewLength = 8; + + if(CBufferRefT :: m_nSize + length + eol > nNewLength) + nNewLength *= 2; + + if(CBufferRefT :: m_nSize + length + eol > nNewLength) + { + nNewLength = CBufferRefT :: m_nSize + length + eol + 11; + nNewLength -= nNewLength % 8; + } + + // Realloc + if(nNewLength > m_nMaxLength) + { + ELT * pNewBuffer = new ELT[nNewLength]; + + if(m_pBuffer != 0) + { + memcpy(pNewBuffer, m_pBuffer, sizeof(ELT) * CBufferRefT :: m_nSize); + delete [] m_pBuffer; + } + + CBufferRefT :: m_pRef = m_pBuffer = pNewBuffer; + m_nMaxLength = nNewLength; + } + + // Append + memcpy(m_pBuffer + CBufferRefT :: m_nSize, pcsz, sizeof(ELT) * length); + CBufferRefT :: m_nSize += length; + + if(eol > 0) m_pBuffer[CBufferRefT :: m_nSize] = 0; +} + +template inline void CBufferT :: Append(ELT el, int eol) +{ + Append(&el, 1, eol); +} + +template void CBufferT :: Push(ELT el) +{ + // Realloc + if(CBufferRefT :: m_nSize >= m_nMaxLength) + { + int nNewLength = m_nMaxLength * 2; + if( nNewLength < 8 ) nNewLength = 8; + + ELT * pNewBuffer = new ELT[nNewLength]; + + if(m_pBuffer != 0) + { + memcpy(pNewBuffer, m_pBuffer, sizeof(ELT) * CBufferRefT :: m_nSize); + delete [] m_pBuffer; + } + + CBufferRefT :: m_pRef = m_pBuffer = pNewBuffer; + m_nMaxLength = nNewLength; + } + + // Append + m_pBuffer[CBufferRefT :: m_nSize++] = el; +} + +template inline int CBufferT :: Pop(ELT & el) +{ + if(CBufferRefT :: m_nSize > 0) + { + el = m_pBuffer[--CBufferRefT :: m_nSize]; + return 1; + } + else + { + return 0; + } +} + +template inline int CBufferT :: Peek(ELT & el) const +{ + if(CBufferRefT :: m_nSize > 0) + { + el = m_pBuffer[CBufferRefT :: m_nSize - 1]; + return 1; + } + else + { + return 0; + } +} + +template const ELT * CBufferT :: GetBuffer() const +{ + static const ELT _def[] = {0}; return m_pBuffer ? m_pBuffer : _def; +} + +template ELT * CBufferT :: GetBuffer() +{ + static const ELT _def[] = {0}; return m_pBuffer ? m_pBuffer : (ELT *)_def; +} + +template ELT * CBufferT :: Detach() +{ + ELT * pBuffer = m_pBuffer; + + CBufferRefT :: m_pRef = m_pBuffer = 0; + CBufferRefT :: m_nSize = m_nMaxLength = 0; + + return pBuffer; +} + +template void CBufferT :: Release() +{ + ELT * pBuffer = Detach(); + + if(pBuffer != 0) delete [] pBuffer; +} + +template void CBufferT :: Prepare(int index, int fill) +{ + int nNewSize = index + 1; + + // Realloc + if(nNewSize > m_nMaxLength) + { + int nNewLength = m_nMaxLength; + + if( nNewLength < 8 ) + nNewLength = 8; + + if( nNewSize > nNewLength ) + nNewLength *= 2; + + if( nNewSize > nNewLength ) + { + nNewLength = nNewSize + 11; + nNewLength -= nNewLength % 8; + } + + ELT * pNewBuffer = new ELT[nNewLength]; + + if(m_pBuffer != 0) + { + memcpy(pNewBuffer, m_pBuffer, sizeof(ELT) * CBufferRefT :: m_nSize); + delete [] m_pBuffer; + } + + CBufferRefT :: m_pRef = m_pBuffer = pNewBuffer; + m_nMaxLength = nNewLength; + } + + // size + if( CBufferRefT :: m_nSize < nNewSize ) + { + memset(m_pBuffer + CBufferRefT :: m_nSize, fill, sizeof(ELT) * (nNewSize - CBufferRefT :: m_nSize)); + CBufferRefT :: m_nSize = nNewSize; + } +} + +template inline void CBufferT :: Restore(int size) +{ + CBufferRefT :: m_nSize = size; +} + +template CBufferT :: ~CBufferT() +{ + if(m_pBuffer != 0) delete [] m_pBuffer; +} + +// +// Context +// +class CContext +{ +public: + CBufferT m_stack; + CBufferT m_capturestack, m_captureindex; + +public: + int m_nCurrentPos; + int m_nBeginPos; + int m_nLastBeginPos; + int m_nParenZindex; + + void * m_pMatchString; + int m_pMatchStringLength; +}; + +// +// Interface +// +class ElxInterface +{ +public: + virtual int Match (CContext * pContext) const = 0; + virtual int MatchNext(CContext * pContext) const = 0; + +public: + virtual ~ElxInterface() {}; +}; + +// +// Alternative +// +template class CAlternativeElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CAlternativeElxT(); + +public: + CBufferT m_elxlist; +}; + +typedef CAlternativeElxT <0> CAlternativeElx; + +// +// Assert +// +template class CAssertElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CAssertElxT(ElxInterface * pelx, int byes = 1); + +public: + ElxInterface * m_pelx; + int m_byes; +}; + +typedef CAssertElxT <0> CAssertElx; + +// +// Back reference elx +// +template class CBackrefElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CBackrefElxT(int nnumber, int brightleft, int bignorecase); + +public: + int m_nnumber; + int m_brightleft; + int m_bignorecase; + + CBufferT m_szNamed; +}; + +// +// Implementation +// +template CBackrefElxT :: CBackrefElxT(int nnumber, int brightleft, int bignorecase) +{ + m_nnumber = nnumber; + m_brightleft = brightleft; + m_bignorecase = bignorecase; +} + +template int CBackrefElxT :: Match(CContext * pContext) const +{ + // check number, for named + if( m_nnumber < 0 || m_nnumber >= pContext->m_captureindex.GetSize() ) return 0; + + int index = pContext->m_captureindex[m_nnumber]; + if( index < 0 ) return 0; + + // check enclosed + int pos1 = pContext->m_capturestack[index + 1]; + int pos2 = pContext->m_capturestack[index + 2]; + + if( pos2 < 0 ) pos2 = pContext->m_nCurrentPos; + + // info + int lpos = pos1 < pos2 ? pos1 : pos2; + int rpos = pos1 < pos2 ? pos2 : pos1; + int slen = rpos - lpos; + + const CHART * pcsz = (const CHART *)pContext->m_pMatchString; + int npos = pContext->m_nCurrentPos; + int tlen = pContext->m_pMatchStringLength; + + // compare + int bsucc; + CBufferRefT refstr(pcsz + lpos, slen); + + if( m_brightleft ) + { + if(npos < slen) + return 0; + + if(m_bignorecase) + bsucc = ! refstr.nCompareNoCase(pcsz + (npos - slen)); + else + bsucc = ! refstr.nCompare (pcsz + (npos - slen)); + + if( bsucc ) + { + pContext->m_stack.Push(npos); + pContext->m_nCurrentPos -= slen; + } + } + else + { + if(npos + slen > tlen) + return 0; + + if(m_bignorecase) + bsucc = ! refstr.nCompareNoCase(pcsz + npos); + else + bsucc = ! refstr.nCompare (pcsz + npos); + + if( bsucc ) + { + pContext->m_stack.Push(npos); + pContext->m_nCurrentPos += slen; + } + } + + return bsucc; +} + +template int CBackrefElxT :: MatchNext(CContext * pContext) const +{ + int npos = 0; + + pContext->m_stack.Pop(npos); + pContext->m_nCurrentPos = npos; + + return 0; +} + +// RCHART +#ifndef RCHART + #define RCHART(ch) ((CHART)ch) +#endif + +// BOUNDARY_TYPE +enum BOUNDARY_TYPE +{ + BOUNDARY_FILE_BEGIN, // begin of whole text + BOUNDARY_FILE_END , // end of whole text + BOUNDARY_LINE_BEGIN, // begin of line + BOUNDARY_LINE_END , // end of line + BOUNDARY_WORD_BEGIN, // begin of word + BOUNDARY_WORD_END , // end of word + BOUNDARY_WORD_EDGE , +}; + +// +// Boundary Elx +// +template class CBoundaryElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CBoundaryElxT(int ntype, int byes = 1); + +protected: + static int IsWordChar(CHART ch); + +public: + int m_ntype; + int m_byes; +}; + +// +// Implementation +// +template CBoundaryElxT :: CBoundaryElxT(int ntype, int byes) +{ + m_ntype = ntype; + m_byes = byes; +} + +template int CBoundaryElxT :: Match(CContext * pContext) const +{ + const CHART * pcsz = (const CHART *)pContext->m_pMatchString; + int npos = pContext->m_nCurrentPos; + int tlen = pContext->m_pMatchStringLength; + + CHART chL = npos > 0 ? pcsz[npos - 1] : 0; + CHART chR = npos < tlen ? pcsz[npos ] : 0; + + int bsucc = 0; + + switch(m_ntype) + { + case BOUNDARY_FILE_BEGIN: + bsucc = (npos <= 0); + break; + + case BOUNDARY_FILE_END: + bsucc = (npos >= tlen); + break; + + case BOUNDARY_LINE_BEGIN: + bsucc = (npos <= 0 ) || (chL == RCHART('\n')) || ((chL == RCHART('\r')) && (chR != RCHART('\n'))); + break; + + case BOUNDARY_LINE_END: + bsucc = (npos >= tlen) || (chR == RCHART('\r')) || ((chR == RCHART('\n')) && (chL != RCHART('\r'))); + break; + + case BOUNDARY_WORD_BEGIN: + bsucc = ! IsWordChar(chL) && IsWordChar(chR); + break; + + case BOUNDARY_WORD_END: + bsucc = IsWordChar(chL) && ! IsWordChar(chR); + break; + + case BOUNDARY_WORD_EDGE: + bsucc = IsWordChar(chL) ? ! IsWordChar(chR) : IsWordChar(chR); + break; + } + + return bsucc; +} + +template int CBoundaryElxT :: MatchNext(CContext *) const +{ + return 0; +} + +template inline int CBoundaryElxT :: IsWordChar(CHART ch) +{ + return (ch >= RCHART('A') && ch <= RCHART('Z')) || (ch >= RCHART('a') && ch <= RCHART('z')) || (ch >= RCHART('0') && ch <= RCHART('9')) || (ch == RCHART('_')); +} + +// +// Bracket +// +template class CBracketElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CBracketElxT(int nnumber, int bright); + +public: + int m_nnumber; + int m_bright; + + CBufferT m_szNamed; +}; + +template CBracketElxT :: CBracketElxT(int nnumber, int bright) +{ + m_nnumber = nnumber; + m_bright = bright; +} + +template int CBracketElxT :: Match(CContext * pContext) const +{ + // check, for named + if(m_nnumber < 0) return 0; + + if( ! m_bright ) + { + pContext->m_captureindex.Prepare(m_nnumber, -1); + int index = pContext->m_captureindex[m_nnumber]; + + // check + if(index > 0 && index < pContext->m_capturestack.GetSize() && pContext->m_capturestack[index+2] < 0) + { + pContext->m_capturestack[index+3] --; + return 1; + } + + // save + pContext->m_captureindex[m_nnumber] = pContext->m_capturestack.GetSize(); + + pContext->m_capturestack.Push(m_nnumber); + pContext->m_capturestack.Push(pContext->m_nCurrentPos); + pContext->m_capturestack.Push(-1); + pContext->m_capturestack.Push( 0); // z-index + } + else + { + // check + int index = pContext->m_captureindex[m_nnumber]; + + if(pContext->m_capturestack[index + 3] < 0) + { + pContext->m_capturestack[index + 3] ++; + return 1; + } + + // save + pContext->m_capturestack[index + 2] = pContext->m_nCurrentPos; + pContext->m_capturestack[index + 3] = pContext->m_nParenZindex ++; + } + + return 1; +} + +template int CBracketElxT :: MatchNext(CContext * pContext) const +{ + int index = pContext->m_captureindex[m_nnumber]; + + if( ! m_bright ) + { + if(pContext->m_capturestack[index + 3] < 0) + { + pContext->m_capturestack[index + 3] ++; + return 0; + } + + pContext->m_capturestack.Restore(pContext->m_capturestack.GetSize() - 4); + + // to find + index = pContext->m_capturestack.GetSize() - 4; + while(index >= 0 && pContext->m_capturestack[index] != m_nnumber) index -= 4; + + // new index + pContext->m_captureindex[m_nnumber] = index; + } + else + { + if(pContext->m_capturestack[index + 3] < 0) + { + pContext->m_capturestack[index + 3] --; + return 0; + } + + pContext->m_capturestack[index + 2] = -1; + pContext->m_capturestack[index + 3] = 0; + } + + return 0; +} + +// +// Deletage +// +template class CDelegateElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CDelegateElxT(int ndata = 0); + +public: + ElxInterface * m_pelx; + int m_ndata; // +0 : recursive to + // -3 : named recursive + + CBufferT m_szNamed; +}; + +template CDelegateElxT :: CDelegateElxT(int ndata) +{ + m_pelx = 0; + m_ndata = ndata; +} + +template int CDelegateElxT :: Match(CContext * pContext) const +{ + if(m_pelx != 0) + return m_pelx->Match(pContext); + else + return 1; +} + +template int CDelegateElxT :: MatchNext(CContext * pContext) const +{ + if(m_pelx != 0) + return m_pelx->MatchNext(pContext); + else + return 0; +} + +// +// Empty +// +template class CEmptyElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CEmptyElxT(); +}; + +typedef CEmptyElxT <0> CEmptyElx; + +// +// Global +// +template class CGlobalElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CGlobalElxT(); +}; + +typedef CGlobalElxT <0> CGlobalElx; + +// +// Repeat +// +template class CRepeatElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CRepeatElxT(ElxInterface * pelx, int ntimes); + +protected: + int MatchFixed (CContext * pContext) const; + int MatchNextFixed(CContext * pContext) const; + +public: + ElxInterface * m_pelx; + int m_nfixed; +}; + +typedef CRepeatElxT <0> CRepeatElx; + +// +// Greedy +// +template class CGreedyElxT : public CRepeatElxT +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CGreedyElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX); + +protected: + int MatchVart (CContext * pContext) const; + int MatchNextVart(CContext * pContext) const; + +public: + int m_nvart; +}; + +typedef CGreedyElxT <0> CGreedyElx; + +// +// Independent +// +template class CIndependentElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CIndependentElxT(ElxInterface * pelx); + +public: + ElxInterface * m_pelx; +}; + +typedef CIndependentElxT <0> CIndependentElx; + +// +// List +// +template class CListElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CListElxT(int brightleft); + +public: + CBufferT m_elxlist; + int m_brightleft; +}; + +typedef CListElxT <0> CListElx; + +// +// Posix Elx +// +template class CPosixElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CPosixElxT(const char * posix, int brightleft); + +protected: + static int misblank(int c); + +public: + int (*m_posixfun)(int); + int m_brightleft; + int m_byes; +}; + +// +// Implementation +// +template CPosixElxT :: CPosixElxT(const char * posix, int brightleft) +{ + m_brightleft = brightleft; + + if(posix[1] == '^') + { + m_byes = 0; + posix += 2; + } + else + { + m_byes = 1; + posix += 1; + } + + if (!strncmp(posix, "alnum:", 6)) m_posixfun = isalnum ; + else if(!strncmp(posix, "alpha:", 6)) m_posixfun = isalpha ; + else if(!strncmp(posix, "ascii:", 6)) m_posixfun = isascii ; + else if(!strncmp(posix, "cntrl:", 6)) m_posixfun = iscntrl ; + else if(!strncmp(posix, "digit:", 6)) m_posixfun = isdigit ; + else if(!strncmp(posix, "graph:", 6)) m_posixfun = isgraph ; + else if(!strncmp(posix, "lower:", 6)) m_posixfun = islower ; + else if(!strncmp(posix, "print:", 6)) m_posixfun = isprint ; + else if(!strncmp(posix, "punct:", 6)) m_posixfun = ispunct ; + else if(!strncmp(posix, "space:", 6)) m_posixfun = isspace ; + else if(!strncmp(posix, "upper:", 6)) m_posixfun = isupper ; + else if(!strncmp(posix, "xdigit:",7)) m_posixfun = isxdigit; + else if(!strncmp(posix, "blank:", 6)) m_posixfun = misblank; + else m_posixfun = 0 ; +} + +template int CPosixElxT :: misblank(int c) +{ + return c == 0x20 || c == '\t'; +} + +template int CPosixElxT :: Match(CContext * pContext) const +{ + if(m_posixfun == 0) return 0; + + int tlen = pContext->m_pMatchStringLength; + int npos = pContext->m_nCurrentPos; + + // check + int at = m_brightleft ? npos - 1 : npos; + if( at < 0 || at >= tlen ) + return 0; + + CHART ch = ((const CHART *)pContext->m_pMatchString)[at]; + + int bsucc = (*m_posixfun)(ch); + + if( ! m_byes ) + bsucc = ! bsucc; + + if( bsucc ) + pContext->m_nCurrentPos += m_brightleft ? -1 : 1; + + return bsucc; +} + +template int CPosixElxT :: MatchNext(CContext * pContext) const +{ + pContext->m_nCurrentPos -= m_brightleft ? -1 : 1; + return 0; +} + +// +// Possessive +// +template class CPossessiveElxT : public CGreedyElxT +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CPossessiveElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX); +}; + +typedef CPossessiveElxT <0> CPossessiveElx; + +// +// Range Elx +// +template class CRangeElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CRangeElxT(int brightleft, int byes); + +public: + CBufferT m_ranges; + CBufferT m_chars; + CBufferT m_embeds; + +public: + int m_brightleft; + int m_byes; +}; + +// +// Implementation +// +template CRangeElxT :: CRangeElxT(int brightleft, int byes) +{ + m_brightleft = brightleft; + m_byes = byes; +} + +template int CRangeElxT :: Match(CContext * pContext) const +{ + int tlen = pContext->m_pMatchStringLength; + int npos = pContext->m_nCurrentPos; + + // check + int at = m_brightleft ? npos - 1 : npos; + if( at < 0 || at >= tlen ) + return 0; + + CHART ch = ((const CHART *)pContext->m_pMatchString)[at]; + int bsucc = 0, i; + + // compare + for(i=0; !bsucc && iMatch(pContext)) + { + pContext->m_nCurrentPos = npos; + bsucc = 1; + } + } + + if( ! m_byes ) + bsucc = ! bsucc; + + if( bsucc ) + pContext->m_nCurrentPos += m_brightleft ? -1 : 1; + + return bsucc; +} + +template int CRangeElxT :: MatchNext(CContext * pContext) const +{ + pContext->m_nCurrentPos -= m_brightleft ? -1 : 1; + return 0; +} + +// +// Reluctant +// +template class CReluctantElxT : public CRepeatElxT +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CReluctantElxT(ElxInterface * pelx, int nmin = 0, int nmax = INT_MAX); + +protected: + int MatchVart (CContext * pContext) const; + int MatchNextVart(CContext * pContext) const; + +public: + int m_nvart; +}; + +typedef CReluctantElxT <0> CReluctantElx; + +// +// String Elx +// +template class CStringElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase); + +public: + CBufferT m_szPattern; + int m_brightleft; + int m_bignorecase; +}; + +// +// Implementation +// +template CStringElxT :: CStringElxT(const CHART * fixed, int nlength, int brightleft, int bignorecase) : m_szPattern(fixed, nlength) +{ + m_brightleft = brightleft; + m_bignorecase = bignorecase; +} + +template int CStringElxT :: Match(CContext * pContext) const +{ + const CHART * pcsz = (const CHART *)pContext->m_pMatchString; + int npos = pContext->m_nCurrentPos; + int tlen = pContext->m_pMatchStringLength; + int slen = m_szPattern.GetSize(); + + int bsucc; + + if(m_brightleft) + { + if(npos < slen) + return 0; + + if(m_bignorecase) + bsucc = ! m_szPattern.nCompareNoCase(pcsz + (npos - slen)); + else + bsucc = ! m_szPattern.nCompare (pcsz + (npos - slen)); + + if( bsucc ) + pContext->m_nCurrentPos -= slen; + } + else + { + if(npos + slen > tlen) + return 0; + + if(m_bignorecase) + bsucc = ! m_szPattern.nCompareNoCase(pcsz + npos); + else + bsucc = ! m_szPattern.nCompare (pcsz + npos); + + if( bsucc ) + pContext->m_nCurrentPos += slen; + } + + return bsucc; +} + +template int CStringElxT :: MatchNext(CContext * pContext) const +{ + int slen = m_szPattern.GetSize(); + + if(m_brightleft) + pContext->m_nCurrentPos += slen; + else + pContext->m_nCurrentPos -= slen; + + return 0; +} + +// +// CConditionElx +// +template class CConditionElxT : public ElxInterface +{ +public: + int Match (CContext * pContext) const; + int MatchNext(CContext * pContext) const; + +public: + CConditionElxT(); + +public: + // backref condition + int m_nnumber; + CBufferT m_szNamed; + + // elx condition + ElxInterface * m_pelxask; + + // selection + ElxInterface * m_pelxyes, * m_pelxno; +}; + +template CConditionElxT :: CConditionElxT() +{ + m_nnumber = -1; +} + +template int CConditionElxT :: Match(CContext * pContext) const +{ + // status + int nbegin = pContext->m_nCurrentPos; + int nsize = pContext->m_stack.GetSize(); + int ncsize = pContext->m_capturestack.GetSize(); + + // condition result + int condition_yes = 0; + + // backref type + if( m_nnumber >= 0 ) + { + do + { + if(m_nnumber >= pContext->m_captureindex.GetSize()) break; + + int index = pContext->m_captureindex[m_nnumber]; + if( index < 0) break; + + // else valid + condition_yes = 1; + } + while(0); + } + else + { + if( m_pelxask == 0 ) + condition_yes = 1; + else + condition_yes = m_pelxask->Match(pContext); + + pContext->m_stack.Restore(nsize); + pContext->m_nCurrentPos = nbegin; + } + + // elx result + int bsucc; + if( condition_yes ) + bsucc = m_pelxyes == 0 ? 1 : m_pelxyes->Match(pContext); + else + bsucc = m_pelxno == 0 ? 1 : m_pelxno ->Match(pContext); + + if( bsucc ) + { + pContext->m_stack.Push(ncsize); + pContext->m_stack.Push(condition_yes); + } + else + { + pContext->m_capturestack.Restore(ncsize); + } + + return bsucc; +} + +template int CConditionElxT :: MatchNext(CContext * pContext) const +{ + // pop + int ncsize, condition_yes; + + pContext->m_stack.Pop(condition_yes); + pContext->m_stack.Pop(ncsize); + + // elx result + int bsucc; + if( condition_yes ) + bsucc = m_pelxyes == 0 ? 0 : m_pelxyes->MatchNext(pContext); + else + bsucc = m_pelxno == 0 ? 0 : m_pelxno ->MatchNext(pContext); + + if( bsucc ) + { + pContext->m_stack.Push(ncsize); + pContext->m_stack.Push(condition_yes); + } + else + { + pContext->m_capturestack.Restore(ncsize); + } + + return bsucc; +} + +// +// MatchResult +// +template class MatchResultT +{ +public: + int IsMatched() const; + +public: + int GetStart() const; + int GetEnd () const; + +public: + int MaxGroupNumber() const; + int GetGroupStart(int nGroupNumber) const; + int GetGroupEnd (int nGroupNumber) const; + +public: + MatchResultT(CContext * pContext, int nMaxNumber = -1); + MatchResultT & operator = (const MatchResultT &); + inline operator int() const { return IsMatched(); } + +public: + CBufferT m_result; +}; + +typedef MatchResultT <0> MatchResult; + +// Stocked Elx IDs +enum STOCKELX_ID_DEFINES +{ + STOCKELX_EMPTY = 0, + + /////////////////////// + + STOCKELX_DOT_ALL, + STOCKELX_DOT_NOT_ALL, + + STOCKELX_WORD, + STOCKELX_WORD_NOT, + + STOCKELX_SPACE, + STOCKELX_SPACE_NOT, + + STOCKELX_DIGITAL, + STOCKELX_DIGITAL_NOT, + + ////////////////////// + + STOCKELX_DOT_ALL_RIGHTLEFT, + STOCKELX_DOT_NOT_ALL_RIGHTLEFT, + + STOCKELX_WORD_RIGHTLEFT, + STOCKELX_WORD_RIGHTLEFT_NOT, + + STOCKELX_SPACE_RIGHTLEFT, + STOCKELX_SPACE_RIGHTLEFT_NOT, + + STOCKELX_DIGITAL_RIGHTLEFT, + STOCKELX_DIGITAL_RIGHTLEFT_NOT, + + ///////////////////// + + STOCKELX_COUNT +}; + +// REGEX_FLAGS +#ifndef _REGEX_FLAGS_DEFINED + enum REGEX_FLAGS + { + NO_FLAG = 0, + SINGLELINE = 0x01, + MULTILINE = 0x02, + GLOBAL = 0x04, + IGNORECASE = 0x08, + RIGHTTOLEFT = 0x10, + EXTENDED = 0x20, + }; + #define _REGEX_FLAGS_DEFINED +#endif + +// +// Builder T +// +template class CBuilderT +{ +public: + typedef CDelegateElxT CDelegateElx; + typedef CBracketElxT CBracketElx; + typedef CBackrefElxT CBackrefElx; + typedef CConditionElxT CConditionElx; + +// Methods +public: + ElxInterface * Build(const CBufferRefT & pattern, int flags); + int GetNamedNumber(const CBufferRefT & named) const; + void Clear(); + +public: + CBuilderT(); + ~CBuilderT(); + +// Public Attributes +public: + ElxInterface * m_pTopElx; + int m_nFlags; + int m_nMaxNumber; + int m_nNextNamed; + int m_nGroupCount; + + CBufferT m_objlist; + CBufferT m_grouplist; + CBufferT m_recursivelist; + CBufferT m_namedlist; + CBufferT m_namedbackreflist; + CBufferT m_namedconditionlist; + +// CHART_INFO +protected: + struct CHART_INFO + { + public: + CHART ch; + int type; + int pos; + int len; + + public: + CHART_INFO(CHART c, int t, int p = 0, int l = 0) { ch = c; type = t; pos = p; len = l; } + inline int operator == (const CHART_INFO & ci) { return ch == ci.ch && type == ci.type; } + inline int operator != (const CHART_INFO & ci) { return ! operator == (ci); } + }; + +protected: + static unsigned int Hex2Int(const CHART * pcsz, int length, int & used); + static int ReadDec(char * & str, unsigned int & dec); + void MoveNext(); + int GetNext2(); + + ElxInterface * BuildAlternative(int vaflags); + ElxInterface * BuildList (int & flags); + ElxInterface * BuildRepeat (int & flags); + ElxInterface * BuildSimple (int & flags); + ElxInterface * BuildCharset (int & flags); + ElxInterface * BuildRecursive (int & flags); + ElxInterface * BuildBoundary (int & flags); + ElxInterface * BuildBackref (int & flags); + + ElxInterface * GetStockElx (int nStockId); + ElxInterface * Keep(ElxInterface * pElx); + +// Private Attributes +protected: + CBufferRefT m_pattern; + CHART_INFO prev, curr, next, nex2; + int m_nNextPos; + int m_nCharsetDepth; + int m_bQuoted; + int (*m_quote_fun)(int); + + ElxInterface * m_pStockElxs[STOCKELX_COUNT]; +}; + +// +// Implementation +// +template CBuilderT :: CBuilderT() : m_pattern(0, 0), prev(0, 0), curr(0, 0), next(0, 0), nex2(0, 0) +{ + Clear(); +} + +template CBuilderT :: ~CBuilderT() +{ + Clear(); +} + +template int CBuilderT :: GetNamedNumber(const CBufferRefT & named) const +{ + for(int i=0; im_elxlist[0])->m_szNamed.CompareNoCase(named) ) + return ((CBracketElx *)m_namedlist[i]->m_elxlist[0])->m_nnumber; + } + + return -3; +} + +template ElxInterface * CBuilderT :: Build(const CBufferRefT & pattern, int flags) +{ + // init + m_pattern = pattern; + m_nNextPos = 0; + m_nCharsetDepth = 0; + m_nMaxNumber = 0; + m_nNextNamed = 0; + m_nFlags = flags; + m_bQuoted = 0; + m_quote_fun = 0; + + m_grouplist .Restore(0); + m_recursivelist .Restore(0); + m_namedlist .Restore(0); + m_namedbackreflist .Restore(0); + m_namedconditionlist.Restore(0); + + int i; + for(i=0; i<3; i++) MoveNext(); + + // build + m_pTopElx = BuildAlternative(flags); + + // group 0 + m_grouplist.Prepare(0); + m_grouplist[0] = m_pTopElx; + + // append named to unnamed + m_nGroupCount = m_grouplist.GetSize(); + + m_grouplist.Prepare(m_nMaxNumber + m_namedlist.GetSize()); + + for(i=0; im_elxlist[0]; + CBracketElx * pright = (CBracketElx *)m_namedlist[i]->m_elxlist[2]; + + // append + m_grouplist[m_nGroupCount ++] = m_namedlist[i]; + + if( pleft->m_nnumber > 0 ) + continue; + + // same name + int find_same_name = GetNamedNumber(pleft->m_szNamed); + if( find_same_name >= 0 ) + { + pleft ->m_nnumber = find_same_name; + pright->m_nnumber = find_same_name; + } + else + { + m_nMaxNumber ++; + + pleft ->m_nnumber = m_nMaxNumber; + pright->m_nnumber = m_nMaxNumber; + } + } + + for(i=1; im_elxlist[0]; + + if( pleft->m_nnumber > m_nMaxNumber ) + m_nMaxNumber = pleft->m_nnumber; + } + + // connect recursive + for(i=0; im_ndata == -3 ) + m_recursivelist[i]->m_ndata = GetNamedNumber(m_recursivelist[i]->m_szNamed); + + if( m_recursivelist[i]->m_ndata >= 0 && m_recursivelist[i]->m_ndata < m_grouplist.GetSize() ) + m_recursivelist[i]->m_pelx = m_grouplist[m_recursivelist[i]->m_ndata]; + } + + // named backref + for(i=0; im_nnumber = GetNamedNumber(m_namedbackreflist[i]->m_szNamed); + } + + // named condition + for(i=0; im_szNamed); + if( nn >= 0 ) + { + m_namedconditionlist[i]->m_nnumber = nn; + m_namedconditionlist[i]->m_pelxask = 0; + } + } + + return m_pTopElx; +} + +template void CBuilderT :: Clear() +{ + for(int i=0; i unsigned int CBuilderT :: Hex2Int(const CHART * pcsz, int length, int & used) +{ + unsigned int result = 0; + int & i = used; + + for(i=0; i= RCHART('0') && pcsz[i] <= RCHART('9')) + result = (result << 4) + (pcsz[i] - RCHART('0')); + else if(pcsz[i] >= RCHART('A') && pcsz[i] <= RCHART('F')) + result = (result << 4) + (0x0A + (pcsz[i] - RCHART('A'))); + else if(pcsz[i] >= RCHART('a') && pcsz[i] <= RCHART('f')) + result = (result << 4) + (0x0A + (pcsz[i] - RCHART('a'))); + else + break; + } + + return result; +} + +template inline ElxInterface * CBuilderT :: Keep(ElxInterface * pelx) +{ + m_objlist.Push(pelx); + return pelx; +} + +template void CBuilderT :: MoveNext() +{ + // forwards + prev = curr; + curr = next; + next = nex2; + + // get nex2 + while( ! GetNext2() ) {}; +} + +template int CBuilderT :: GetNext2() +{ + // check length + if(m_nNextPos >= m_pattern.GetSize()) + { + nex2 = CHART_INFO(0, 1, m_nNextPos, 0); + return 1; + } + + int delta = 1; + CHART ch = m_pattern[m_nNextPos]; + + // if quoted + if(m_bQuoted) + { + if(ch == RCHART('\\')) + { + if(m_pattern[m_nNextPos + 1] == RCHART('E')) + { + m_quote_fun = 0; + m_bQuoted = 0; + m_nNextPos += 2; + return 0; + } + } + + if(m_quote_fun != 0) + nex2 = CHART_INFO((CHART)(*m_quote_fun)((int)ch), 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + + m_nNextPos += delta; + + return 1; + } + + // common + switch(ch) + { + case RCHART('\\'): + { + CHART ch1 = m_pattern[m_nNextPos+1]; + + // backref + if(ch1 >= RCHART('0') && ch1 <= RCHART('9')) + { + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + break; + } + + // escape + delta = 2; + + switch(ch1) + { + case RCHART('A'): + case RCHART('Z'): + case RCHART('w'): + case RCHART('W'): + case RCHART('s'): + case RCHART('S'): + case RCHART('B'): + case RCHART('d'): + case RCHART('D'): + case RCHART('k'): + case RCHART('g'): + nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta); + break; + + case RCHART('b'): + if(m_nCharsetDepth > 0) + nex2 = CHART_INFO('\b', 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta); + break; + + /* + case RCHART('<'): + case RCHART('>'): + if(m_nCharsetDepth > 0) + nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta); + break; + */ + + case RCHART('x'): + if(m_pattern[m_nNextPos+2] != '{') + { + int red = 0; + unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 2, 2, red); + + delta += red; + + if(red > 0) + nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); + + break; + } + + case RCHART('u'): + if(m_pattern[m_nNextPos+2] != '{') + { + int red = 0; + unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 2, 4, red); + + delta += red; + + if(red > 0) + nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); + } + else + { + int red = 0; + unsigned int ch2 = Hex2Int(m_pattern.GetBuffer() + m_nNextPos + 3, sizeof(int) * 2, red); + + delta += red; + + while(m_nNextPos + delta < m_pattern.GetSize() && m_pattern.At(m_nNextPos + delta) != RCHART('}')) + delta ++; + + delta ++; // skip '}' + + nex2 = CHART_INFO(RCHART(ch2), 0, m_nNextPos, delta); + } + break; + + case RCHART('a'): nex2 = CHART_INFO(RCHART('\a'), 0, m_nNextPos, delta); break; + case RCHART('f'): nex2 = CHART_INFO(RCHART('\f'), 0, m_nNextPos, delta); break; + case RCHART('n'): nex2 = CHART_INFO(RCHART('\n'), 0, m_nNextPos, delta); break; + case RCHART('r'): nex2 = CHART_INFO(RCHART('\r'), 0, m_nNextPos, delta); break; + case RCHART('t'): nex2 = CHART_INFO(RCHART('\t'), 0, m_nNextPos, delta); break; + case RCHART('v'): nex2 = CHART_INFO(RCHART('\v'), 0, m_nNextPos, delta); break; + case RCHART('e'): nex2 = CHART_INFO(RCHART( 27 ), 0, m_nNextPos, delta); break; + + case RCHART('G'): // skip '\G' + if(m_nCharsetDepth > 0) + { + m_nNextPos += 2; + return 0; + } + else + { + nex2 = CHART_INFO(ch1, 1, m_nNextPos, delta); + break; + } + + case RCHART('L'): + if( ! m_quote_fun ) m_quote_fun = ::tolower; + + case RCHART('U'): + if( ! m_quote_fun ) m_quote_fun = ::toupper; + + case RCHART('Q'): + { + m_bQuoted = 1; + m_nNextPos += 2; + return 0; + } + + case RCHART('E'): + { + m_quote_fun = 0; + m_bQuoted = 0; + m_nNextPos += 2; + return 0; + } + + case 0: + if(m_nNextPos+1 >= m_pattern.GetSize()) + { + delta = 1; + nex2 = CHART_INFO(ch , 0, m_nNextPos, delta); + } + else + nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); // common '\0' char + break; + + default: + nex2 = CHART_INFO(ch1, 0, m_nNextPos, delta); + break; + } + } + break; + + case RCHART('*'): + case RCHART('+'): + case RCHART('?'): + case RCHART('.'): + case RCHART('{'): + case RCHART('}'): + case RCHART(')'): + case RCHART('|'): + case RCHART('$'): + if(m_nCharsetDepth > 0) + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + break; + + case RCHART('-'): + if(m_nCharsetDepth > 0) + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + break; + + case RCHART('('): + { + CHART ch1 = m_pattern[m_nNextPos+1]; + CHART ch2 = m_pattern[m_nNextPos+2]; + + // skip remark + if(ch1 == RCHART('?') && ch2 == RCHART('#')) + { + m_nNextPos += 2; + while(m_nNextPos < m_pattern.GetSize()) + { + if(m_pattern[m_nNextPos] == RCHART(')')) + break; + + m_nNextPos ++; + } + + if(m_pattern[m_nNextPos] == RCHART(')')) + { + m_nNextPos ++; + + // get next nex2 + return 0; + } + } + else + { + if(m_nCharsetDepth > 0) + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + } + } + break; + + case RCHART('#'): + if(m_nFlags & EXTENDED) + { + // skip remark + m_nNextPos ++; + + while(m_nNextPos < m_pattern.GetSize()) + { + if(m_pattern[m_nNextPos] == RCHART('\n') || m_pattern[m_nNextPos] == RCHART('\r')) + break; + + m_nNextPos ++; + } + + // get next nex2 + return 0; + } + else + { + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + } + break; + + case RCHART(' '): + case RCHART('\f'): + case RCHART('\n'): + case RCHART('\r'): + case RCHART('\t'): + case RCHART('\v'): + if(m_nFlags & EXTENDED) + { + m_nNextPos ++; + + // get next nex2 + return 0; + } + else + { + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + } + break; + + case RCHART('['): + m_nCharsetDepth ++; + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + break; + + case RCHART(']'): + if(m_nCharsetDepth > 0) + { + m_nCharsetDepth --; + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + } + else + { + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + } + break; + + case RCHART(':'): + if(next == CHART_INFO(RCHART('['), 1)) + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + break; + + case RCHART('^'): + if(m_nCharsetDepth == 0 || next == CHART_INFO(RCHART('['), 1) || (curr == CHART_INFO(RCHART('['), 1) && next == CHART_INFO(RCHART(':'), 1))) + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); + else + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + break; + + case 0: + if(m_nNextPos >= m_pattern.GetSize()) + nex2 = CHART_INFO(ch, 1, m_nNextPos, delta); // end of string + else + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); // common '\0' char + break; + + default: + nex2 = CHART_INFO(ch, 0, m_nNextPos, delta); + break; + } + + m_nNextPos += delta; + + return 1; +} + +template ElxInterface * CBuilderT :: GetStockElx(int nStockId) +{ + ElxInterface ** pStockElxs = m_pStockElxs; + + // check + if(nStockId < 0 || nStockId >= STOCKELX_COUNT) + return GetStockElx(0); + + // create if no + if(pStockElxs[nStockId] == 0) + { + switch(nStockId) + { + case STOCKELX_EMPTY: + pStockElxs[nStockId] = Keep(new CEmptyElx()); + break; + + case STOCKELX_WORD: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 1)); + + pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z')); + pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z')); + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + pRange->m_chars .Push(RCHART('_')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_WORD_NOT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 0)); + + pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z')); + pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z')); + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + pRange->m_chars .Push(RCHART('_')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_DOT_ALL: + pStockElxs[nStockId] = Keep(new CRangeElxT (0, 0)); + break; + + case STOCKELX_DOT_NOT_ALL: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 0)); + + pRange->m_chars .Push(RCHART('\n')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_SPACE: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 1)); + + pRange->m_chars .Push(RCHART(' ')); + pRange->m_chars .Push(RCHART('\t')); + pRange->m_chars .Push(RCHART('\r')); + pRange->m_chars .Push(RCHART('\n')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_SPACE_NOT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 0)); + + pRange->m_chars .Push(RCHART(' ')); + pRange->m_chars .Push(RCHART('\t')); + pRange->m_chars .Push(RCHART('\r')); + pRange->m_chars .Push(RCHART('\n')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_DIGITAL: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 1)); + + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_DIGITAL_NOT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (0, 0)); + + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_WORD_RIGHTLEFT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 1)); + + pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z')); + pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z')); + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + pRange->m_chars .Push(RCHART('_')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_WORD_RIGHTLEFT_NOT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 0)); + + pRange->m_ranges.Push(RCHART('A')); pRange->m_ranges.Push(RCHART('Z')); + pRange->m_ranges.Push(RCHART('a')); pRange->m_ranges.Push(RCHART('z')); + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + pRange->m_chars .Push(RCHART('_')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_DOT_ALL_RIGHTLEFT: + pStockElxs[nStockId] = Keep(new CRangeElxT (1, 0)); + break; + + case STOCKELX_DOT_NOT_ALL_RIGHTLEFT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 0)); + + pRange->m_chars .Push(RCHART('\n')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_SPACE_RIGHTLEFT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 1)); + + pRange->m_chars .Push(RCHART(' ')); + pRange->m_chars .Push(RCHART('\t')); + pRange->m_chars .Push(RCHART('\r')); + pRange->m_chars .Push(RCHART('\n')); + pRange->m_chars .Push(RCHART('\f')); + pRange->m_chars .Push(RCHART('\v')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_SPACE_RIGHTLEFT_NOT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 0)); + + pRange->m_chars .Push(RCHART(' ')); + pRange->m_chars .Push(RCHART('\t')); + pRange->m_chars .Push(RCHART('\r')); + pRange->m_chars .Push(RCHART('\n')); + pRange->m_chars .Push(RCHART('\f')); + pRange->m_chars .Push(RCHART('\v')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_DIGITAL_RIGHTLEFT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 1)); + + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + + pStockElxs[nStockId] = pRange; + } + break; + + case STOCKELX_DIGITAL_RIGHTLEFT_NOT: + { + CRangeElxT * pRange = (CRangeElxT *)Keep(new CRangeElxT (1, 0)); + + pRange->m_ranges.Push(RCHART('0')); pRange->m_ranges.Push(RCHART('9')); + + pStockElxs[nStockId] = pRange; + } + break; + } + } + + // return + return pStockElxs[nStockId]; +} + +template ElxInterface * CBuilderT :: BuildAlternative(int vaflags) +{ + if(curr == CHART_INFO(0, 1)) + return GetStockElx(STOCKELX_EMPTY); + + // flag instance + int flags = vaflags; + + // first part + ElxInterface * pAlternativeOne = BuildList(flags); + + // check alternative + if(curr == CHART_INFO(RCHART('|'), 1)) + { + CAlternativeElx * pAlternative = (CAlternativeElx *)Keep(new CAlternativeElx()); + pAlternative->m_elxlist.Push(pAlternativeOne); + + // loop + while(curr == CHART_INFO(RCHART('|'), 1)) + { + // skip '|' itself + MoveNext(); + + pAlternativeOne = BuildList(flags); + pAlternative->m_elxlist.Push(pAlternativeOne); + } + + return pAlternative; + } + + return pAlternativeOne; +} + +template ElxInterface * CBuilderT :: BuildList(int & flags) +{ + if(curr == CHART_INFO(0, 1) || curr == CHART_INFO(RCHART('|'), 1) || curr == CHART_INFO(RCHART(')'), 1)) + return GetStockElx(STOCKELX_EMPTY); + + // first + ElxInterface * pListOne = BuildRepeat(flags); + + if(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('|'), 1) && curr != CHART_INFO(RCHART(')'), 1)) + { + CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT)); + pList->m_elxlist.Push(pListOne); + + while(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('|'), 1) && curr != CHART_INFO(RCHART(')'), 1)) + { + pListOne = BuildRepeat(flags); + + // add + pList->m_elxlist.Push(pListOne); + } + + return pList; + } + + return pListOne; +} + +template ElxInterface * CBuilderT :: BuildRepeat(int & flags) +{ + // simple + ElxInterface * pSimple = BuildSimple(flags); + + if(curr.type == 0) return pSimple; + + // is quantifier or not + int bIsQuantifier = 1; + + // quantifier range + unsigned int nMin = 0, nMax = 0; + + switch(curr.ch) + { + case RCHART('{'): + { + CBufferT re; + + // skip '{' + MoveNext(); + + // copy + while(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART('}'), 1)) + { + re.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + + // skip '}' + MoveNext(); + + // read + int red; + char * str = re.GetBuffer(); + + if( ! ReadDec(str, nMin) ) + red = 0; + else if( *str != ',' ) + red = 1; + else + { + str ++; + + if( ! ReadDec(str, nMax) ) + red = 2; + else + red = 3; + } + + // check + if(red <= 1 ) nMax = nMin; + if(red == 2 ) nMax = INT_MAX; + if(nMax < nMin) nMax = nMin; + } + break; + + case RCHART('?'): + nMin = 0; + nMax = 1; + + // skip '?' + MoveNext(); + break; + + case RCHART('*'): + nMin = 0; + nMax = INT_MAX; + + // skip '*' + MoveNext(); + break; + + case RCHART('+'): + nMin = 1; + nMax = INT_MAX; + + // skip '+' + MoveNext(); + break; + + default: + bIsQuantifier = 0; + break; + } + + // do quantify + if(bIsQuantifier) + { + // 0 times + if(nMax == 0) + return GetStockElx(STOCKELX_EMPTY); + + // fixed times + if(nMin == nMax) + { + if(curr == CHART_INFO(RCHART('?'), 1) || curr == CHART_INFO(RCHART('+'), 1)) + MoveNext(); + + return Keep(new CRepeatElx(pSimple, nMin)); + } + + // range times + if(curr == CHART_INFO(RCHART('?'), 1)) + { + MoveNext(); + return Keep(new CReluctantElx(pSimple, nMin, nMax)); + } + else if(curr == CHART_INFO(RCHART('+'), 1)) + { + MoveNext(); + return Keep(new CPossessiveElx(pSimple, nMin, nMax)); + } + else + { + return Keep(new CGreedyElx(pSimple, nMin, nMax)); + } + } + + return pSimple; +} + +template ElxInterface * CBuilderT :: BuildSimple(int & flags) +{ + CBufferT fixed; + + while(curr != CHART_INFO(0, 1)) + { + if(curr.type == 0) + { + if(next == CHART_INFO(RCHART('{'), 1) || next == CHART_INFO(RCHART('?'), 1) || next == CHART_INFO(RCHART('*'), 1) || next == CHART_INFO(RCHART('+'), 1)) + { + if(fixed.GetSize() == 0) + { + fixed.Append(curr.ch, 1); + MoveNext(); + } + + break; + } + else + { + fixed.Append(curr.ch, 1); + MoveNext(); + } + } + else if(curr.type == 1) + { + CHART vch = curr.ch; + + // end of simple + if(vch == RCHART(')') || vch == RCHART('|')) + break; + + // has fixed already + if(fixed.GetSize() > 0) + break; + + // left parentheses + if(vch == RCHART('(')) + { + return BuildRecursive(flags); + } + + // char set + if( vch == RCHART('[') || vch == RCHART('.') || vch == RCHART('w') || vch == RCHART('W') || + vch == RCHART('s') || vch == RCHART('S') || vch == RCHART('d') || vch == RCHART('D') + ) + { + return BuildCharset(flags); + } + + // boundary + if( vch == RCHART('^') || vch == RCHART('$') || vch == RCHART('A') || vch == RCHART('Z') || + vch == RCHART('b') || vch == RCHART('B') || vch == RCHART('G') // vch == RCHART('<') || vch == RCHART('>') + ) + { + return BuildBoundary(flags); + } + + // backref + if(vch == RCHART('\\') || vch == RCHART('k') || vch == RCHART('g')) + { + return BuildBackref(flags); + } + + // treat vchar as char + fixed.Append(curr.ch, 1); + MoveNext(); + } + } + + if(fixed.GetSize() > 0) + return Keep(new CStringElxT (fixed.GetBuffer(), fixed.GetSize(), flags & RIGHTTOLEFT, flags & IGNORECASE)); + else + return GetStockElx(STOCKELX_EMPTY); +} + +template ElxInterface * CBuilderT :: BuildCharset(int & flags) +{ + // char + CHART ch = curr.ch; + + // skip + MoveNext(); + + switch(ch) + { + case RCHART('.'): + return GetStockElx( + flags & RIGHTTOLEFT ? + ((flags & SINGLELINE) ? STOCKELX_DOT_ALL_RIGHTLEFT : STOCKELX_DOT_NOT_ALL_RIGHTLEFT) : + ((flags & SINGLELINE) ? STOCKELX_DOT_ALL : STOCKELX_DOT_NOT_ALL) + ); + + case RCHART('w'): + return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_WORD_RIGHTLEFT : STOCKELX_WORD); + + case RCHART('W'): + return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_WORD_RIGHTLEFT_NOT : STOCKELX_WORD_NOT); + + case RCHART('s'): + return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_SPACE_RIGHTLEFT : STOCKELX_SPACE); + + case RCHART('S'): + return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_SPACE_RIGHTLEFT_NOT : STOCKELX_SPACE_NOT); + + case RCHART('d'): + return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_DIGITAL_RIGHTLEFT : STOCKELX_DIGITAL); + + case RCHART('D'): + return GetStockElx(flags & RIGHTTOLEFT ? STOCKELX_DIGITAL_RIGHTLEFT_NOT : STOCKELX_DIGITAL_NOT); + + case RCHART('['): + { + CRangeElxT * pRange; + + // create + if(curr == CHART_INFO(RCHART(':'), 1)) + { + CBufferT posix; + + do { + posix.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + while(curr.ch != RCHART(0) && curr != CHART_INFO(RCHART(']'), 1)); + + MoveNext(); // skip ']' + + // posix + return Keep(new CPosixElxT (posix.GetBuffer(), flags & RIGHTTOLEFT)); + } + else if(curr == CHART_INFO(RCHART('^'), 1)) + { + MoveNext(); // skip '^' + pRange = (CRangeElxT *)Keep(new CRangeElxT (flags & RIGHTTOLEFT, 0)); + } + else + { + pRange = (CRangeElxT *)Keep(new CRangeElxT (flags & RIGHTTOLEFT, 1)); + } + + // parse + while(curr != CHART_INFO(0, 1) && curr != CHART_INFO(RCHART(']'), 1)) + { + ch = curr.ch; + + if(curr.type == 1 && ( + ch == RCHART('.') || ch == RCHART('w') || ch == RCHART('W') || ch == RCHART('s') || ch == RCHART('S') || ch == RCHART('d') || ch == RCHART('D') || + (ch == RCHART('[') && next == CHART_INFO(RCHART(':'), 1)) + )) + { + pRange->m_embeds.Push(BuildCharset(flags)); + } + else if(next == CHART_INFO(RCHART('-'), 1) && nex2.type == 0) + { + pRange->m_ranges.Push(ch); pRange->m_ranges.Push(nex2.ch); + + // next + MoveNext(); + MoveNext(); + MoveNext(); + } + else + { + pRange->m_chars.Push(ch); + + // next + MoveNext(); + } + } + + // skip ']' + MoveNext(); + + return pRange; + } + } + + return GetStockElx(STOCKELX_EMPTY); +} + +template ElxInterface * CBuilderT :: BuildRecursive(int & flags) +{ + // skip '(' + MoveNext(); + + if(curr == CHART_INFO(RCHART('?'), 1)) + { + ElxInterface * pElx = 0; + + // skip '?' + MoveNext(); + + int bNegative = 0; + CHART named_end = RCHART('>'); + + switch(curr.ch) + { + case RCHART('!'): + bNegative = 1; + + case RCHART('='): + { + MoveNext(); // skip '!' or '=' + pElx = Keep(new CAssertElx(BuildAlternative(flags & ~RIGHTTOLEFT), !bNegative)); + } + break; + + case RCHART('<'): + switch(next.ch) + { + case RCHART('!'): + bNegative = 1; + + case RCHART('='): + MoveNext(); // skip '<' + MoveNext(); // skip '!' or '=' + { + pElx = Keep(new CAssertElx(BuildAlternative(flags | RIGHTTOLEFT), !bNegative)); + } + break; + + default: // named group + break; + } + // break if assertion // else named + if(pElx != 0) break; + + case RCHART('P'): + if(curr.ch == RCHART('P')) MoveNext(); // skip 'P' + + case RCHART('\''): + if (curr.ch == RCHART('<' )) named_end = RCHART('>' ); + else if(curr.ch == RCHART('\'')) named_end = RCHART('\''); + MoveNext(); // skip '<' or '\'' + { + // named number + int nThisBackref = m_nNextNamed ++; + + CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT)); + CBracketElx * pleft = (CBracketElx *)Keep(new CBracketElx(-1, flags & RIGHTTOLEFT ? 1 : 0)); + CBracketElx * pright = (CBracketElx *)Keep(new CBracketElx(-1, flags & RIGHTTOLEFT ? 0 : 1)); + + // save name + CBufferT & name = pleft->m_szNamed; + CBufferT num; + + while(curr.ch != RCHART(0) && curr.ch != named_end) + { + name.Append(curr.ch, 1); + num .Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + MoveNext(); // skip '>' or '\'' + + // check + unsigned int number; + char * str = num.GetBuffer(); + + if( ReadDec(str, number) ? ( *str == '\0') : 0 ) + { + pleft ->m_nnumber = number; + pright->m_nnumber = number; + + name.Release(); + } + + // left, center, right + pList->m_elxlist.Push(pleft); + pList->m_elxlist.Push(BuildAlternative(flags)); + pList->m_elxlist.Push(pright); + + // for recursive + m_namedlist.Prepare(nThisBackref); + m_namedlist[nThisBackref] = pList; + + pElx = pList; + } + break; + + case RCHART('>'): + { + MoveNext(); // skip '>' + pElx = Keep(new CIndependentElx(BuildAlternative(flags))); + } + break; + + case RCHART('R'): + MoveNext(); // skip 'R' + while(curr.ch != RCHART(0) && isspace(curr.ch)) MoveNext(); // skip space + + if(curr.ch == RCHART('<') || curr.ch == RCHART('\'')) + { + named_end = curr.ch == RCHART('<') ? RCHART('>') : RCHART('\''); + CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(-3)); + + MoveNext(); // skip '<' or '\\' + + // save name + CBufferT & name = pDelegate->m_szNamed; + CBufferT num; + + while(curr.ch != RCHART(0) && curr.ch != named_end) + { + name.Append(curr.ch, 1); + num .Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + MoveNext(); // skip '>' or '\'' + + // check + unsigned int number; + char * str = num.GetBuffer(); + + if( ReadDec(str, number) ? ( *str == '\0') : 0 ) + { + pDelegate->m_ndata = number; + name.Release(); + } + + m_recursivelist.Push(pDelegate); + pElx = pDelegate; + } + else + { + CBufferT rto; + while(curr.ch != RCHART(0) && curr.ch != RCHART(')')) + { + rto.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + + unsigned int rtono = 0; + char * str = rto.GetBuffer(); + ReadDec(str, rtono); + + CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(rtono)); + + m_recursivelist.Push(pDelegate); + pElx = pDelegate; + } + break; + + case RCHART('('): + { + CConditionElx * pConditionElx = (CConditionElx *)Keep(new CConditionElx()); + + // condition + ElxInterface * & pCondition = pConditionElx->m_pelxask; + + if(next == CHART_INFO(RCHART('?'), 1)) + { + pCondition = BuildRecursive(flags); + } + else // named, assert or number + { + MoveNext(); // skip '(' + int pos0 = curr.pos; + + // save elx condition + pCondition = Keep(new CAssertElx(BuildAlternative(flags), 1)); + + // save name + pConditionElx->m_szNamed.Append(m_pattern.GetBuffer() + pos0, curr.pos - pos0, 1); + + // save number + CBufferT numstr; + while(pos0 < curr.pos) + { + CHART ch = m_pattern[pos0]; + numstr.Append(((ch & (CHART)0xff) == ch) ? (char)ch : 0, 1); + pos0 ++; + } + + unsigned int number; + char * str = numstr.GetBuffer(); + + // valid group number + if( ReadDec(str, number) ? ( *str == '\0') : 0 ) + { + pConditionElx->m_nnumber = number; + pCondition = 0; + } + else // maybe elx, maybe named + { + pConditionElx->m_nnumber = -1; + m_namedconditionlist.Push(pConditionElx); + } + + MoveNext(); // skip ')' + } + + // alternative + { + int newflags = flags; + + pConditionElx->m_pelxyes = BuildList(newflags); + } + + if(curr.ch == RCHART('|')) + { + MoveNext(); // skip '|' + + pConditionElx->m_pelxno = BuildAlternative(flags); + } + else + { + pConditionElx->m_pelxno = 0; + } + + pElx = pConditionElx; + } + break; + + default: + while(curr.ch != RCHART(0) && isspace(curr.ch)) MoveNext(); // skip space + + if(curr.ch >= RCHART('0') && curr.ch <= RCHART('9')) // recursive (?1) => (?R1) + { + CBufferT rto; + while(curr.ch != RCHART(0) && curr.ch != RCHART(')')) + { + rto.Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + + unsigned int rtono = 0; + char * str = rto.GetBuffer(); + ReadDec(str, rtono); + + CDelegateElx * pDelegate = (CDelegateElx *)Keep(new CDelegateElx(rtono)); + + m_recursivelist.Push(pDelegate); + pElx = pDelegate; + } + else + { + // flag + int newflags = flags; + while(curr != CHART_INFO(0, 1) && curr.ch != RCHART(':') && curr.ch != RCHART(')') && curr != CHART_INFO(RCHART('('), 1)) + { + int tochange = 0; + + switch(curr.ch) + { + case RCHART('i'): + case RCHART('I'): + tochange = IGNORECASE; + break; + + case RCHART('s'): + case RCHART('S'): + tochange = SINGLELINE; + break; + + case RCHART('m'): + case RCHART('M'): + tochange = MULTILINE; + break; + + case RCHART('g'): + case RCHART('G'): + tochange = GLOBAL; + break; + + case RCHART('-'): + bNegative = 1; + break; + } + + if(bNegative) + newflags &= ~tochange; + else + newflags |= tochange; + + // move to next char + MoveNext(); + } + + if(curr.ch == RCHART(':') || curr == CHART_INFO(RCHART('('), 1)) + { + // skip ':' + if(curr.ch == RCHART(':')) MoveNext(); + + pElx = BuildAlternative(newflags); + } + else + { + // change parent flags + flags = newflags; + + pElx = GetStockElx(STOCKELX_EMPTY); + } + } + break; + } + + MoveNext(); // skip ')' + + return pElx; + } + else + { + // group and number + CListElx * pList = (CListElx *)Keep(new CListElx(flags & RIGHTTOLEFT)); + int nThisBackref = ++ m_nMaxNumber; + + // left, center, right + pList->m_elxlist.Push(Keep(new CBracketElx(nThisBackref, flags & RIGHTTOLEFT ? 1 : 0))); + pList->m_elxlist.Push(BuildAlternative(flags)); + pList->m_elxlist.Push(Keep(new CBracketElx(nThisBackref, flags & RIGHTTOLEFT ? 0 : 1))); + + // for recursive + m_grouplist.Prepare(nThisBackref); + m_grouplist[nThisBackref] = pList; + + // right + MoveNext(); // skip ')' + + return pList; + } +} + +template ElxInterface * CBuilderT :: BuildBoundary(int & flags) +{ + // char + CHART ch = curr.ch; + + // skip + MoveNext(); + + switch(ch) + { + case RCHART('^'): + return Keep(new CBoundaryElxT ((flags & MULTILINE) ? BOUNDARY_LINE_BEGIN : BOUNDARY_FILE_BEGIN)); + + case RCHART('$'): + return Keep(new CBoundaryElxT ((flags & MULTILINE) ? BOUNDARY_LINE_END : BOUNDARY_FILE_END)); + + case RCHART('b'): + return Keep(new CBoundaryElxT (BOUNDARY_WORD_EDGE)); + + case RCHART('B'): + return Keep(new CBoundaryElxT (BOUNDARY_WORD_EDGE, 0)); + + case RCHART('A'): + return Keep(new CBoundaryElxT (BOUNDARY_FILE_BEGIN)); + + case RCHART('Z'): + return Keep(new CBoundaryElxT (BOUNDARY_FILE_END)); + + case RCHART('G'): + if(flags & GLOBAL) + return Keep(new CGlobalElx()); + else + return GetStockElx(STOCKELX_EMPTY); + + default: + return GetStockElx(STOCKELX_EMPTY); + } +} + +template ElxInterface * CBuilderT :: BuildBackref(int & flags) +{ + // skip '\\' or '\k' or '\g' + MoveNext(); + + if(curr.ch == RCHART('<') || curr.ch == RCHART('\'')) + { + CHART named_end = curr.ch == RCHART('<') ? RCHART('>') : RCHART('\''); + CBackrefElxT * pbackref = (CBackrefElxT *)Keep(new CBackrefElxT (-1, flags & RIGHTTOLEFT, flags & IGNORECASE)); + + MoveNext(); // skip '<' or '\'' + + // save name + CBufferT & name = pbackref->m_szNamed; + CBufferT num; + + while(curr.ch != RCHART(0) && curr.ch != named_end) + { + name.Append(curr.ch, 1); + num .Append(((curr.ch & (CHART)0xff) == curr.ch) ? (char)curr.ch : 0, 1); + MoveNext(); + } + MoveNext(); // skip '>' or '\'' + + // check + unsigned int number; + char * str = num.GetBuffer(); + + if( ReadDec(str, number) ? ( *str == '\0') : 0 ) + { + pbackref->m_nnumber = number; + name.Release(); + } + else + { + m_namedbackreflist.Push(pbackref); + } + + return pbackref; + } + else + { + unsigned int nbackref = 0; + + for(int i=0; i<3; i++) + { + if(curr.ch >= RCHART('0') && curr.ch <= RCHART('9')) + nbackref = nbackref * 10 + (curr.ch - RCHART('0')); + else + break; + + MoveNext(); + } + + return Keep(new CBackrefElxT (nbackref, flags & RIGHTTOLEFT, flags & IGNORECASE)); + } +} + +template int CBuilderT :: ReadDec(char * & str, unsigned int & dec) +{ + int s = 0; + while(str[s] != 0 && isspace(str[s])) s++; + + if(str[s] < '0' || str[s] > '9') return 0; + + dec = 0; + unsigned int i; + + for(i = s; i= '0' && str[i] <= '9') + dec = dec * 10 + (str[i] - '0'); + else + break; + } + + while(str[i] != 0 && isspace(str[i])) i++; + str += i; + + return 1; +} + +// +// Regexp +// +template class CRegexpT +{ +public: + CRegexpT(const CHART * pattern = 0, int flags = 0); + CRegexpT(const CHART * pattern, int length, int flags); + void Compile(const CHART * pattern, int flags = 0); + void Compile(const CHART * pattern, int length, int flags); + +public: + MatchResult MatchExact(const CHART * tstring, CContext * pContext = 0) const; + MatchResult MatchExact(const CHART * tstring, int length, CContext * pContext = 0) const; + MatchResult Match(const CHART * tstring, int start = -1, CContext * pContext = 0) const; + MatchResult Match(const CHART * tstring, int length, int start, CContext * pContext = 0) const; + MatchResult Match(CContext * pContext) const; + CContext * PrepareMatch(const CHART * tstring, int start = -1, CContext * pContext = 0) const; + CContext * PrepareMatch(const CHART * tstring, int length, int start, CContext * pContext = 0) const; + CHART * Replace(const CHART * tstring, const CHART * replaceto, int start = -1, int ntimes = -1, MatchResult * result = 0, CContext * pContext = 0) const; + CHART * Replace(const CHART * tstring, int string_length, const CHART * replaceto, int to_length, int & result_length, int start = -1, int ntimes = -1, MatchResult * result = 0, CContext * pContext = 0) const; + int GetNamedGroupNumber(const CHART * group_name) const; + +public: + static void ReleaseString (CHART * tstring ); + static void ReleaseContext(CContext * pContext); + +public: + CBuilderT m_builder; +}; + +// +// Implementation +// +template CRegexpT :: CRegexpT(const CHART * pattern, int flags) +{ + Compile(pattern, CBufferRefT(pattern).GetSize(), flags); +} + +template CRegexpT :: CRegexpT(const CHART * pattern, int length, int flags) +{ + Compile(pattern, length, flags); +} + +template inline void CRegexpT :: Compile(const CHART * pattern, int flags) +{ + Compile(pattern, CBufferRefT(pattern).GetSize(), flags); +} + +template void CRegexpT :: Compile(const CHART * pattern, int length, int flags) +{ + m_builder.Clear(); + if(pattern != 0) m_builder.Build(CBufferRefT(pattern, length), flags); +} + +template inline MatchResult CRegexpT :: MatchExact(const CHART * tstring, CContext * pContext) const +{ + return MatchExact(tstring, CBufferRefT(tstring).GetSize(), pContext); +} + +template MatchResult CRegexpT :: MatchExact(const CHART * tstring, int length, CContext * pContext) const +{ + if(m_builder.m_pTopElx == 0) + return 0; + + // info + int endpos = 0; + + CContext context; + if(pContext == 0) pContext = &context; + + pContext->m_stack.Restore(0); + pContext->m_capturestack.Restore(0); + pContext->m_captureindex.Restore(0); + + pContext->m_nParenZindex = 0; + pContext->m_nLastBeginPos = -1; + pContext->m_pMatchString = (void*)tstring; + pContext->m_pMatchStringLength = length; + + if(m_builder.m_nFlags & RIGHTTOLEFT) + { + pContext->m_nBeginPos = length; + pContext->m_nCurrentPos = length; + endpos = 0; + } + else + { + pContext->m_nBeginPos = 0; + pContext->m_nCurrentPos = 0; + endpos = length; + } + + pContext->m_captureindex.Prepare(m_builder.m_nMaxNumber, -1); + pContext->m_captureindex[0] = 0; + pContext->m_capturestack.Push(0); + pContext->m_capturestack.Push(pContext->m_nCurrentPos); + pContext->m_capturestack.Push(-1); + pContext->m_capturestack.Push(-1); + + // match + if( ! m_builder.m_pTopElx->Match( pContext ) ) + return 0; + else + { + while( pContext->m_nCurrentPos != endpos ) + { + if( ! m_builder.m_pTopElx->MatchNext( pContext ) ) + return 0; + else + { + if( pContext->m_nLastBeginPos == pContext->m_nBeginPos && pContext->m_nBeginPos == pContext->m_nCurrentPos ) + return 0; + else + pContext->m_nLastBeginPos = pContext->m_nCurrentPos; + } + } + + // end pos + pContext->m_capturestack[2] = pContext->m_nCurrentPos; + + return MatchResult( pContext, m_builder.m_nMaxNumber ); + } +} + +template MatchResult CRegexpT :: Match(const CHART * tstring, int start, CContext * pContext) const +{ + return Match(tstring, CBufferRefT(tstring).GetSize(), start, pContext); +} + +template MatchResult CRegexpT :: Match(const CHART * tstring, int length, int start, CContext * pContext) const +{ + if(m_builder.m_pTopElx == 0) + return 0; + + CContext context; + if(pContext == 0) pContext = &context; + + pContext->m_nParenZindex = 0; + pContext->m_nLastBeginPos = -1; + pContext->m_pMatchString = (void*)tstring; + pContext->m_pMatchStringLength = length; + + if(start < 0) + { + if(m_builder.m_nFlags & RIGHTTOLEFT) + { + pContext->m_nBeginPos = length; + pContext->m_nCurrentPos = length; + } + else + { + pContext->m_nBeginPos = 0; + pContext->m_nCurrentPos = 0; + } + } + else + { + pContext->m_nBeginPos = start; + pContext->m_nCurrentPos = start; + } + + return Match( pContext ); +} + +template MatchResult CRegexpT :: Match(CContext * pContext) const +{ + if(m_builder.m_pTopElx == 0) + return 0; + + int endpos, delta; + + if(m_builder.m_nFlags & RIGHTTOLEFT) + { + endpos = -1; + delta = -1; + } + else + { + endpos = pContext->m_pMatchStringLength + 1; + delta = 1; + } + + while(pContext->m_nCurrentPos != endpos) + { + pContext->m_captureindex.Restore(0); + pContext->m_stack .Restore(0); + pContext->m_capturestack.Restore(0); + + pContext->m_captureindex.Prepare(m_builder.m_nMaxNumber, -1); + pContext->m_captureindex[0] = 0; + pContext->m_capturestack.Push(0); + pContext->m_capturestack.Push(pContext->m_nCurrentPos); + pContext->m_capturestack.Push(-1); + pContext->m_capturestack.Push(-1); + + if( m_builder.m_pTopElx->Match( pContext ) ) + { + // zero width + if( pContext->m_nLastBeginPos == pContext->m_nBeginPos && pContext->m_nBeginPos == pContext->m_nCurrentPos ) + { + pContext->m_nCurrentPos += delta; + continue; + } + + // save pos + pContext->m_nLastBeginPos = pContext->m_nBeginPos; + pContext->m_nBeginPos = pContext->m_nCurrentPos; + pContext->m_capturestack[2] = pContext->m_nCurrentPos; + + // return + return MatchResult( pContext, m_builder.m_nMaxNumber ); + } + else + { + pContext->m_nCurrentPos += delta; + } + } + + return 0; +} + +template inline CContext * CRegexpT :: PrepareMatch(const CHART * tstring, int start, CContext * pContext) const +{ + return PrepareMatch(tstring, CBufferRefT(tstring).GetSize(), start, pContext); +} + +template CContext * CRegexpT :: PrepareMatch(const CHART * tstring, int length, int start, CContext * pContext) const +{ + if(m_builder.m_pTopElx == 0) + return 0; + + if(pContext == 0) pContext = new CContext(); + + pContext->m_nParenZindex = 0; + pContext->m_nLastBeginPos = -1; + pContext->m_pMatchString = (void*)tstring; + pContext->m_pMatchStringLength = length; + + if(start < 0) + { + if(m_builder.m_nFlags & RIGHTTOLEFT) + { + pContext->m_nBeginPos = length; + pContext->m_nCurrentPos = length; + } + else + { + pContext->m_nBeginPos = 0; + pContext->m_nCurrentPos = 0; + } + } + else + { + pContext->m_nBeginPos = start; + pContext->m_nCurrentPos = start; + } + + return pContext; +} + +template inline int CRegexpT :: GetNamedGroupNumber(const CHART * group_name) const +{ + return m_builder.GetNamedNumber(group_name); +} + +template CHART * CRegexpT :: Replace(const CHART * tstring, const CHART * replaceto, int start, int ntimes, MatchResult * result, CContext * pContext) const +{ + int result_length = 0; + return Replace(tstring, CBufferRefT(tstring).GetSize(), replaceto, CBufferRefT(replaceto).GetSize(), result_length, start, ntimes, result, pContext); +} + +template CHART * CRegexpT :: Replace(const CHART * tstring, int string_length, const CHART * replaceto, int to_length, int & result_length, int start, int ntimes, MatchResult * remote_result, CContext * oContext) const +{ + typedef CBufferRefT StringRef; + + MatchResult local_result(0), * result = remote_result ? remote_result : & local_result; + + if(m_builder.m_pTopElx == 0) return 0; + + // Prepare + CContext * pContext = PrepareMatch(tstring, string_length, start, oContext); + + int flags = m_builder.m_nFlags; + int lastIndex = (flags & RIGHTTOLEFT) ? string_length : 0; + int endpos = (flags & RIGHTTOLEFT) ? 0 : string_length; + int toIndex = 0, toLastIndex = 0; + int i, ntime; + + CBufferT buffer, buf; + + static const CHART rtoptn[] = { RCHART('\\'), RCHART('$' ), RCHART('('), RCHART('?'), RCHART(':'), RCHART('[' ), RCHART('$' ), RCHART('&' ), RCHART('`' ), RCHART('\''), RCHART('+'), RCHART('_' ), RCHART('\\'), RCHART('d'), RCHART(']'), RCHART('|'), RCHART('\\'), RCHART('{'), RCHART('.'), RCHART('*'), RCHART('?'), RCHART('\\'), RCHART('}'), RCHART(')' ), RCHART('\0') }; + static int rtoptnlen = StringRef(rtoptn).GetSize(); + static CRegexpT rtoreg(rtoptn, rtoptnlen, 0); + + // Match + for(ntime = 0; ntimes < 0 || ntime < ntimes; ntime ++) + { + (*result) = Match(pContext); + + if( ! result->IsMatched() ) + break; + + toIndex = toLastIndex; + + // before + if( flags & RIGHTTOLEFT ) + { + int distance = lastIndex - result->GetEnd(); + if( distance ) + { + buffer.Push(new StringRef(tstring + result->GetEnd(), distance)); + toIndex -= distance; + } + lastIndex = result->GetStart(); + } + else + { + int distance = result->GetStart() - lastIndex; + if( distance ) + { + buffer.Push(new StringRef(tstring + lastIndex, distance)); + toIndex += distance; + } + lastIndex = result->GetEnd(); + } + + toLastIndex = toIndex; + + // middle + CContext * pCtx = rtoreg.PrepareMatch(replaceto, to_length, -1); + int lastI = 0; + + buf.Restore(0); + + while(1) + { + MatchResult res = rtoreg.Match(pCtx); + + if( ! res.IsMatched() ) + break; + + // before + int distance = res.GetStart() - lastI; + if( distance ) + { + buf.Push(new StringRef(replaceto + lastI, distance)); + } + lastI = res.GetStart(); + + // middle + int delta = 2, nmatch = 0; + + switch(replaceto[res.GetStart() + 1]) + { + case RCHART('$'): + buf.Push(new StringRef(rtoptn + 1, 1)); // '$' itself + break; + + case RCHART('&'): + buf.Push(new StringRef(tstring + result->GetStart(), result->GetEnd() - result->GetStart())); + break; + + case RCHART('`'): + buf.Push(new StringRef(tstring, result->GetStart())); + break; + + case RCHART('\''): + buf.Push(new StringRef(tstring + result->GetEnd(), string_length - result->GetEnd())); + break; + + case RCHART('+'): + for(nmatch = result->MaxGroupNumber(); nmatch >= 0; nmatch --) + { + if(result->GetGroupStart(nmatch) >= 0) break; + } + buf.Push(new StringRef(tstring + result->GetGroupStart(nmatch), result->GetGroupEnd(nmatch) - result->GetGroupStart(nmatch))); + break; + + case RCHART('_'): + buf.Push(new StringRef(tstring, string_length)); + break; + + case RCHART('{'): + delta = res.GetEnd() - res.GetStart(); + nmatch = m_builder.GetNamedNumber(StringRef(replaceto + (res.GetStart() + 2), delta - 3)); + + if(nmatch > 0 && nmatch <= m_builder.m_nMaxNumber) + buf.Push(new StringRef(tstring + result->GetGroupStart(nmatch), result->GetGroupEnd(nmatch) - result->GetGroupStart(nmatch))); + else + buf.Push(new StringRef(replaceto + res.GetStart(), delta)); + break; + + default: + nmatch = 0; + for(delta=1; delta<=3; delta++) + { + CHART ch = replaceto[lastI + delta]; + + if(ch < RCHART('0') || ch > RCHART('9')) + break; + + nmatch = nmatch * 10 + (ch - RCHART('0')); + } + + if(nmatch > m_builder.m_nMaxNumber) + { + while(nmatch > m_builder.m_nMaxNumber) + { + nmatch /= 10; + delta --; + } + + if(nmatch == 0) + { + delta = 1; + } + } + + if(delta == 1) + buf.Push(new StringRef(rtoptn + 1, 1)); // '$' itself + else + buf.Push(new StringRef(tstring + result->GetGroupStart(nmatch), result->GetGroupEnd(nmatch) - result->GetGroupStart(nmatch))); + break; + } + + lastI += delta; + } + + // after + if(lastI < to_length) + buf.Push(new StringRef(replaceto + lastI, to_length - lastI)); + + // append to buffer + if(flags & RIGHTTOLEFT) + { + for(i=buf.GetSize()-1; i>=0; i--) + { + buffer.Push(buf[i]); + toLastIndex -= buf[i]->GetSize(); + } + } + else + { + for(i=0; iGetSize(); + } + } + + rtoreg.ReleaseContext(pCtx); + } + + // after + if(flags & RIGHTTOLEFT) + { + if(endpos < lastIndex) buffer.Push(new StringRef(tstring + endpos, lastIndex - endpos)); + } + else + { + if(lastIndex < endpos) buffer.Push(new StringRef(tstring + lastIndex, endpos - lastIndex)); + } + + if(oContext == 0) ReleaseContext(pContext); + + // join string + result_length = 0; + for(i=0; iGetSize(); + + CBufferT result_string; + result_string.Prepare(result_length); + result_string.Restore(0); + + if(flags & RIGHTTOLEFT) + { + for(i=buffer.GetSize()-1; i>=0; i--) + { + result_string.Append(buffer[i]->GetBuffer(), buffer[i]->GetSize()); + delete buffer[i]; + } + } + else + { + for(i=0; iGetBuffer(), buffer[i]->GetSize()); + delete buffer[i]; + } + } + + result_string[result_length] = 0; + + result->m_result.Append(toIndex < toLastIndex ? toIndex : toLastIndex, 2); + result->m_result.Append(toIndex > toLastIndex ? toIndex : toLastIndex); + result->m_result.Append(ntime); + + return result_string.Detach(); +} + +template inline void CRegexpT :: ReleaseString(CHART * tstring) +{ + if(tstring != 0) delete [] tstring; +} + +template inline void CRegexpT :: ReleaseContext(CContext * pContext) +{ + if(pContext != 0) delete pContext; +} + +// +// All implementations +// +template CAlternativeElxT :: CAlternativeElxT() +{ +} + +template int CAlternativeElxT :: Match(CContext * pContext) const +{ + if(m_elxlist.GetSize() == 0) + return 1; + + // try all + for(int n = 0; n < m_elxlist.GetSize(); n++) + { + if(m_elxlist[n]->Match(pContext)) + { + pContext->m_stack.Push(n); + return 1; + } + } + + return 0; +} + +template int CAlternativeElxT :: MatchNext(CContext * pContext) const +{ + if(m_elxlist.GetSize() == 0) + return 0; + + int n = 0; + + // recall prev + pContext->m_stack.Pop(n); + + // prev + if(m_elxlist[n]->MatchNext(pContext)) + { + pContext->m_stack.Push(n); + return 1; + } + else + { + // try rest + for(n++; n < m_elxlist.GetSize(); n++) + { + if(m_elxlist[n]->Match(pContext)) + { + pContext->m_stack.Push(n); + return 1; + } + } + + return 0; + } +} + +// assertx.cpp: implementation of the CAssertElx class. +// +template CAssertElxT :: CAssertElxT(ElxInterface * pelx, int byes) +{ + m_pelx = pelx; + m_byes = byes; +} + +template int CAssertElxT :: Match(CContext * pContext) const +{ + int nbegin = pContext->m_nCurrentPos; + int nsize = pContext->m_stack.GetSize(); + int ncsize = pContext->m_capturestack.GetSize(); + int bsucc; + + // match + if( m_byes ) + bsucc = m_pelx->Match(pContext); + else + bsucc = ! m_pelx->Match(pContext); + + // status + pContext->m_stack.Restore(nsize); + pContext->m_nCurrentPos = nbegin; + + if( bsucc ) + pContext->m_stack.Push(ncsize); + else + pContext->m_capturestack.Restore(ncsize); + + return bsucc; +} + +template int CAssertElxT :: MatchNext(CContext * pContext) const +{ + int ncsize = 0; + + pContext->m_stack.Pop(ncsize); + pContext->m_capturestack.Restore(ncsize); + + return 0; +} + +// emptyelx.cpp: implementation of the CEmptyElx class. +// +template CEmptyElxT :: CEmptyElxT() +{ +} + +template int CEmptyElxT :: Match(CContext *) const +{ + return 1; +} + +template int CEmptyElxT :: MatchNext(CContext *) const +{ + return 0; +} + +// globalx.cpp: implementation of the CGlobalElx class. +// +template CGlobalElxT ::CGlobalElxT() +{ +} + +template int CGlobalElxT :: Match(CContext * pContext) const +{ + return pContext->m_nCurrentPos == pContext->m_nBeginPos; +} + +template int CGlobalElxT :: MatchNext(CContext *) const +{ + return 0; +} + +// greedelx.cpp: implementation of the CGreedyElx class. +// +template CGreedyElxT :: CGreedyElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT (pelx, nmin) +{ + m_nvart = nmax - nmin; +} + +template int CGreedyElxT :: Match(CContext * pContext) const +{ + if( ! CRepeatElxT :: MatchFixed(pContext) ) + return 0; + + while( ! MatchVart(pContext) ) + { + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + return 0; + } + + return 1; +} + +template int CGreedyElxT :: MatchNext(CContext * pContext) const +{ + if( MatchNextVart(pContext) ) + return 1; + + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + return 0; + + while( ! MatchVart(pContext) ) + { + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + return 0; + } + + return 1; +} + +template int CGreedyElxT :: MatchVart(CContext * pContext) const +{ + int n = 0; + int nbegin = pContext->m_nCurrentPos; + + while(n < m_nvart && CRepeatElxT :: m_pelx->Match(pContext)) + { + while(pContext->m_nCurrentPos == nbegin) + { + if( ! CRepeatElxT :: m_pelx->MatchNext(pContext) ) break; + } + + if(pContext->m_nCurrentPos == nbegin) break; + + n ++; + nbegin = pContext->m_nCurrentPos; + } + + pContext->m_stack.Push(n); + + return 1; +} + +template int CGreedyElxT :: MatchNextVart(CContext * pContext) const +{ + int n = 0; + pContext->m_stack.Pop(n); + + if(n == 0) return 0; + + if( ! CRepeatElxT :: m_pelx->MatchNext(pContext) ) + { + n --; + } + + pContext->m_stack.Push(n); + + return 1; +} + +// indepelx.cpp: implementation of the CIndependentElx class. +// +template CIndependentElxT :: CIndependentElxT(ElxInterface * pelx) +{ + m_pelx = pelx; +} + +template int CIndependentElxT :: Match(CContext * pContext) const +{ + int nbegin = pContext->m_nCurrentPos; + int nsize = pContext->m_stack.GetSize(); + int ncsize = pContext->m_capturestack.GetSize(); + + // match + int bsucc = m_pelx->Match(pContext); + + // status + pContext->m_stack.Restore(nsize); + + if( bsucc ) + { + pContext->m_stack.Push(nbegin); + pContext->m_stack.Push(ncsize); + } + + return bsucc; +} + +template int CIndependentElxT :: MatchNext(CContext * pContext) const +{ + int nbegin = 0, ncsize = 0; + + pContext->m_stack.Pop(ncsize); + pContext->m_stack.Pop(nbegin); + + pContext->m_capturestack.Restore(ncsize); + pContext->m_nCurrentPos = nbegin; + + return 0; +} + +// listelx.cpp: implementation of the CListElx class. +// +template CListElxT :: CListElxT(int brightleft) +{ + m_brightleft = brightleft; +} + +template int CListElxT :: Match(CContext * pContext) const +{ + if(m_elxlist.GetSize() == 0) + return 1; + + // prepare + int bol = m_brightleft ? m_elxlist.GetSize() : -1; + int stp = m_brightleft ? -1 : 1; + int eol = m_brightleft ? -1 : m_elxlist.GetSize(); + + // from first + int n = bol + stp; + + // match all + while(n != eol) + { + if(m_elxlist[n]->Match(pContext)) + { + n += stp; + } + else + { + n -= stp; + + while(n != bol && ! m_elxlist[n]->MatchNext(pContext)) + n -= stp; + + if(n != bol) + n += stp; + else + return 0; + } + } + + return 1; +} + +template int CListElxT :: MatchNext(CContext * pContext) const +{ + if(m_elxlist.GetSize() == 0) + return 0; + + // prepare + int bol = m_brightleft ? m_elxlist.GetSize() : -1; + int stp = m_brightleft ? -1 : 1; + int eol = m_brightleft ? -1 : m_elxlist.GetSize(); + + // from last + int n = eol - stp; + + while(n != bol && ! m_elxlist[n]->MatchNext(pContext)) + n -= stp; + + if(n != bol) + n += stp; + else + return 0; + + // match rest + while(n != eol) + { + if(m_elxlist[n]->Match(pContext)) + { + n += stp; + } + else + { + n -= stp; + + while(n != bol && ! m_elxlist[n]->MatchNext(pContext)) + n -= stp; + + if(n != bol) + n += stp; + else + return 0; + } + } + + return 1; +} + +// mresult.cpp: implementation of the MatchResult class. +// +template MatchResultT :: MatchResultT(CContext * pContext, int nMaxNumber) +{ + if(pContext != 0) + { + m_result.Prepare(nMaxNumber * 2 + 3, -1); + + // matched + m_result[0] = 1; + m_result[1] = nMaxNumber; + + for(int n = 0; n <= nMaxNumber; n++) + { + int index = pContext->m_captureindex[n]; + if( index < 0 ) continue; + + // check enclosed + int pos1 = pContext->m_capturestack[index + 1]; + int pos2 = pContext->m_capturestack[index + 2]; + + // info + m_result[n*2 + 2] = pos1 < pos2 ? pos1 : pos2; + m_result[n*2 + 3] = pos1 < pos2 ? pos2 : pos1; + } + } +} + +template inline int MatchResultT :: IsMatched() const +{ + return m_result.At(0, 0); +} + +template inline int MatchResultT :: MaxGroupNumber() const +{ + return m_result.At(1, 0); +} + +template inline int MatchResultT :: GetStart() const +{ + return m_result.At(2, -1); +} + +template inline int MatchResultT :: GetEnd() const +{ + return m_result.At(3, -1); +} + +template inline int MatchResultT :: GetGroupStart(int nGroupNumber) const +{ + return m_result.At(2 + nGroupNumber * 2, -1); +} + +template inline int MatchResultT :: GetGroupEnd(int nGroupNumber) const +{ + return m_result.At(2 + nGroupNumber * 2 + 1, -1); +} + +template MatchResultT & MatchResultT :: operator = (const MatchResultT & result) +{ + m_result.Restore(0); + if(result.m_result.GetSize() > 0) m_result.Append(result.m_result.GetBuffer(), result.m_result.GetSize()); + + return *this; +} + +// posselx.cpp: implementation of the CPossessiveElx class. +// +template CPossessiveElxT :: CPossessiveElxT(ElxInterface * pelx, int nmin, int nmax) : CGreedyElxT (pelx, nmin, nmax) +{ +} + +template int CPossessiveElxT :: Match(CContext * pContext) const +{ + int nbegin = pContext->m_nCurrentPos; + int nsize = pContext->m_stack.GetSize(); + int ncsize = pContext->m_capturestack.GetSize(); + int bsucc = 1; + + // match + if( ! CRepeatElxT :: MatchFixed(pContext) ) + { + bsucc = 0; + } + else + { + while( ! CGreedyElxT :: MatchVart(pContext) ) + { + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + { + bsucc = 0; + break; + } + } + } + + // status + pContext->m_stack.Restore(nsize); + + if( bsucc ) + { + pContext->m_stack.Push(nbegin); + pContext->m_stack.Push(ncsize); + } + + return bsucc; +} + +template int CPossessiveElxT :: MatchNext(CContext * pContext) const +{ + int nbegin = 0, ncsize = 0; + + pContext->m_stack.Pop(ncsize); + pContext->m_stack.Pop(nbegin); + + pContext->m_capturestack.Restore(ncsize); + pContext->m_nCurrentPos = nbegin; + + return 0; +} + +// reluctx.cpp: implementation of the CReluctantElx class. +// +template CReluctantElxT :: CReluctantElxT(ElxInterface * pelx, int nmin, int nmax) : CRepeatElxT (pelx, nmin) +{ + m_nvart = nmax - nmin; +} + +template int CReluctantElxT :: Match(CContext * pContext) const +{ + if( ! CRepeatElxT :: MatchFixed(pContext) ) + return 0; + + while( ! MatchVart(pContext) ) + { + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + return 0; + } + + return 1; +} + +template int CReluctantElxT :: MatchNext(CContext * pContext) const +{ + if( MatchNextVart(pContext) ) + return 1; + + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + return 0; + + while( ! MatchVart(pContext) ) + { + if( ! CRepeatElxT :: MatchNextFixed(pContext) ) + return 0; + } + + return 1; +} + +template int CReluctantElxT :: MatchVart(CContext * pContext) const +{ + pContext->m_stack.Push(0); + + return 1; +} + +template int CReluctantElxT :: MatchNextVart(CContext * pContext) const +{ + int n = 0, nbegin = pContext->m_nCurrentPos; + + pContext->m_stack.Pop(n); + + if(n < m_nvart && CRepeatElxT :: m_pelx->Match(pContext)) + { + while(pContext->m_nCurrentPos == nbegin) + { + if( ! CRepeatElxT :: m_pelx->MatchNext(pContext) ) break; + } + + if(pContext->m_nCurrentPos != nbegin) + { + n ++; + + pContext->m_stack.Push(nbegin); + pContext->m_stack.Push(n); + + return 1; + } + } + + while(n > 0) + { + pContext->m_stack.Pop(nbegin); + + while( CRepeatElxT :: m_pelx->MatchNext(pContext) ) + { + if(pContext->m_nCurrentPos != nbegin) + { + pContext->m_stack.Push(nbegin); + pContext->m_stack.Push(n); + + return 1; + } + } + + n --; + } + + return 0; +} + +// repeatx.cpp: implementation of the CRepeatElx class. +// +template CRepeatElxT :: CRepeatElxT(ElxInterface * pelx, int ntimes) +{ + m_pelx = pelx; + m_nfixed = ntimes; +} + +template int CRepeatElxT :: Match(CContext * pContext) const +{ + return MatchFixed(pContext); +} + +template int CRepeatElxT :: MatchNext(CContext * pContext) const +{ + return MatchNextFixed(pContext); +} + +template int CRepeatElxT :: MatchFixed(CContext * pContext) const +{ + if(m_nfixed == 0) + return 1; + + int n = 0; + + while(n < m_nfixed) + { + if(m_pelx->Match(pContext)) + { + n ++; + } + else + { + n --; + + while(n >= 0 && ! m_pelx->MatchNext(pContext)) + n --; + + if(n >= 0) + n ++; + else + return 0; + } + } + + return 1; +} + +template int CRepeatElxT :: MatchNextFixed(CContext * pContext) const +{ + if(m_nfixed == 0) + return 0; + + // from last + int n = m_nfixed - 1; + + while(n >= 0 && ! m_pelx->MatchNext(pContext)) + n --; + + if(n >= 0) + n ++; + else + return 0; + + // match rest + while(n < m_nfixed) + { + if(m_pelx->Match(pContext)) + { + n ++; + } + else + { + n --; + + while(n >= 0 && ! m_pelx->MatchNext(pContext)) + n --; + + if(n >= 0) + n ++; + else + return 0; + } + } + + return 1; +} + +// Regexp +typedef CRegexpT CRegexpA; +typedef CRegexpT CRegexpW; + +#if defined(_UNICODE) || defined(UNICODE) + typedef CRegexpW CRegexp; +#else + typedef CRegexpA CRegexp; +#endif + +#endif//__DEELX_REGEXP__H__